GithubHelp home page GithubHelp logo

stargazing-dino / just_the_tooltip Goto Github PK

View Code? Open in Web Editor NEW
56.0 56.0 51.0 5.08 MB

A directional tooltip for flutter projects

Home Page: https://pub.dev/packages/just_the_tooltip

License: MIT License

Kotlin 0.10% Ruby 1.13% Swift 0.34% Objective-C 0.03% Dart 97.15% HTML 1.25%

just_the_tooltip's People

Contributors

anton-tarasiuk avatar caseycrogers avatar pavel-sulimau avatar piotrmitkowski avatar sgehrman avatar stargazing-dino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

just_the_tooltip's Issues

LateInitializationError: Field '_controller@1501137672' has already been  initialized

Hi, I have error when I try create a new justTheController
Any ideas?

StackTrace: #0      LateError._
throwFieldAlreadyInitialized (dart:_internal-patch\/internal_patch.dart:211)\n#1      _JustTheToolt
ipState._controller= (package:just_the_tooltip\/src\/just_the_tooltip.dart:150)\n#2      _JustTheTo
oltipState.didUpdateWidget (package:just_the_tooltip\/src\/just_the_tooltip.dart:222)\n#3      Stat
efulElement.update (package:flutter\/src\/widgets\/framework.dart:4855)\n#4      Element.updateChil
d (package:flutter\/src\/widgets\/framework.dart:3412)\n#5      ComponentElement.performRebuild (pa
ckage:flutter\/src\/widgets\/framework.dart:4690)\n#6      Element.rebuild (package:flutter\/src\/w
idgets\/framework.dart:4355)\n#7      StatelessElement.update (package:flutter\/src\/widgets\/frame
work.dart:4746)\n#8      Element.updateChild (package:flutter\/src\/widgets\/framework.dart:3412)\n
#9      ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690)\n#10
   StatefulElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4840)\n#11     Ele
ment.rebuild (package:flutter\/src\/widgets\/framework.dart:4355)\n#12     StatefulElement.update (
package:flutter\/src\/widgets\/framework.dart:4872)\n#13     Element.updateChild (package:flutter\/
src\/widgets\/framework.dart:3412)\n#14     Element.inflateWidget (package:flutter\/src\/widgets\/f
ramework.dart:3663)\n#15     Element.updateChild (package:flutter\/src\/widgets\/framework.dart:342
5)\n#16     ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690)\n#
17     StatefulElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4840)\n#18
 Element.rebuild (package:flutter\/src\/widgets\/framework.dart:4355)\n#19     ComponentElement._fi
rstBuild (package:flutter\/src\/widgets\/framework.dart:4643)\n#20     StatefulElement._firstBuild
(package:flutter\/src\/widgets\/framework.dart:4831)\n#21     ComponentElement.mount (package:flutt
er\/src\/widgets\/framework.dart:4638)\n#22     Element.inflateWidget (package:flutter\/src\/widget
s\/framework.dart:3673)\n#23     Element.updateChild (package:flutter\/src\/widgets\/framework.dart
:3425)\n#24     ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690
...
#201    BuildOwner.buildScope (package:flutter\/src\/widgets\/framework.dart:2620)\n#202    Widgets
Binding.drawFrame (package:flutter\/src\/widgets\/binding.dart:882)\n#203    RendererBinding._handl
ePersistentFrameCallback (package:flutter\/src\/rendering\/binding.dart:319)\n#204    SchedulerBind
ing._invokeFrameCallback (package:flutter\/src\/scheduler\/binding.dart:1143)\n#205    SchedulerBin
ding.handleDrawFrame (package:flutter\/src\/scheduler\/binding.dart:1080)\n#206    SchedulerBinding
._handleDrawFrame (package:flutter\/src\/scheduler\/binding.dart:996)\n#207    _rootRun (dart:async
\/zone.dart:1428)\n#208    _CustomZone.run (dart:async\/zone.dart:1328)\n#209    _CustomZone.runGua
rded (dart:async\/zone.dart:1236)\n#210    _invoke (dart:ui\/hooks.dart:166)\n#211    PlatformDispa
tcher._drawFrame (dart:ui\/platform_dispatcher.dart:270)\n#212    _drawFrame (dart:ui\/hooks.dart:1
29)\n \n\n Error message: LateInitializationError: Field '_controller@1501137672' has already been 
initialized

After a hot reload, RenderObject does not relayout

This means if we change the axis, no new constraints are processed.

This likely will be fixed with making each property a setter and getter and making the correct thing dirty. Either paint or layout.

Show the tooltip programatically

Forcing the child onTap to show the tooltip is not cool. It might be the default behavior but we should be able to decide when we want to show the tooltip in the app. Think of onboarding scenarios.

Look at simple_tooltip

Dear diary, just saw this other package and its whack how much we have alike. Unlike their package, I use a custom render object instead of drawing a frame late. They somehow manage update the tooltip in realtime as the target moves though which is cool. I think I'll see if I can't get some pointers from them.

Prevent the tooltip from closing on clicking on it

Is this how it was intended, that the tooltip closes when you click on it?

Can this be disabled somehow?

I think such property values (that I have set) should prevent this.

triggerMode: TooltipTriggerMode.manual,
barrierDismissible: false,

But it doesn't work that way.

Customizability of tooltip

We should allow for more customizations. A good starting point would be to try to implement some of these:

  • Frosted look
  • Outline of tooltip
  • Better Shadow properties (List?)

Edit

I might want to consider whether the tooltip should be the space around the tail as well and if the tail should just be gotten from a clipper. That would make things like frosted glass a lot easier to implement. I think it'd complicate gestures though. Just a guess.

Get rid of JustTheInterface

I think I previously was using it to avoid passing through super parameters but with new super language feature in dart it's relatively easy. It would also just be nice because this is very non-standard the way I do it.

Error when using inside a ListView

I noticed a problem in the use of this library when used with the area mode and the tooltip inside a ListView or a GridView on Flutter 2.10.1.

When the widget that contains the tooltip is activated and move to outside of ListView, its cause this error

FlutterError (setState() or markNeedsBuild() called during build.
This ValueListenableBuilder<Widget?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

Possible to reproduce on example:
https://github.com/Nolence/just_the_tooltip/blob/main/example/lib/pages/tooltip_area_page.dart

How to add Hover

When I hover the button this tooltip need to show how to do this

Differentiate between `immediately` and `withoutAnimation`

I just got really confused by thinking immediately referred to an action the tooltip took without animation. That is not the case. immediately in the original Tooltips case implies that they're not waiting for hover hide/show duration.

That's cool and all, but for a controller, we'll want to be able to specify immediately in terms of, skip the whole animation thing. We also don't need to worry about that stuff in terms of modals as they're driven by taps

Add Notifications for tooltip events

I imagine this would be useful to see when a tooltip is on the screen and where. Top level UI might find something to do with this information.

I saw a neat answer from Remi on Notifications. This is a separate from a controller.

https://stackoverflow.com/a/51460832/8213910

We would add notifaction listener and possibly provide:

  • target postion and sizing
  • tooltip direction and sizing
  • visible, hidden
  • more possibly

Use RenderProxyBox for child position and size

Although I do think what I'm currently doing is a little bit hacky, considering I have 10+ fields on the widget state, I'd need to create those same fields on the CustomRenderObject and update them all accordingly. This is super verbose.

My current workaround is just to get the RenderBox of child's self at runtime when it's requested to show a tooltip.

TargetInformation _getTargetInformation(BuildContext context) {
  final box = context.findRenderObject() as RenderBox?;

  if (box == null) {
    throw StateError(
      'Cannot find the box for the given object with context $context',
    );
  }

  final targetSize = box.getDryLayout(const BoxConstraints.tightForFinite());
  final target = box.localToGlobal(box.size.center(Offset.zero));
  final offsetToTarget = Offset(
    -target.dx + box.size.width / 2,
    -target.dy + box.size.height / 2,
  );

  return TargetInformation(
    targetSize,
    target,
    offsetToTarget,
  );
}

Tooltip does not work with TextField

════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during performLayout():
The _RenderDecoration class does not support dry layout.

Layout requires baseline metrics, which are only available after a full layout.
The relevant error-causing widget was
TooltipOverlay
../…/src/just_the_tooltip.dart:227
When the exception was thrown, this was the stack
#0      RenderBox.debugCannotComputeDryLayout.<anonymous closure>
package:flutter/…/rendering/box.dart:1901
#1      RenderBox.debugCannotComputeDryLayout
package:flutter/…/rendering/box.dart:1911
#2      _RenderDecoration.computeDryLayout
package:flutter/…/material/input_decorator.dart:1300
#3      RenderBox._computeDryLayout
package:flutter/…/rendering/box.dart:1824
#4      RenderBox.getDryLayout.<anonymous closure>
package:flutter/…/rendering/box.dart:1813
#5      _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:311:23)
#6      RenderBox.getDryLayout
package:flutter/…/rendering/box.dart:1813
#7      RenderProxyBoxMixin.computeDryLayout
package:flutter/…/rendering/proxy_box.dart:108
#8      RenderBox._computeDryLayout
package:flutter/…/rendering/box.dart:1824
#9      RenderBox.getDryLayout.<anonymous closure>
package:flutter/…/rendering/box.dart:1813

This is probably because I'm calling getDryLayout on the child and it doesn't have that available for textfields. I think there's a debug version available that knows though isn't there?

Ability to place tail tip along cross axis

For vertical text boxes like japanese, it'd be cool if you could center the tip along the center vertical axis.

Simulator Screen Shot - iPod touch (7th generation) - 2021-06-17 at 11 25 19

This would involve doing some black magic on cross axis code of vertical|horizontal PositionDependentBox function. Namely, we'd likely pass through an alignment and do it based off that. The code below favors the left margin I think

// HORIZONTAL DIRECTION
  double x;
  if (size.width - margin.horizontal < childSize.width) {
    x = (size.width - childSize.width) / 2.0;
  } else {
    final normalizedTargetX =
        target.dx.clamp(margin.left, size.width - margin.right);
    final edge = margin.left + childSize.width / 2.0;
    if (normalizedTargetX < edge) {
      x = margin.left;
    } else if (normalizedTargetX > size.width - edge) {
      x = size.width - margin.left - childSize.width;
    } else {
      x = normalizedTargetX - childSize.width / 2.0;
    }
  }

Barrier should not be visually on top of child widget

A custom user built barrier shouldn't visually obscure the child widget. This doesn't really match with what a user would expect and naturally bars a lot of users from using the tooltip as a sort of coach or app guide such as the following:

A couple of possibilities to get what we want would be to:

  1. shadermasks (credit caseycrogers)
  2. a duplicate overlay entry of the child
  3. a clip mask or user defined clip mask

or something else

coachmaker does something similar so it might help to get inspiration from them.

onShow, onHide callbacks

I am using a widget by tapping it i am showing a tooltip. but i also want to change the size, colour of the tooltip but unable to do because i am not getting any callback of show and close in which i can change the widget.It would be great if those call backs are added soon. Thank you.

Add goldens to pubignore

Those images are quite large and to force every user to install them with a standard install is wack

Null safety issue

I'm getting this error while building my app:


ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:329:27: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:           RendererBinding.instance!.mouseTracker.mouseIsConnected;
ERROR:                           ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:393:21: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:     RendererBinding.instance!.mouseTracker
ERROR:                     ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:397:20: Warning: Operand of null-aware operation '!' has type 'GestureBinding' which excludes null.
ERROR:  - 'GestureBinding' is from 'package:flutter/src/gestures/binding.dart' ('/opt/flutter/packages/flutter/lib/src/gestures/binding.dart').
ERROR:     GestureBinding.instance!.pointerRouter.addGlobalRoute(_handlePointerEvent);
ERROR:                    ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:402:21: Warning: Operand of null-aware operation '?.' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:     RendererBinding.instance?.mouseTracker
ERROR:                     ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:404:20: Warning: Operand of null-aware operation '?.' has type 'GestureBinding' which excludes null.
ERROR:  - 'GestureBinding' is from 'package:flutter/src/gestures/binding.dart' ('/opt/flutter/packages/flutter/lib/src/gestures/binding.dart').
ERROR:     GestureBinding.instance?.pointerRouter
ERROR:                    ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:414:25: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:         RendererBinding.instance!.mouseTracker.mouseIsConnected;
ERROR:                         ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:498:22: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
ERROR:  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('/opt/flutter/packages/flutter/lib/src/widgets/binding.dart').
ERROR:       WidgetsBinding.instance?.addPostFrameCallback((_) async {
ERROR:                      ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip_entry.dart:210:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
ERROR:  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('/opt/flutter/packages/flutter/lib/src/widgets/binding.dart').
ERROR:     WidgetsBinding.instance?.addPostFrameCallback((_) {
ERROR:                    ^

isModal:true makes the tooltip persistant (on previous page) when a GestureDetector of higher level pushes the navigator to a new route...

...Not allowing the tooltip to show for any new item on the new route (as the previous one wasn't closed 'properly'. It also doesn't allow it to close on the new page as it technically doesn't exist on that page? Lets look at this example:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Error App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Error'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center: (child: GestureDetector(
        onDoubleTap: () {
          Navigator.push<void>(
            context,
            MaterialPageRoute(builder: (context) {
              FocusScope.of(context).unfocus();
              return SecondPage();
            }),
          );
        },
        child: ToolTipBug(
          description: 'Hello',
        ),
      ),
     ),
   );
  }
}

class ToolTipBug extends StatelessWidget {
  final String description;

  const ToolTipBug({
    Key? key,
    required this.description,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return JustTheTooltip(
      isModal: true,
      triggerMode: TooltipTriggerMode.tap,
      content: Text(description),
      child: SizedBox(
        height: 100,
        child: Center(child: Text('Test')),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {


    return  Scaffold(
      appBar: AppBar(
        title: Text('Page 2'),
      ),
      body: Center: (
        child: ToolTipBug(
          description: 'hello 2',
        ),
      ),
   );
  }
}


Lets consider this simple example. When you open the tooltip and then double click on the MyHomePage Class, and you go to the SecondPage, you expect the modal of the previous page to be closed and that you will be able to open the second ToolTipBug Widget on SecondPage by cliking on it but this doesn't happen. The previous modal in the MyHomePage Class persists (but is not there) and nothing opens in the new page. This behaviour only happens when isModal is set to true.

Error: Type 'TooltipTriggerMode' not found. final TooltipTriggerMode? triggerMode

app is working in debug mode, but its throwing several errors when i try to build the APK. Bellow i will mention the errors which i got.

`../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:80:9: Error: Type 'TooltipTriggerMode' not found.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:288:16: Error: Type 'TooltipTriggerMode' not found.
static const TooltipTriggerMode _defaultTriggerMode =
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:300:8: Error: Type 'TooltipTriggerMode' not found.
late TooltipTriggerMode triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip_entry.dart:60:9: Error: Type 'TooltipTriggerMode' not found.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/models/just_the_interface.dart:125:3: Error: Type 'TooltipTriggerMode' not found.
TooltipTriggerMode? get triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:289:7: Error: Getter not found: 'TooltipTriggerMode'.
TooltipTriggerMode.longPress;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:80:9: Error: 'TooltipTriggerMode' isn't a type.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:288:16: Error: 'TooltipTriggerMode' isn't a type.
static const TooltipTriggerMode _defaultTriggerMode =
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:300:8: Error: 'TooltipTriggerMode' isn't a type.
late TooltipTriggerMode triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:559:26: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.

  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    if (triggerMode == TooltipTriggerMode.longPress) {
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:581:44: Error: The getter 'triggerMode' isn't defined for the class 'TooltipThemeData'.
  • 'TooltipThemeData' is from 'package:flutter/src/material/tooltip_theme.dart' ('../../src/flutter_2.2.3/packages/flutter/lib/src/material/tooltip_theme.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'triggerMode'.
    widget.triggerMode ?? tooltipTheme.triggerMode ?? _defaultTriggerMode;
    ^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:583:22: Error: The getter 'enableFeedback' isn't defined for the class 'TooltipThemeData'.
  • 'TooltipThemeData' is from 'package:flutter/src/material/tooltip_theme.dart' ('../../src/flutter_2.2.3/packages/flutter/lib/src/material/tooltip_theme.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'enableFeedback'.
    tooltipTheme.enableFeedback ??
    ^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:590:29: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.
  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    : (triggerMode == TooltipTriggerMode.longPress)
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:595:29: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.
  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    : (triggerMode == TooltipTriggerMode.tap)
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip_entry.dart:60:9: Error: 'TooltipTriggerMode' isn't a type.
    final TooltipTriggerMode? triggerMode;
    ^^^^^^^^^^^^^^^^^^

FAILURE: Build failed with an exception.

  • Where:
    Script '/home/mindstack/src/flutter_2.2.3/packages/flutter_tools/gradle/flutter.gradle' line: 1035

  • What went wrong:
    Execution failed for task ':app:compileFlutterBuildRelease'.

Process 'command '/home/mindstack/src/flutter_2.2.3/bin/flutter'' finished with non-zero exit value 1

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

  • Get more help at https://help.gradle.org
    `

Some problems with all the durations

I don't know exactly what's going on, but setting these durations is near impossible to get right.

Most of the time the tooltip doesn't show up. It must be hiding the tooltip in timers that get fired at the wrong time.

Very confusing to set this up.

tooltip in ListView item crash

I haven't investigated this yet. But I added a tooltip on some listview items and I'm getting this:

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: RenderFlex children have non-zero flex but incoming width constraints are unbounded.
When a row is in a parent that does not provide a finite width constraint, for example if it is in a horizontal scrollable, it will try to shrink-wrap its children along the horizontal axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the horizontal direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
If this message did not help you determine the problem, consider using debugDumpRenderTree():
https://flutter.dev/debugging/#rendering-layer
http://api.flutter.dev/flutter/rendering/debugDumpRenderTree.html
The affected RenderFlex is:
RenderFlex#88256 relayoutBoundary=up18(creator: Row ← Padding ← DefaultTextStyle ← Builder ← Semantics ← DefaultTextStyle ← AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#2bfc5 ink renderer] ← NotificationListener ← CustomPaint ← _ShapeBorderPaint ← PhysicalShape ← ⋯, parentData: offset=Offset(10.0, 10.0) (can use size), constraints: BoxConstraints(w=849.8, 0.0<=h<=Infinity), size: Size(849.8, 60.0), direction: horizontal, mainAxisAlignment: start, mainAxisSize: max, crossAxisAlignment: center, textDirection: ltr, verticalDirection: down)
The creator information is set to:
Row ← Padding ← DefaultTextStyle ← Builder ← Semantics ← DefaultTextStyle ← AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#2bfc5 ink renderer] ← NotificationListener ← CustomPaint ← _ShapeBorderPaint ← PhysicalShape ← ⋯
See also: https://flutter.dev/layout/
If none of the above helps enough to fix this problem, please don't hesitate to file a bug:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
#0 RenderBox.debugCannotComputeDryLayout.
#1 RenderBox.debugCannotComputeDryLayout
#2 RenderFlex.computeDryLayout
#3 RenderBox._computeDryLayout
#4 RenderBox.getDryLayout.
#5 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#6 RenderBox.getDryLayout
#7 RenderPadding.computeDryLayout
#8 RenderBox._computeDryLayout
#9 RenderBox.getDryLayout.
#10 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#11 RenderBox.getDryLayout
#12 RenderProxyBoxMixin.computeDryLayout
#13 RenderBox._computeDryLayout
#14 RenderBox.getDryLayout.
#15 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#16 RenderBox.getDryLayout
#17 RenderProxyBoxMixin.computeDryLayout
#18 RenderBox._computeDryLayout
#19 RenderBox.getDryLayout.
#20 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#21 RenderBox.getDryLayout
#22 RenderProxyBoxMixin.computeDryLayout
#23 RenderBox._computeDryLayout
#24 RenderBox.getDryLayout.
#25 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#26 RenderBox.getDryLayout
#27 RenderProxyBoxMixin.computeDryLayout
#28 RenderBox._computeDryLayout
#29 RenderBox.getDryLayout.
#30 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#31 RenderBox.getDryLayout
#32 RenderPadding.computeDryLayout
#33 RenderBox._computeDryLayout
#34 RenderBox.getDryLayout.
#35 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#36 RenderBox.getDryLayout
#37 RenderProxyBoxMixin.computeDryLayout
#38 RenderBox._computeDryLayout
#39 RenderBox.getDryLayout.
#40 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#41 RenderBox.getDryLayout
#42 RenderProxyBoxMixin.computeDryLayout
#43 RenderBox._computeDryLayout
#44 RenderBox.getDryLayout.
#45 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#46 RenderBox.getDryLayout
#47 RenderProxyBoxMixin.computeDryLayout
#48 RenderBox._computeDryLayout
#49 RenderBox.getDryLayout.
#50 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#51 RenderBox.getDryLayout
#52 _JustTheTooltipState._getTargetInformation
#53 _JustTheTooltipState._createEntry
#54 _JustTheTooltipState._createNewEntries
#55 _JustTheTooltipState.ensureTooltipVisible
#56 _JustTheTooltipState._showTooltip.
#57 _JustTheTooltipState._showTooltip.
#58 _rootRun (dart:async/zone.dart:1420:47)
#59 _CustomZone.run (dart:async/zone.dart:1328:19)
#60 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#61 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1276:23)
#62 _rootRun (dart:async/zone.dart:1428:13)
#63 _CustomZone.run (dart:async/zone.dart:1328:19)
#64 _CustomZone.bindCallback. (dart:async/zone.dart:1260:23)
#65 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
#66 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#67 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#68 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:187:12)

JustTheController doesn't reflect the correct tooltip status

It's easy to reproduce, just add a listener to the JustTheController instance. And check 'isShowing' within the closure, like what I did in the PR.

As I mentioned in the PR, JustTheController as a ValueNotifier, ideally, it should reflect the current status of tooltip, like open or close. I noticed you have implemented these functions: 'isShowing' and 'isHidden', however, it's broken, the value never changes.

I also tried to fix it directly, but the value will be changed multiple times during each user action, that means, if I listen to JustTheController, the listener will be invoked multiple times for each user action. Potentially, this listener behavior would cause some unnecessary issues. That's why I end up with creating a new status notifier. Maybe you have better implementation. Please let me know if you have any questions.

Scroll constraints should not allot full scroll extent if size does not require it

I currently allow stuff that pass me a scroll controller to go past the immediate viewport into extentBefore and extentAfter. HOWEVER. If it's something that chooses to expand as large as possible such as a Center then we should try constraining the child size first to the viewport and then, if it fails, fallback to giving it all the possible size.

Back button not called when tooltip visible

I think this occurs when you use the default AppBar(). This creates a back button that has a maybePop() call when a back it triggered. The maybePop likely sees the overlays and sends a false back.

One workaround I've found is to replace the skrim's default gestureDetector

Widget _createSkrim() {
  return GestureDetector(
    key: skrimKey,
    behavior: HitTestBehavior.translucent,
    onTap: _hideTooltip,
  );
}

with a

Widget _createSkrim() {
  return Listener(
    key: skrimKey,
    behavior: HitTestBehavior.translucent,
    onPointerDown: (_) => _hideTooltip(),
  );
}

But this creates the weird case where when you're dragging, the tooltip is immediately closed because an onPointerDown event was sent.

Listener
https://user-images.githubusercontent.com/29642168/135305144-46ed33e3-49ee-4659-98ac-2f2a879283e0.mp4

GestureDetector
https://user-images.githubusercontent.com/29642168/135305163-17499af7-85cc-4c98-8dac-2e8193eb50bf.mp4

Breaks with RotatedBox

I don't know how to get a box that has a preferredSize that is larger in the vertical direction than the horizontal. This was to test that it worked in correctly constraining stuff.

However, I tried a RotatedBox and it looks like it doesn't swap the size? Not sure how but I got a width of like 68 for something that was obviously like 300. I don't know how you'd check if something was rotated either

This functionality probably belongs in dependentBox stuff but if it's not even being passed the actual information of the box it's positioning then I'm at a loss

provide Alignment argument

Let's add an Alignment argument that the tooltip center will use to position itself. For example, we could provide a value of Alignment.topRight and the tail tip will point itself on the child's box at the topRight corner. We'd likely need to flip the Alignment (multiply by -1) if we end up positioning ourselves in the opposite of preferredAxis.

Center and Circular progress indicator

This ends up taking the whole height instead of the minimum !

Agh, it probably has to do with intrinsics again....

The expected behaviour is that it takes the minimum amount of height for just the circularprogressindicator

Simulator Screen Shot - iPod touch (7th generation) - 2021-07-01 at 14 21 38

Unhandled Exception: RenderFlex children have non-zero flex

I reported this previously, but have the problem again.

try a test like:

Listview
children: [
tooltip(
child: Row(children: [Text, Expanded(Text), Button])
)
]
)

The tooltip code doesn't like that expanded row.

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: RenderFlex children have non-zero flex but incoming width constraints are unbounded.
When a row is in a parent that does not provide a finite width constraint, for example if it is in a horizontal scrollable, it will try to shrink-wrap its children along the horizontal axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the horizontal direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.

Making a button to show a tooltip when it's a non-modal closes the modal immediately

This is semi expected behavior as the tooltip adds a global listener for taps and will close the tooltip if there's any taps. However, I don't think it should happen the second the tooltip is created.

The tap handler should should ignore all taps until hasEntry is true

Edit

It does wait until it has an entry. It still doesn't handle it correctly

void _handlePointerEvent(PointerEvent event) {
    if (!delegate.hasEntry) return;

    if (event is PointerUpEvent || event is PointerCancelEvent) {
      _hideTooltip();
    } else if (event is PointerDownEvent) {
      _hideTooltip(immediately: true);
    }
  }

Vertical space filling tooltip overflowed

I don't think this should overflow as I've passed in a scroll Controller and there is technically space both before and after. If anything, this looks weird in where it decides to stop drawing. Are those the constaints?

Simulator Screen Shot - iPod touch (7th generation) - 2021-06-28 at 09 36 32

class TooltipAreaExamplePage extends StatefulWidget {
  const TooltipAreaExamplePage({Key? key}) : super(key: key);

  @override
  State<TooltipAreaExamplePage> createState() => _TooltipAreaExamplePageState();
}

class _TooltipAreaExamplePageState extends State<TooltipAreaExamplePage> {
  final titleController = TextEditingController(
    text: 'Lorem ipsum dolor',
  );
  final descriptionController = TextEditingController(
    text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do '
        'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim '
        'ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ',
  );
  final scrollController = ScrollController();

  @override
  void dispose() {
    titleController.dispose();
    descriptionController.dispose();
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('It goes under me')),
      body: JustTheTooltipArea(
        builder: (context, tooltip, scrim) {
          return Stack(
            fit: StackFit.passthrough,
            children: [
              ListView(
                controller: scrollController,
                children: List.generate(
                  40,
                  (index) {
                    if (index == 15) {
                      return JustTheTooltipEntry(
                        scrollController: scrollController,
                        isModal: true,
                        tailLength: 20.0,
                        preferredDirection: AxisDirection.right,
                        margin: const EdgeInsets.all(16.0),
                        child: const Material(
                          color: Colors.blue,
                          shape: CircleBorder(),
                          elevation: 4.0,
                          child: Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Icon(
                              Icons.touch_app,
                              color: Colors.white,
                            ),
                          ),
                        ),
                        content: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            TextField(
                              maxLines: null,
                              keyboardType: TextInputType.text,
                              textCapitalization: TextCapitalization.sentences,
                              style: Theme.of(context).textTheme.headline6,
                              controller: titleController,
                            ),
                            const SizedBox(height: 12.0),
                            TextField(
                              controller: descriptionController,
                              maxLines: null,
                              keyboardType: TextInputType.multiline,
                              textCapitalization: TextCapitalization.sentences,
                              style: Theme.of(context).textTheme.subtitle1,
                            ),
                            const SizedBox(height: 16.0),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceAround,
                              children: [
                                Expanded(
                                  child: OutlinedButton(
                                    style: OutlinedButton.styleFrom(
                                      shape: const StadiumBorder(),
                                    ),
                                    onPressed: () {},
                                    child: const Text('exercises'),
                                  ),
                                ),
                                const SizedBox(width: 16.0),
                                Expanded(
                                  child: OutlinedButton(
                                    style: OutlinedButton.styleFrom(
                                      shape: const StadiumBorder(),
                                    ),
                                    onPressed: () {},
                                    child: const Text('course'),
                                  ),
                                ),
                              ],
                            )
                          ],
                        ),
                      );
                    }

                    return ListTile(title: Text('Item $index'));
                  },
                ),
              ),
              if (scrim != null) scrim,
              if (tooltip != null) tooltip,
            ],
          );
        },
      ),
    );
  }
}

Make tests less bad

I'm currently doing the most naive golden tests. I couldn't find out a way to use to use a screenbuilder with various screens without breaking the tooltip. It wouldn't break but because internally the golden test lib is just resizing things instead of relaying them out as well, the tooltip was being pushed to the edge.

I'd like scenerios like the following example from flutter_glove_box:

final builder = DeviceBuilder()
      ..overrideDevicesForAllScenarios(devices: [
        Device.phone,
        Device.iphone11,
        Device.tabletPortrait,
        Device.tabletLandscape,
      ])
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'default page',
      )
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'tap once',
        onCreate: (scenarioWidgetKey) async {
          final finder = find.descendant(
            of: find.byKey(scenarioWidgetKey),
            matching: find.byIcon(Icons.add),
          );
          expect(finder, findsOneWidget);
          await tester.tap(finder);
        },
      )
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'tap five times',
        onCreate: (scenarioWidgetKey) async {
          final finder = find.descendant(
            of: find.byKey(scenarioWidgetKey),
            matching: find.byIcon(Icons.add),
          );
          expect(finder, findsOneWidget);

          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
        },
      );

but where I can choose to do something in between different devices. Like a hook before the screenshot is taken.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.