├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── dart.yml │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .metadata ├── AUTHORS ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── app │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── flutter │ │ └── plugins │ │ └── GeneratedPluginRegistrant.java └── local.properties ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── super_tooltip_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ └── main.dart ├── pubspec.yaml └── super_tooltip_example.iml ├── lib ├── src │ ├── bubble_shape.dart │ ├── enums.dart │ ├── shape_overlay.dart │ ├── super_tooltip.dart │ ├── super_tooltip_controller.dart │ ├── tooltip_position_delegate.dart │ └── utils.dart └── super_tooltip.dart ├── makedoc.bat ├── pubspec.yaml └── screenshots ├── screenshot1.gif ├── screenshot2.png └── screenshot3.gif /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [bensonarafat] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: bensonarafat # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | name: Static code analysis 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | lint: 11 | runs-on: macos-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3.5.2 15 | - uses: actions/setup-java@v3.11.0 16 | with: 17 | java-version: 11 18 | distribution: temurin 19 | - uses: subosito/flutter-action@v2.10.0 20 | with: 21 | flutter-version: '3.24.3' 22 | cache: true 23 | 24 | - name: Install dependencies for super_tooltip 25 | run: flutter pub get 26 | 27 | # Statically analyze the Dart code for any errors. 28 | - run: flutter analyze . 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | jobs: 7 | contrib-readme-job: 8 | runs-on: ubuntu-latest 9 | name: A job to automate contrib in readme 10 | steps: 11 | - name: Contribute List 12 | uses: akhilmhdh/contributors-readme-action@v2.3.6 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/publish.yml 2 | name: Publish to pub.dev 3 | 4 | on: 5 | push: 6 | tags: 7 | - 'v[0-9]+.[0-9]+.[0-9]+*' # tag pattern on pub.dev: 'v' 8 | 9 | # Publish using custom workflow 10 | jobs: 11 | publish: 12 | permissions: 13 | id-token: write # Required for authentication using OIDC 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: dart-lang/setup-dart@v1 18 | - name: Install dependencies 19 | run: flutter pub get 20 | # Here you can insert custom steps you need 21 | # - run: dart tool/generate-code.dart 22 | - name: Publish 23 | run: dart pub publish --force -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .atom/ 3 | .vscode/ 4 | .dart_tool/ 5 | .idea 6 | .packages 7 | .pub/ 8 | packages 9 | ios/Runner/GeneratedPluginRegistrant.h 10 | ios/Runner/GeneratedPluginRegistrant.m 11 | pubspec.lock 12 | .vscode 13 | example/flutter_weather_demo/pubspec.lock 14 | /*.code-workspace 15 | example/android.iml 16 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: adc9dde3ba8563eebb824feb689f95eb947ab745 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the Flutter project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Benson Arafat 7 | 8 | Thomas Burkhart -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [2.0.9] - 27.10.2024 2 | - Fix hide tooltip doesn't work when tap arrow 3 | - Arrow tip radius 4 | - Update code base documentation 5 | 6 | # [2.0.8] - 13.07.2024 7 | - Added toggleOnTap option to toggle tooltip 8 | - Remove un-use method 9 | - Fix showClosButton and hideToolTip on Barrier Tap 10 | - expose showowOffset 11 | 12 | # [2.0.7] - 28.09.2023 13 | * Fix custom decoration 14 | # [2.0.6] - 28.09.2023 15 | * Fix custom decoration and hide tooltip on tab 16 | 17 | # [2.0.5] - 10.08.2023 18 | * Feature - add blur (imageFilter) 19 | # [2.0.4] - 28.06.2023 20 | 21 | # [2.0.3] - 23.06.2023 22 | # [2.0.2] - 25.05.2023 23 | 24 | * Update LICENSE 25 | * 26 | # [2.0.1] - 25.05.2023 27 | 28 | * Update Screenshot path on doc 29 | 30 | # [2.0.0] - 25.05.2023 31 | 32 | * Release of version 2 33 | 34 | ## [1.0.1] - 15.3.2021 35 | 36 | * Allow to change the icon of the close button 37 | 38 | ## [1.0.0] - 13.3.2021 39 | 40 | * Null safe version, this will be probably the last version of SuperTooltip with this API. We are working on a new better one. 41 | 42 | ## [0.9.6] - 14.10.2020 43 | 44 | * Adds properties to disable dismiss on tap outside and to exclude the barrier at all. 45 | * Thanks to PR [https://github.com/escamoteur/super_tooltip/pull/11] by @castrors 46 | 47 | ## [0.9.5] - 23.7.2020 48 | 49 | * Adds properties to customize the shadow. 50 | * Updated Example to latest Flutter version 51 | 52 | ## [0.9.0] - 8.7.2018 53 | 54 | * Initial release. 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thomas Burkhart. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # super_tooltip 2 | 3 | [![Static code analysis](https://github.com/bensonarafat/super_tooltip/actions/workflows/dart.yml/badge.svg)](https://github.com/bensonarafat/super_tooltip/actions/workflows/dart.yml) 4 | [![pub package](https://img.shields.io/pub/v/super_tooltip.svg)](https://pub.dartlang.org/packages/super_tooltip) 5 | 6 | `SuperTooltip` It is super flexible and allows you to display ToolTips in the overlay of the screen. It gives you more flexibility over the Flutter standard `Tooltip`. You have the option to make the whole screen covered with a background color. Tapping on the background closes the Tooltip. 7 | 8 | 9 | 10 | ## Installing 11 | 12 | Run this command: 13 | 14 | With Flutter: 15 | 16 | ``` 17 | flutter pub add super_tooltip 18 | ``` 19 | 20 | This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get): 21 | 22 | ``` 23 | dependencies: 24 | super_tooltip: latest 25 | ``` 26 | 27 | Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more. 28 | 29 | Now in your Dart code, you can use: 30 | 31 | ``` 32 | import 'package:super_tooltip/super_tooltip.dart'; 33 | ``` 34 | 35 | # Getting Started 36 | 37 | You have to make your Widget a `StatefulWidget` and you just need to create a controller to manage state of tooltips, you can do so by defining an instance of a `SuperTooltipController` and pass it through to constructor. 38 | 39 | ```dart 40 | final _controller = SuperTooltipController(); 41 | 42 | child: SuperTooltip( 43 | _controller: tooltipController, 44 | // ... 45 | ) 46 | 47 | void makeTooltip() { 48 | _controller.showTooltip(); 49 | } 50 | ``` 51 | 52 | You need to wrap `SuperTooltip` with a `GestureDetector`, `MouseRegion` or `InkWell` that is responsible for showing and hiding the content. Further handling of the tooltip state can be managed explicitly through a controller 53 | 54 | ```dart 55 | child: GestureDetector( 56 | onTap: () async { 57 | await _controller.showTooltip(); 58 | }, 59 | child: SuperTooltip( 60 | showBarrier: true, 61 | controller: _controller, 62 | content: const Text( 63 | "Lorem ipsum dolor sit amet, consetetur sadipscing elitr,", 64 | softWrap: true, 65 | style: TextStyle( 66 | color: Colors.white, 67 | ), 68 | ), 69 | child: Container( 70 | width: 40.0, 71 | height: 40.0, 72 | decoration: const BoxDecoration( 73 | shape: BoxShape.circle, 74 | color: Colors.blue, 75 | ), 76 | child: Icon( 77 | Icons.add, 78 | color: Colors.white, 79 | ), 80 | ), 81 | ), 82 | ), 83 | ``` 84 | 85 | `SuperTooltip` just need one required argument which is the content. You can pass a child Widget which can be an icon to represent the what should be clicked. As showed in the example below. 86 | 87 | ```dart 88 | SuperTooltip( 89 | content: const Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr", 90 | softWrap: true, 91 | style: TextStyle( 92 | color: Colors.white, 93 | ), 94 | ), 95 | child: Container( 96 | width: 40.0, 97 | height: 40.0, 98 | decoration: const BoxDecoration( 99 | shape: BoxShape.circle, 100 | color: Colors.blue, 101 | ), 102 | child: Icon( 103 | Icons.add, 104 | color: Colors.white, 105 | ), 106 | ), 107 | ), 108 | ``` 109 | 110 | Change the background by passing the `backgroundColor`. 111 | 112 | ```dart 113 | SuperTooltip( 114 | backgroundColor: Color(0xff2f2d2f), 115 | //.... 116 | ), 117 | ``` 118 | 119 | Change Popup direction to `TooltipDirection.right`, `TooltipDirection.left`, `TooltipDirection.bottom` and `TooltipDirection.up` 120 | 121 | ```dart 122 | SuperTooltip( 123 | popupDirection: TooltipDirection.right, 124 | //... 125 | ) 126 | ``` 127 | 128 | 129 | ## DecorationBuilder 130 | 131 | To customize the shape of the popup or apply your own decoration, you can utilize the `decorationBuilder` property. This allows you to access the `target` property and define a custom shape or decoration for the tooltip. 132 | 133 | ```dart 134 | SuperTooltip( 135 | decorationBuilder:(target){ 136 | return ShapeDecoration( 137 | //... 138 | shape: CustomShape( 139 | //... 140 | target: target, 141 | ), 142 | ); 143 | } 144 | //... 145 | ) 146 | ``` 147 | 148 | 149 | ## Barrier 150 | 151 | If you'd like to keep the user from dismissing the tooltip by clicking on the barrier, you can change `showBarrier` to `true` which means pressing on the scrim area will not immediately hide the tooltip. 152 | 153 | ```dart 154 | SuperTooltip( 155 | showBarrier: true, 156 | barrierColor: Colors.red, 157 | //... 158 | ) 159 | ``` 160 | 161 | ## Blur 162 | 163 | If you'd like to also show blur behind the pop up, you can do that by making the `showDropBoxFilter` to `true` you must also enable `showBarrier` then set `sigmaX` and `sigmaY` 164 | 165 | ```dart 166 | SuperTooltip( 167 | showBarrier: true, 168 | showDropBoxFilter: true, 169 | sigmaX: 10, 170 | sigmaY: 10, 171 | //... 172 | ) 173 | ``` 174 | 175 | 176 | 177 | If you'd like to simply react to open or close states, you can pass through `onHide` or `onShow` callbacks to the default constructor. 178 | 179 | ```dart 180 | SuperTooltip( 181 | onDismiss: () { 182 | // Maybe continue tutorial? 183 | }, 184 | onShow: () { 185 | // Start animation? 186 | } 187 | ), 188 | ``` 189 | 190 | To hide the tooltip when the user tap the back button. Wrap your `GestureDetector` widget with `WillPopScope` widget passing a callback function to `onWillPop` like the example below 191 | 192 | ```dart 193 | return WillPopScope( 194 | onWillPop: _willPopCallback, 195 | child: GestureDetector( 196 | onTap: () async { 197 | await _controller.showTooltip(); 198 | }, 199 | // .. 200 | ), 201 | ); 202 | ``` 203 | 204 | Create a callback function to dismiss 205 | 206 | ```dart 207 | Future _willPopCallback() async { 208 | // If the tooltip is open we don't pop the page on a backbutton press 209 | // but close the ToolTip 210 | if (_controller.isVisible) { 211 | await _controller.hideTooltip(); 212 | return false; 213 | } 214 | return true; 215 | } 216 | ``` 217 | 218 | ## Example app 219 | 220 | Find the example app [here](https://github.com/bensonarafat/super_tooltip/tree/master/example). 221 | 222 | 223 | 224 | 225 | 226 | Made with [contrib.rocks](https://contrib.rocks). 227 | 228 | ## Contributing 229 | 230 | Contributions are welcome. 231 | In case of any problems look at [existing issues](https://github.com/bensonarafat/super_tooltip/issues), if you cannot find anything related to your problem then open an issue. 232 | Create an issue before opening a [pull request](https://github.com/bensonarafat/super_tooltip/pulls) for non-trivial fixes. 233 | In case of trivial fixes open a [pull request](https://github.com/bensonarafat/super_tooltip/pulls) directly. 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | errors: 5 | unused_import: error 6 | unused_local_variable: warning 7 | dead_code: error 8 | exclude: 9 | 10 | linter: 11 | rules: 12 | - annotate_overrides 13 | - avoid_empty_else 14 | - avoid_function_literals_in_foreach_calls 15 | - avoid_init_to_null 16 | - avoid_null_checks_in_equality_operators 17 | - avoid_renaming_method_parameters 18 | - avoid_return_types_on_setters 19 | - avoid_types_as_parameter_names 20 | - avoid_unused_constructor_parameters 21 | - await_only_futures 22 | - camel_case_types 23 | - comment_references 24 | - control_flow_in_finally 25 | - directives_ordering 26 | - empty_catches 27 | - empty_constructor_bodies 28 | - empty_statements 29 | - hash_and_equals 30 | - library_names 31 | - library_prefixes 32 | - no_adjacent_strings_in_list 33 | - no_duplicate_case_values 34 | - non_constant_identifier_names 35 | - omit_local_variable_types 36 | - overridden_fields 37 | - package_names 38 | - package_prefixed_library_names 39 | - prefer_adjacent_string_concatenation 40 | - prefer_collection_literals 41 | - prefer_conditional_assignment 42 | - prefer_contains 43 | - prefer_final_fields 44 | - prefer_initializing_formals 45 | - prefer_is_empty 46 | - prefer_is_not_empty 47 | - prefer_typing_uninitialized_variables 48 | - recursive_getters 49 | - slash_for_doc_comments 50 | - test_types_in_equals 51 | - throw_in_finally 52 | - type_init_formals 53 | - unawaited_futures 54 | - unnecessary_brace_in_string_interps 55 | - unnecessary_getters_setters 56 | - unnecessary_null_aware_assignments 57 | - unnecessary_statements 58 | - unrelated_type_equality_checks 59 | - valid_regexps -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import androidx.annotation.Keep; 4 | import androidx.annotation.NonNull; 5 | import io.flutter.Log; 6 | 7 | import io.flutter.embedding.engine.FlutterEngine; 8 | 9 | /** 10 | * Generated file. Do not edit. 11 | * This file is generated by the Flutter tool based on the 12 | * plugins that support the Android platform. 13 | */ 14 | @Keep 15 | public final class GeneratedPluginRegistrant { 16 | private static final String TAG = "GeneratedPluginRegistrant"; 17 | public static void registerWith(@NonNull FlutterEngine flutterEngine) { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | sdk.dir=/Users/bensonarafat/Library/Android/sdk 2 | flutter.sdk=/Users/bensonarafat/development/flutter -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: adc9dde3ba8563eebb824feb689f95eb947ab745 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # super_tooltip_example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | def localProperties = new Properties() 7 | def localPropertiesFile = rootProject.file('local.properties') 8 | if (localPropertiesFile.exists()) { 9 | localPropertiesFile.withReader('UTF-8') { reader -> 10 | localProperties.load(reader) 11 | } 12 | } 13 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 14 | if (flutterVersionCode == null) { 15 | flutterVersionCode = '1' 16 | } 17 | 18 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 19 | if (flutterVersionName == null) { 20 | flutterVersionName = '1.0' 21 | } 22 | 23 | // apply plugin: 'com.android.application' 24 | // apply plugin: 'kotlin-android' 25 | // apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion flutter.compileSdkVersion 29 | 30 | sourceSets { 31 | main.java.srcDirs += 'src/main/kotlin' 32 | } 33 | 34 | lintOptions { 35 | disable 'InvalidPackage' 36 | } 37 | 38 | defaultConfig { 39 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 40 | applicationId "com.example.super_tooltip_example" 41 | minSdkVersion flutter.minSdkVersion 42 | targetSdkVersion 28 43 | versionCode flutterVersionCode.toInteger() 44 | versionName flutterVersionName 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | } 55 | 56 | flutter { 57 | source '../..' 58 | } 59 | 60 | dependencies { 61 | // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 62 | } -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/super_tooltip_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.super_tooltip_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | allprojects { 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | } 8 | 9 | rootProject.buildDir = '../build' 10 | subprojects { 11 | project.buildDir = "${rootProject.buildDir}/${project.name}" 12 | } 13 | subprojects { 14 | project.evaluationDependsOn(':app') 15 | } 16 | 17 | tasks.register("clean", Delete) { 18 | delete rootProject.buildDir 19 | } -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | 3 | pluginManagement { 4 | def flutterSdkPath = { 5 | def properties = new Properties() 6 | file("local.properties").withInputStream { properties.load(it) } 7 | def flutterSdkPath = properties.getProperty("flutter.sdk") 8 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 9 | return flutterSdkPath 10 | }() 11 | 12 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 13 | 14 | repositories { 15 | google() 16 | mavenCentral() 17 | gradlePluginPortal() 18 | } 19 | } 20 | 21 | plugins { 22 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 23 | id "com.android.application" version "7.3.0" apply false 24 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 25 | } 26 | include ':app' -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1510; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | alwaysOutOfDate = 1; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | ); 178 | inputPaths = ( 179 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 180 | ); 181 | name = "Thin Binary"; 182 | outputPaths = ( 183 | ); 184 | runOnlyForDeploymentPostprocessing = 0; 185 | shellPath = /bin/sh; 186 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 187 | }; 188 | 9740EEB61CF901F6004384FC /* Run Script */ = { 189 | isa = PBXShellScriptBuildPhase; 190 | alwaysOutOfDate = 1; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | ); 194 | inputPaths = ( 195 | ); 196 | name = "Run Script"; 197 | outputPaths = ( 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | shellPath = /bin/sh; 201 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 202 | }; 203 | /* End PBXShellScriptBuildPhase section */ 204 | 205 | /* Begin PBXSourcesBuildPhase section */ 206 | 97C146EA1CF9000F007C117D /* Sources */ = { 207 | isa = PBXSourcesBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 211 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | }; 215 | /* End PBXSourcesBuildPhase section */ 216 | 217 | /* Begin PBXVariantGroup section */ 218 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 219 | isa = PBXVariantGroup; 220 | children = ( 221 | 97C146FB1CF9000F007C117D /* Base */, 222 | ); 223 | name = Main.storyboard; 224 | sourceTree = ""; 225 | }; 226 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 227 | isa = PBXVariantGroup; 228 | children = ( 229 | 97C147001CF9000F007C117D /* Base */, 230 | ); 231 | name = LaunchScreen.storyboard; 232 | sourceTree = ""; 233 | }; 234 | /* End PBXVariantGroup section */ 235 | 236 | /* Begin XCBuildConfiguration section */ 237 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ANALYZER_NONNULL = YES; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_ENABLE_MODULES = YES; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_COMMA = YES; 249 | CLANG_WARN_CONSTANT_CONVERSION = YES; 250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_EMPTY_BODY = YES; 253 | CLANG_WARN_ENUM_CONVERSION = YES; 254 | CLANG_WARN_INFINITE_RECURSION = YES; 255 | CLANG_WARN_INT_CONVERSION = YES; 256 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 257 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 258 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 261 | CLANG_WARN_STRICT_PROTOTYPES = YES; 262 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 263 | CLANG_WARN_UNREACHABLE_CODE = YES; 264 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 265 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 266 | COPY_PHASE_STRIP = NO; 267 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 268 | ENABLE_NS_ASSERTIONS = NO; 269 | ENABLE_STRICT_OBJC_MSGSEND = YES; 270 | GCC_C_LANGUAGE_STANDARD = gnu99; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 273 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 274 | GCC_WARN_UNDECLARED_SELECTOR = YES; 275 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 276 | GCC_WARN_UNUSED_FUNCTION = YES; 277 | GCC_WARN_UNUSED_VARIABLE = YES; 278 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 279 | MTL_ENABLE_DEBUG_INFO = NO; 280 | SDKROOT = iphoneos; 281 | SUPPORTED_PLATFORMS = iphoneos; 282 | TARGETED_DEVICE_FAMILY = "1,2"; 283 | VALIDATE_PRODUCT = YES; 284 | }; 285 | name = Profile; 286 | }; 287 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 288 | isa = XCBuildConfiguration; 289 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 290 | buildSettings = { 291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 292 | CLANG_ENABLE_MODULES = YES; 293 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 294 | ENABLE_BITCODE = NO; 295 | FRAMEWORK_SEARCH_PATHS = ( 296 | "$(inherited)", 297 | "$(PROJECT_DIR)/Flutter", 298 | ); 299 | INFOPLIST_FILE = Runner/Info.plist; 300 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 301 | LIBRARY_SEARCH_PATHS = ( 302 | "$(inherited)", 303 | "$(PROJECT_DIR)/Flutter", 304 | ); 305 | PRODUCT_BUNDLE_IDENTIFIER = com.example.superTooltipExample; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 308 | SWIFT_VERSION = 5.0; 309 | VERSIONING_SYSTEM = "apple-generic"; 310 | }; 311 | name = Profile; 312 | }; 313 | 97C147031CF9000F007C117D /* Debug */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ALWAYS_SEARCH_USER_PATHS = NO; 317 | CLANG_ANALYZER_NONNULL = YES; 318 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 319 | CLANG_CXX_LIBRARY = "libc++"; 320 | CLANG_ENABLE_MODULES = YES; 321 | CLANG_ENABLE_OBJC_ARC = YES; 322 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_COMMA = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_EMPTY_BODY = YES; 329 | CLANG_WARN_ENUM_CONVERSION = YES; 330 | CLANG_WARN_INFINITE_RECURSION = YES; 331 | CLANG_WARN_INT_CONVERSION = YES; 332 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 333 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 334 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 335 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 337 | CLANG_WARN_STRICT_PROTOTYPES = YES; 338 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = dwarf; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | ENABLE_TESTABILITY = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_DYNAMIC_NO_PIC = NO; 348 | GCC_NO_COMMON_BLOCKS = YES; 349 | GCC_OPTIMIZATION_LEVEL = 0; 350 | GCC_PREPROCESSOR_DEFINITIONS = ( 351 | "DEBUG=1", 352 | "$(inherited)", 353 | ); 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 361 | MTL_ENABLE_DEBUG_INFO = YES; 362 | ONLY_ACTIVE_ARCH = YES; 363 | SDKROOT = iphoneos; 364 | TARGETED_DEVICE_FAMILY = "1,2"; 365 | }; 366 | name = Debug; 367 | }; 368 | 97C147041CF9000F007C117D /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_ANALYZER_NONNULL = YES; 373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 374 | CLANG_CXX_LIBRARY = "libc++"; 375 | CLANG_ENABLE_MODULES = YES; 376 | CLANG_ENABLE_OBJC_ARC = YES; 377 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 378 | CLANG_WARN_BOOL_CONVERSION = YES; 379 | CLANG_WARN_COMMA = YES; 380 | CLANG_WARN_CONSTANT_CONVERSION = YES; 381 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 382 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 383 | CLANG_WARN_EMPTY_BODY = YES; 384 | CLANG_WARN_ENUM_CONVERSION = YES; 385 | CLANG_WARN_INFINITE_RECURSION = YES; 386 | CLANG_WARN_INT_CONVERSION = YES; 387 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 388 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 389 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 390 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 391 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 392 | CLANG_WARN_STRICT_PROTOTYPES = YES; 393 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 394 | CLANG_WARN_UNREACHABLE_CODE = YES; 395 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 397 | COPY_PHASE_STRIP = NO; 398 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 399 | ENABLE_NS_ASSERTIONS = NO; 400 | ENABLE_STRICT_OBJC_MSGSEND = YES; 401 | GCC_C_LANGUAGE_STANDARD = gnu99; 402 | GCC_NO_COMMON_BLOCKS = YES; 403 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 404 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 405 | GCC_WARN_UNDECLARED_SELECTOR = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 407 | GCC_WARN_UNUSED_FUNCTION = YES; 408 | GCC_WARN_UNUSED_VARIABLE = YES; 409 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 410 | MTL_ENABLE_DEBUG_INFO = NO; 411 | SDKROOT = iphoneos; 412 | SUPPORTED_PLATFORMS = iphoneos; 413 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 414 | TARGETED_DEVICE_FAMILY = "1,2"; 415 | VALIDATE_PRODUCT = YES; 416 | }; 417 | name = Release; 418 | }; 419 | 97C147061CF9000F007C117D /* Debug */ = { 420 | isa = XCBuildConfiguration; 421 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 422 | buildSettings = { 423 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 424 | CLANG_ENABLE_MODULES = YES; 425 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 426 | ENABLE_BITCODE = NO; 427 | FRAMEWORK_SEARCH_PATHS = ( 428 | "$(inherited)", 429 | "$(PROJECT_DIR)/Flutter", 430 | ); 431 | INFOPLIST_FILE = Runner/Info.plist; 432 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 433 | LIBRARY_SEARCH_PATHS = ( 434 | "$(inherited)", 435 | "$(PROJECT_DIR)/Flutter", 436 | ); 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.superTooltipExample; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 441 | SWIFT_VERSION = 5.0; 442 | VERSIONING_SYSTEM = "apple-generic"; 443 | }; 444 | name = Debug; 445 | }; 446 | 97C147071CF9000F007C117D /* Release */ = { 447 | isa = XCBuildConfiguration; 448 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 449 | buildSettings = { 450 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 451 | CLANG_ENABLE_MODULES = YES; 452 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 453 | ENABLE_BITCODE = NO; 454 | FRAMEWORK_SEARCH_PATHS = ( 455 | "$(inherited)", 456 | "$(PROJECT_DIR)/Flutter", 457 | ); 458 | INFOPLIST_FILE = Runner/Info.plist; 459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 460 | LIBRARY_SEARCH_PATHS = ( 461 | "$(inherited)", 462 | "$(PROJECT_DIR)/Flutter", 463 | ); 464 | PRODUCT_BUNDLE_IDENTIFIER = com.example.superTooltipExample; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 467 | SWIFT_VERSION = 5.0; 468 | VERSIONING_SYSTEM = "apple-generic"; 469 | }; 470 | name = Release; 471 | }; 472 | /* End XCBuildConfiguration section */ 473 | 474 | /* Begin XCConfigurationList section */ 475 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 476 | isa = XCConfigurationList; 477 | buildConfigurations = ( 478 | 97C147031CF9000F007C117D /* Debug */, 479 | 97C147041CF9000F007C117D /* Release */, 480 | 249021D3217E4FDB00AE95B9 /* Profile */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 486 | isa = XCConfigurationList; 487 | buildConfigurations = ( 488 | 97C147061CF9000F007C117D /* Debug */, 489 | 97C147071CF9000F007C117D /* Release */, 490 | 249021D4217E4FDB00AE95B9 /* Profile */, 491 | ); 492 | defaultConfigurationIsVisible = 0; 493 | defaultConfigurationName = Release; 494 | }; 495 | /* End XCConfigurationList section */ 496 | }; 497 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 498 | } 499 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | super_tooltip_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:super_tooltip/super_tooltip.dart'; 3 | 4 | void main() => runApp(const MainApp()); 5 | 6 | class MainApp extends StatelessWidget { 7 | const MainApp({Key? key}) : super(key: key); 8 | 9 | // This widget is the root of your application. 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | title: 'Super Tooltip Demo', 14 | theme: ThemeData( 15 | primarySwatch: Colors.blue, 16 | ), 17 | home: const ExamplePage(), 18 | ); 19 | } 20 | } 21 | 22 | class ExamplePage extends StatefulWidget { 23 | const ExamplePage({ 24 | Key? key, 25 | }) : super(key: key); 26 | @override 27 | State createState() => _ExamplePageState(); 28 | } 29 | 30 | class _ExamplePageState extends State { 31 | @override 32 | Widget build(BuildContext context) { 33 | return Scaffold( 34 | backgroundColor: Colors.white, 35 | body: Center( 36 | child: TargetWidget(), 37 | ), 38 | ); 39 | } 40 | } 41 | 42 | class TargetWidget extends StatefulWidget { 43 | const TargetWidget({Key? key}) : super(key: key); 44 | 45 | @override 46 | State createState() => _TargetWidgetState(); 47 | } 48 | 49 | class _TargetWidgetState extends State { 50 | final _controller = SuperTooltipController(); 51 | Future? _willPopCallback() async { 52 | // If the tooltip is open we don't pop the page on a backbutton press 53 | // but close the ToolTip 54 | if (_controller.isVisible) { 55 | await _controller.hideTooltip(); 56 | return false; 57 | } 58 | return true; 59 | } 60 | 61 | TooltipDirection _tooltipDirection = TooltipDirection.left; 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | return PopScope( 66 | onPopInvokedWithResult: (didPop, result) => _willPopCallback, 67 | child: Column( 68 | mainAxisSize: MainAxisSize.min, 69 | children: [ 70 | SuperTooltip( 71 | controller: _controller, 72 | popupDirection: TooltipDirection.left, 73 | popupDirectionBuilder: () { 74 | return _tooltipDirection; 75 | }, 76 | backgroundColor: Color(0xff2f2d2f), 77 | showCloseButton: true, 78 | left: 30, 79 | right: 30, 80 | bottom: 200, 81 | arrowTipDistance: 20.0, 82 | minimumOutsideMargin: 120, 83 | arrowBaseWidth: 20.0, 84 | arrowLength: 20.0, 85 | borderWidth: 2.0, 86 | constraints: const BoxConstraints( 87 | minHeight: 0.0, 88 | maxHeight: 100, 89 | minWidth: 0.0, 90 | maxWidth: 100, 91 | ), 92 | touchThroughAreaShape: ClipAreaShape.rectangle, 93 | touchThroughAreaCornerRadius: 30, 94 | barrierColor: Color.fromARGB(26, 47, 45, 47), 95 | content: const Text( 96 | "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.", 97 | softWrap: true, 98 | textAlign: TextAlign.center, 99 | style: TextStyle( 100 | color: Colors.white, 101 | ), 102 | ), 103 | child: Container( 104 | width: 40.0, 105 | height: 40.0, 106 | decoration: const BoxDecoration( 107 | shape: BoxShape.circle, 108 | color: Colors.blue, 109 | ), 110 | child: Icon( 111 | Icons.add, 112 | color: Colors.white, 113 | ), 114 | ), 115 | ), 116 | Center( 117 | child: Row( 118 | mainAxisSize: MainAxisSize.min, 119 | children: [ 120 | IconButton( 121 | onPressed: () { 122 | _tooltipDirection = TooltipDirection.left; 123 | }, 124 | icon: Icon( 125 | Icons.arrow_left, 126 | ), 127 | ), 128 | IconButton( 129 | onPressed: () { 130 | _tooltipDirection = TooltipDirection.right; 131 | }, 132 | icon: Icon( 133 | Icons.arrow_right, 134 | ), 135 | ), 136 | ], 137 | ), 138 | ) 139 | ], 140 | ), 141 | ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: super_tooltip_example 2 | description: A new Flutter project. 3 | publish_to: none 4 | 5 | # The following defines the version and build number for your application. 6 | # A version number is three numbers separated by dots, like 1.2.43 7 | # followed by an optional build number separated by a +. 8 | # Both the version and the builder number may be overridden in flutter 9 | # build by specifying --build-name and --build-number, respectively. 10 | # Read more about versioning at semver.org. 11 | version: 1.0.0+1 12 | 13 | environment: 14 | sdk: '>=2.18.6 <3.0.0' 15 | 16 | 17 | dependencies: 18 | flutter: 19 | sdk: flutter 20 | super_tooltip: 21 | path: ../ 22 | 23 | # The following adds the Cupertino Icons font to your application. 24 | # Use with the CupertinoIcons class for iOS style icons. 25 | cupertino_icons: ^1.0.5 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | 32 | # For information on the generic Dart part of this file, see the 33 | # following page: https://www.dartlang.org/tools/pub/pubspec 34 | 35 | # The following section is specific to Flutter. 36 | flutter: 37 | 38 | # The following line ensures that the Material Icons font is 39 | # included with your application, so that you can use the icons in 40 | # the material Icons class. 41 | uses-material-design: true 42 | 43 | # To add assets to your application, add an assets section, like this: 44 | # assets: 45 | # - images/a_dot_burr.jpeg 46 | # - images/a_dot_ham.jpeg 47 | 48 | # An image asset can refer to one or more resolution-specific "variants", see 49 | # https://flutter.io/assets-and-images/#resolution-aware. 50 | 51 | # For details regarding adding assets from package dependencies, see 52 | # https://flutter.io/assets-and-images/#from-packages 53 | 54 | # To add custom fonts to your application, add a fonts section here, 55 | # in this "flutter" section. Each entry in this list should have a 56 | # "family" key with the font family name, and a "fonts" key with a 57 | # list giving the asset and other descriptors for the font. For 58 | # example: 59 | # fonts: 60 | # - family: Schyler 61 | # fonts: 62 | # - asset: fonts/Schyler-Regular.ttf 63 | # - asset: fonts/Schyler-Italic.ttf 64 | # style: italic 65 | # - family: Trajan Pro 66 | # fonts: 67 | # - asset: fonts/TrajanPro.ttf 68 | # - asset: fonts/TrajanPro_Bold.ttf 69 | # weight: 700 70 | # 71 | # For details regarding fonts from package dependencies, 72 | # see https://flutter.io/custom-fonts/#from-packages 73 | -------------------------------------------------------------------------------- /example/super_tooltip_example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/src/bubble_shape.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'enums.dart'; 6 | 7 | class BubbleShape extends ShapeBorder { 8 | const BubbleShape({ 9 | required this.preferredDirection, 10 | required this.target, 11 | required this.borderRadius, 12 | required this.arrowTipRadius, 13 | required this.arrowBaseWidth, 14 | required this.arrowTipDistance, 15 | required this.borderColor, 16 | required this.borderWidth, 17 | required this.left, 18 | required this.top, 19 | required this.right, 20 | required this.bottom, 21 | required this.bubbleDimensions, 22 | }); 23 | 24 | final Offset target; 25 | final double arrowBaseWidth; 26 | final double arrowTipDistance; 27 | final double borderRadius; 28 | final double arrowTipRadius; 29 | final Color borderColor; 30 | final double borderWidth; 31 | final double? left, top, right, bottom; 32 | final TooltipDirection preferredDirection; 33 | final EdgeInsetsGeometry bubbleDimensions; 34 | 35 | @override 36 | EdgeInsetsGeometry get dimensions => bubbleDimensions; 37 | 38 | @override 39 | Path getInnerPath(Rect rect, {TextDirection? textDirection}) => Path() 40 | ..fillType = PathFillType.evenOdd 41 | ..addPath(getOuterPath(rect), Offset.zero); 42 | 43 | @override 44 | Path getOuterPath(Rect rect, {TextDirection? textDirection}) { 45 | // 46 | late double topLeftRadius, 47 | topRightRadius, 48 | bottomLeftRadius, 49 | bottomRightRadius; 50 | 51 | Path getLeftTopPath(Rect rect) => Path() 52 | ..moveTo(rect.left, rect.bottom - bottomLeftRadius) 53 | ..lineTo(rect.left, rect.top + topLeftRadius) 54 | ..arcToPoint( 55 | Offset(rect.left + topLeftRadius, rect.top), 56 | radius: Radius.circular(topLeftRadius), 57 | ) 58 | ..lineTo(rect.right - topRightRadius, rect.top) 59 | ..arcToPoint( 60 | Offset(rect.right, rect.top + topRightRadius), 61 | radius: Radius.circular(topRightRadius), 62 | clockwise: true, 63 | ); 64 | 65 | Path getBottomRightPath(Rect rect) => Path() 66 | ..moveTo(rect.left + bottomLeftRadius, rect.bottom) 67 | ..lineTo(rect.right - bottomRightRadius, rect.bottom) 68 | ..arcToPoint( 69 | Offset(rect.right, rect.bottom - bottomRightRadius), 70 | radius: Radius.circular(bottomRightRadius), 71 | clockwise: false, 72 | ) 73 | ..lineTo(rect.right, rect.top + topRightRadius) 74 | ..arcToPoint( 75 | Offset(rect.right - topRightRadius, rect.top), 76 | radius: Radius.circular(topRightRadius), 77 | clockwise: false, 78 | ); 79 | 80 | topLeftRadius = (left == 0 || top == 0) ? 0.0 : borderRadius; 81 | topRightRadius = (right == 0 || top == 0) ? 0.0 : borderRadius; 82 | bottomLeftRadius = (left == 0 || bottom == 0) ? 0.0 : borderRadius; 83 | bottomRightRadius = (right == 0 || bottom == 0) ? 0.0 : borderRadius; 84 | 85 | switch (preferredDirection) { 86 | case TooltipDirection.down: 87 | return getBottomRightPath(rect) 88 | ..lineTo( 89 | min( 90 | max( 91 | target.dx + arrowBaseWidth / 2, 92 | rect.left + borderRadius + arrowBaseWidth, 93 | ), 94 | rect.right - topRightRadius, 95 | ), 96 | rect.top, 97 | ) 98 | // up to arrow tip where the curve starts 99 | ..lineTo( 100 | target.dx + arrowTipRadius / sqrt(2), //sin and cos 45 = 1/root(2) 101 | target.dy + 102 | arrowTipDistance - 103 | (arrowTipRadius - arrowTipRadius / sqrt(2))) 104 | 105 | //arc for the tip 106 | ..arcToPoint( 107 | Offset( 108 | target.dx - arrowTipRadius / sqrt(2), 109 | target.dy + 110 | arrowTipDistance - 111 | (arrowTipRadius - arrowTipRadius / sqrt(2))), 112 | radius: Radius.circular(arrowTipRadius), 113 | clockwise: false) 114 | 115 | // down / 116 | ..lineTo( 117 | max( 118 | min( 119 | target.dx - arrowBaseWidth / 2, 120 | rect.right - topLeftRadius - arrowBaseWidth, 121 | ), 122 | rect.left + topLeftRadius, 123 | ), 124 | rect.top, 125 | ) 126 | ..lineTo(rect.left + topLeftRadius, rect.top) 127 | ..arcToPoint( 128 | Offset(rect.left, rect.top + topLeftRadius), 129 | radius: Radius.circular(topLeftRadius), 130 | clockwise: false, 131 | ) 132 | ..lineTo(rect.left, rect.bottom - bottomLeftRadius) 133 | ..arcToPoint( 134 | Offset(rect.left + bottomLeftRadius, rect.bottom), 135 | radius: Radius.circular(bottomLeftRadius), 136 | clockwise: false, 137 | ); 138 | 139 | case TooltipDirection.up: 140 | return getLeftTopPath(rect) 141 | ..lineTo(rect.right, rect.bottom - bottomRightRadius) 142 | ..arcToPoint(Offset(rect.right - bottomRightRadius, rect.bottom), 143 | radius: Radius.circular(bottomRightRadius), clockwise: true) 144 | ..lineTo( 145 | min( 146 | max(target.dx + arrowBaseWidth / 2, 147 | rect.left + bottomLeftRadius + arrowBaseWidth), 148 | rect.right - bottomRightRadius), 149 | rect.bottom) 150 | 151 | // down to arrow tip curvature start\ 152 | ..lineTo( 153 | target.dx + arrowTipRadius / sqrt(2), //sin and cos 45 = 1/root(2) 154 | target.dy - 155 | arrowTipDistance + 156 | (arrowTipRadius - arrowTipRadius / sqrt(2))) 157 | 158 | //arc for the tip 159 | ..arcToPoint( 160 | Offset( 161 | target.dx - arrowTipRadius / sqrt(2), 162 | target.dy - 163 | arrowTipDistance + 164 | (arrowTipRadius - arrowTipRadius / sqrt(2))), 165 | radius: Radius.circular(arrowTipRadius)) 166 | 167 | // up / 168 | ..lineTo( 169 | max( 170 | min(target.dx - arrowBaseWidth / 2, 171 | rect.right - bottomRightRadius - arrowBaseWidth), 172 | rect.left + bottomLeftRadius), 173 | rect.bottom) 174 | ..lineTo(rect.left + bottomLeftRadius, rect.bottom) 175 | ..arcToPoint(Offset(rect.left, rect.bottom - bottomLeftRadius), 176 | radius: Radius.circular(bottomLeftRadius), clockwise: true) 177 | ..lineTo(rect.left, rect.top + topLeftRadius) 178 | ..arcToPoint(Offset(rect.left + topLeftRadius, rect.top), 179 | radius: Radius.circular(topLeftRadius), clockwise: true); 180 | 181 | case TooltipDirection.left: 182 | return getLeftTopPath(rect) 183 | ..lineTo( 184 | rect.right, 185 | max( 186 | min(target.dy - arrowBaseWidth / 2, 187 | rect.bottom - bottomRightRadius - arrowBaseWidth), 188 | rect.top + topRightRadius)) 189 | 190 | // right to arrow tip to the start point of the arc \ 191 | ..lineTo( 192 | target.dx - 193 | arrowTipDistance + 194 | (arrowTipRadius - arrowTipRadius / sqrt(2)), 195 | target.dy - arrowTipRadius / sqrt(2)) 196 | 197 | //arc for the tip 198 | ..arcToPoint( 199 | Offset( 200 | target.dx - 201 | arrowTipDistance + 202 | (arrowTipRadius - arrowTipRadius / sqrt(2)), 203 | target.dy + arrowTipRadius / sqrt(2), 204 | ), 205 | radius: Radius.circular(arrowTipRadius), 206 | ) 207 | 208 | // left / 209 | ..lineTo( 210 | rect.right, 211 | min(target.dy + arrowBaseWidth / 2, 212 | rect.bottom - bottomRightRadius)) 213 | ..lineTo(rect.right, rect.bottom - borderRadius) 214 | ..arcToPoint(Offset(rect.right - bottomRightRadius, rect.bottom), 215 | radius: Radius.circular(bottomRightRadius), clockwise: true) 216 | ..lineTo(rect.left + bottomLeftRadius, rect.bottom) 217 | ..arcToPoint(Offset(rect.left, rect.bottom - bottomLeftRadius), 218 | radius: Radius.circular(bottomLeftRadius), clockwise: true); 219 | 220 | case TooltipDirection.right: 221 | return getBottomRightPath(rect) 222 | ..lineTo(rect.left + topLeftRadius, rect.top) 223 | ..arcToPoint(Offset(rect.left, rect.top + topLeftRadius), 224 | radius: Radius.circular(topLeftRadius), clockwise: false) 225 | ..lineTo( 226 | rect.left, 227 | max( 228 | min(target.dy - arrowBaseWidth / 2, 229 | rect.bottom - bottomLeftRadius - arrowBaseWidth), 230 | rect.top + topLeftRadius)) 231 | 232 | //left to arrow tip till curve start/ 233 | 234 | ..lineTo( 235 | target.dx + 236 | arrowTipDistance - 237 | (arrowTipRadius - arrowTipRadius / sqrt(2)), 238 | target.dy - arrowTipRadius / sqrt(2)) 239 | 240 | //arc for the tip 241 | ..arcToPoint( 242 | Offset( 243 | target.dx + 244 | arrowTipDistance - 245 | (arrowTipRadius - arrowTipRadius / sqrt(2)), 246 | target.dy + arrowTipRadius / sqrt(2)), 247 | radius: Radius.circular(arrowTipRadius), 248 | clockwise: false) 249 | 250 | // right \ 251 | ..lineTo( 252 | rect.left, 253 | min(target.dy + arrowBaseWidth / 2, 254 | rect.bottom - bottomLeftRadius)) 255 | ..lineTo(rect.left, rect.bottom - bottomLeftRadius) 256 | ..arcToPoint(Offset(rect.left + bottomLeftRadius, rect.bottom), 257 | radius: Radius.circular(bottomLeftRadius), clockwise: false); 258 | 259 | default: 260 | throw ArgumentError(preferredDirection); 261 | } 262 | } 263 | 264 | @override 265 | void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { 266 | var paint = Paint() 267 | ..color = borderColor 268 | ..style = PaintingStyle.stroke 269 | ..strokeWidth = borderWidth; 270 | 271 | canvas.drawPath(getOuterPath(rect), paint); 272 | 273 | paint = Paint() 274 | ..color = Colors.white 275 | ..style = PaintingStyle.stroke 276 | ..strokeWidth = borderWidth; 277 | 278 | if (right == 0.0) { 279 | if (top == 0.0 && bottom == 0.0) { 280 | canvas.drawPath( 281 | Path() 282 | ..moveTo(rect.right, rect.top) 283 | ..lineTo(rect.right, rect.bottom), 284 | paint, 285 | ); 286 | } else { 287 | canvas.drawPath( 288 | Path() 289 | ..moveTo(rect.right, rect.top + borderWidth / 2) 290 | ..lineTo(rect.right, rect.bottom - borderWidth / 2), 291 | paint, 292 | ); 293 | } 294 | } 295 | if (left == 0.0) { 296 | if (top == 0.0 && bottom == 0.0) { 297 | canvas.drawPath( 298 | Path() 299 | ..moveTo(rect.left, rect.top) 300 | ..lineTo(rect.left, rect.bottom), 301 | paint, 302 | ); 303 | } else { 304 | canvas.drawPath( 305 | Path() 306 | ..moveTo(rect.left, rect.top + borderWidth / 2) 307 | ..lineTo(rect.left, rect.bottom - borderWidth / 2), 308 | paint, 309 | ); 310 | } 311 | } 312 | if (top == 0.0) { 313 | if (left == 0.0 && right == 0.0) { 314 | canvas.drawPath( 315 | Path() 316 | ..moveTo(rect.right, rect.top) 317 | ..lineTo(rect.left, rect.top), 318 | paint, 319 | ); 320 | } else { 321 | canvas.drawPath( 322 | Path() 323 | ..moveTo(rect.right - borderWidth / 2, rect.top) 324 | ..lineTo(rect.left + borderWidth / 2, rect.top), 325 | paint, 326 | ); 327 | } 328 | } 329 | if (bottom == 0.0) { 330 | if (left == 0.0 && right == 0.0) { 331 | canvas.drawPath( 332 | Path() 333 | ..moveTo(rect.right, rect.bottom) 334 | ..lineTo(rect.left, rect.bottom), 335 | paint, 336 | ); 337 | } else { 338 | canvas.drawPath( 339 | Path() 340 | ..moveTo(rect.right - borderWidth / 2, rect.bottom) 341 | ..lineTo(rect.left + borderWidth / 2, rect.bottom), 342 | paint, 343 | ); 344 | } 345 | } 346 | } 347 | 348 | @override 349 | ShapeBorder scale(double t) { 350 | return BubbleShape( 351 | preferredDirection: preferredDirection, 352 | target: target, 353 | borderRadius: borderRadius, 354 | arrowTipRadius: arrowTipRadius, 355 | arrowBaseWidth: arrowBaseWidth, 356 | arrowTipDistance: arrowTipDistance, 357 | borderColor: borderColor, 358 | borderWidth: borderWidth, 359 | left: left, 360 | top: top, 361 | right: right, 362 | bottom: bottom, 363 | bubbleDimensions: bubbleDimensions, 364 | ); 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /lib/src/enums.dart: -------------------------------------------------------------------------------- 1 | enum TooltipDirection { up, down, left, right } 2 | 3 | enum CloseButtonType { inside, outside } 4 | 5 | enum ClipAreaShape { oval, rectangle } 6 | 7 | enum Event { show, hide } 8 | -------------------------------------------------------------------------------- /lib/src/shape_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'enums.dart'; 5 | 6 | class ShapeOverlay extends ShapeBorder { 7 | const ShapeOverlay({ 8 | required this.clipRect, 9 | required this.clipAreaShape, 10 | required this.clipAreaCornerRadius, 11 | required this.barrierColor, 12 | required this.overlayDimensions, 13 | }); 14 | 15 | final Rect? clipRect; 16 | final ClipAreaShape clipAreaShape; 17 | final double clipAreaCornerRadius; 18 | final Color? barrierColor; 19 | final EdgeInsetsGeometry overlayDimensions; 20 | 21 | @override 22 | EdgeInsetsGeometry get dimensions => overlayDimensions; 23 | 24 | @override 25 | Path getInnerPath(Rect rect, {TextDirection? textDirection}) => 26 | Path()..addOval(clipRect!); 27 | 28 | @override 29 | Path getOuterPath(Rect rect, {TextDirection? textDirection}) { 30 | var outer = Path()..addRect(rect); 31 | 32 | if (clipRect == null) return outer; 33 | 34 | Path exclusion; 35 | 36 | if (clipAreaShape == ClipAreaShape.oval) { 37 | exclusion = Path()..addOval(clipRect!); 38 | } else { 39 | exclusion = Path() 40 | ..moveTo(clipRect!.left + clipAreaCornerRadius, clipRect!.top) 41 | ..lineTo(clipRect!.right - clipAreaCornerRadius, clipRect!.top) 42 | ..arcToPoint( 43 | Offset(clipRect!.right, clipRect!.top + clipAreaCornerRadius), 44 | radius: Radius.circular(clipAreaCornerRadius), 45 | ) 46 | ..lineTo(clipRect!.right, clipRect!.bottom - clipAreaCornerRadius) 47 | ..arcToPoint( 48 | Offset(clipRect!.right - clipAreaCornerRadius, clipRect!.bottom), 49 | radius: Radius.circular(clipAreaCornerRadius), 50 | ) 51 | ..lineTo(clipRect!.left + clipAreaCornerRadius, clipRect!.bottom) 52 | ..arcToPoint( 53 | Offset(clipRect!.left, clipRect!.bottom - clipAreaCornerRadius), 54 | radius: Radius.circular(clipAreaCornerRadius), 55 | ) 56 | ..lineTo(clipRect!.left, clipRect!.top + clipAreaCornerRadius) 57 | ..arcToPoint( 58 | Offset(clipRect!.left + clipAreaCornerRadius, clipRect!.top), 59 | radius: Radius.circular(clipAreaCornerRadius), 60 | ) 61 | ..close(); 62 | } 63 | 64 | return Path.combine(ui.PathOperation.difference, outer, exclusion); 65 | } 66 | 67 | @override 68 | void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) => 69 | canvas.drawPath( 70 | getOuterPath(rect), 71 | Paint()..color = barrierColor!, 72 | ); 73 | 74 | @override 75 | ShapeBorder scale(double t) { 76 | return ShapeOverlay( 77 | clipRect: clipRect, 78 | clipAreaShape: clipAreaShape, 79 | clipAreaCornerRadius: clipAreaCornerRadius, 80 | barrierColor: barrierColor, 81 | overlayDimensions: overlayDimensions, 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/src/super_tooltip.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: comment_references 2 | 3 | import 'dart:ui'; 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:super_tooltip/src/utils.dart'; 7 | 8 | import 'bubble_shape.dart'; 9 | import 'enums.dart'; 10 | import 'shape_overlay.dart'; 11 | import 'super_tooltip_controller.dart'; 12 | import 'tooltip_position_delegate.dart'; 13 | 14 | typedef DecorationBuilder = Decoration Function( 15 | Offset target, 16 | ); 17 | 18 | /// A powerful and customizable tooltip widget for Flutter. 19 | /// 20 | /// `SuperTooltip` provides a flexible and feature-rich way to display tooltips 21 | /// in your Flutter applications. It offers several advantages over the standard 22 | /// Flutter `Tooltip` widget, including: 23 | /// 24 | /// * **Flexible Positioning:** Control the tooltip's position relative to its 25 | /// target widget using the `popupDirection`, `top`, `right`, `bottom`, and 26 | /// `left` parameters. 27 | /// * **Customizable Appearance:** Customize the tooltip's background color, 28 | /// border, shadow, and more using the `backgroundColor`, `decoration`, 29 | /// `borderColor`, and other styling parameters. 30 | /// * **Barrier and Blur:** Optionally display a barrier (scrim) and blur effect 31 | /// behind the tooltip using the `showBarrier`, `barrierColor`, 32 | /// `showDropBoxFilter`, `sigmaX`, and `sigmaY` parameters. 33 | /// * **Close Button:** Add a close button to allow users to manually dismiss the 34 | /// tooltip using the `showCloseButton` and `closeButtonType` parameters. 35 | /// * **Animation:** Smooth fade-in and fade-out animations for a visually 36 | /// appealing experience. 37 | /// * **Event Callbacks:** Trigger actions when the tooltip is shown or hidden 38 | /// using the `onShow` and `onHide` callbacks. 39 | /// * **Touch-Through Area:** Define an area that allows touch events to pass 40 | /// through the barrier using the `touchThroughArea` parameter. 41 | /// 42 | /// To use `SuperTooltip`, wrap your target widget with a `GestureDetector`, 43 | /// `MouseRegion`, or `InkWell` and use the `controller` to manage the 44 | /// tooltip's visibility. 45 | /// 46 | /// ```dart 47 | /// final _controller = SuperTooltipController(); 48 | /// 49 | /// GestureDetector( 50 | /// onTap: () => _controller.showTooltip(), 51 | /// child: SuperTooltip( 52 | /// controller: _controller, 53 | /// content: const Text('This is a tooltip!'), 54 | /// child: const Icon(Icons.info), 55 | /// ), 56 | /// ) 57 | /// ``` 58 | 59 | class SuperTooltip extends StatefulWidget { 60 | // Creates a `SuperTooltip` widget. 61 | /// 62 | /// The `content` parameter is required and specifies the widget to be 63 | /// displayed inside the tooltip. 64 | final Widget content; 65 | 66 | /// The direction in which the tooltip should appear relative to its 67 | /// target widget. 68 | /// 69 | /// Defaults to [TooltipDirection.down]. 70 | /// 71 | /// See also: 72 | /// 73 | /// * [TooltipDirection], which defines the possible tooltip directions. 74 | final TooltipDirection popupDirection; 75 | 76 | /// The direction in which the tooltip should appear relative to its 77 | /// target widget. 78 | /// 79 | /// Defaults to [TooltipDirection.down]. 80 | /// 81 | /// See also: 82 | /// 83 | /// * [TooltipDirection], which defines the possible tooltip directions. 84 | final TooltipDirection Function()? popupDirectionBuilder; 85 | 86 | /// A [SuperTooltipController] to manage the tooltip's visibility and state. 87 | /// 88 | /// If not provided, a new [SuperTooltipController] will be created 89 | /// internally. 90 | final SuperTooltipController? controller; 91 | 92 | /// Called when the user long presses the target widget. 93 | final void Function()? onLongPress; 94 | 95 | /// Called when the tooltip is shown. 96 | final void Function()? onShow; 97 | 98 | /// Called when the tooltip is hidden. 99 | final void Function()? onHide; 100 | 101 | /// Whether the tooltip should snap to the top or bottom of the screen 102 | /// if there's not enough space in the preferred direction. 103 | /// 104 | /// Defaults to `false`. 105 | final bool snapsFarAwayVertically; 106 | 107 | /// Whether the tooltip should snap to the left or right of the screen 108 | /// if there's not enough space in the preferred direction. 109 | /// 110 | /// Defaults to `false`. 111 | final bool snapsFarAwayHorizontally; 112 | 113 | /// Whether the tooltip should have a shadow. 114 | /// 115 | /// Defaults to `true`. 116 | final bool? hasShadow; 117 | 118 | /// The color of the shadow. 119 | /// 120 | /// If not provided, the default color will be used. 121 | final Color? shadowColor; 122 | 123 | /// The blur radius of the shadow. 124 | /// 125 | /// If not provided, the default blur radius will be used. 126 | final double? shadowBlurRadius; 127 | 128 | /// The spread radius of the shadow. 129 | /// 130 | /// If not provided, the default spread radius will be used. 131 | final double? shadowSpreadRadius; 132 | 133 | /// The offset of the shadow. 134 | /// 135 | /// If not provided, the default offset will be used. 136 | final Offset? shadowOffset; 137 | 138 | /// [top], [right], [bottom], [left] define the distance between the respective 139 | /// edges of the tooltip and the corresponding edges of the screen. 140 | /// 141 | /// If not provided, the tooltip will be positioned as close as possible 142 | /// to the specified edge, respecting the `minimumOutsideMargin`. 143 | final double? top, right, bottom, left; 144 | 145 | /// Whether to display a close button inside the tooltip. 146 | /// 147 | /// Defaults to `false`. 148 | final bool showCloseButton; 149 | 150 | /// The type of close button to display. 151 | /// 152 | /// Defaults to [CloseButtonType.inside]. 153 | /// 154 | /// See also: 155 | /// 156 | /// * [CloseButtonType], which defines the possible close button types. 157 | final CloseButtonType closeButtonType; 158 | 159 | /// The color of the close button. 160 | /// 161 | /// If not provided, the default color will be used. 162 | final Color? closeButtonColor; 163 | 164 | /// The size of the close button. 165 | /// 166 | /// If not provided, the default size will be used. 167 | final double? closeButtonSize; 168 | 169 | /// The minimum margin between the tooltip and the edges of the screen. 170 | /// 171 | /// Defaults to `20.0`. 172 | final double minimumOutsideMargin; 173 | 174 | /// The vertical offset of the tooltip from its target widget. 175 | /// 176 | /// Defaults to `0.0`. 177 | final double verticalOffset; 178 | 179 | /// The target widget to which the tooltip is attached. 180 | final Widget? child; 181 | 182 | /// The border color of the tooltip. 183 | /// 184 | /// Defaults to `Colors.black`. 185 | final Color borderColor; 186 | 187 | /// Box constraints for the tooltip's size. 188 | /// 189 | /// Defaults to: 190 | /// ```dart 191 | /// const BoxConstraints( 192 | /// minHeight: 0.0, 193 | /// maxHeight: double.infinity, 194 | /// minWidth: 0.0, 195 | /// maxWidth: double.infinity, 196 | /// ) 197 | /// ``` 198 | final BoxConstraints constraints; 199 | 200 | /// The background color of the tooltip. 201 | /// 202 | /// If not provided, the default background color will be used. 203 | final Color? backgroundColor; 204 | 205 | /// A custom decoration for the tooltip. 206 | /// 207 | /// If not provided, the default decoration will be used. 208 | final DecorationBuilder? decorationBuilder; 209 | 210 | /// The elevation of the tooltip. 211 | /// 212 | /// Defaults to `0.0`. 213 | final double elevation; 214 | 215 | /// The duration of the fade-in animation. 216 | /// 217 | /// Defaults to `const Duration(milliseconds: 150)`. 218 | final Duration fadeInDuration; 219 | 220 | /// The duration of the fade-out animation. 221 | /// 222 | /// Defaults to `const Duration(milliseconds: 0)`. 223 | final Duration fadeOutDuration; 224 | 225 | /// The length of the tooltip's arrow. 226 | /// 227 | /// Defaults to `20.0`. 228 | final double arrowLength; 229 | 230 | /// The width of the tooltip's arrow base. 231 | /// 232 | /// Defaults to `20.0`. 233 | final double arrowBaseWidth; 234 | 235 | /// The distance between the arrow tip and the target widget. 236 | /// 237 | /// Defaults to `2.0`. 238 | final double arrowTipRadius; 239 | 240 | final double arrowTipDistance; 241 | 242 | /// The border radius of the tooltip. 243 | /// 244 | /// Defaults to `10.0`. 245 | final double borderRadius; 246 | 247 | /// The width of the tooltip's border. 248 | /// 249 | /// Defaults to `0.0`. 250 | final double borderWidth; 251 | 252 | /// Whether to display a barrier (scrim) behind the tooltip. 253 | /// 254 | /// Defaults to `true`. 255 | final bool? showBarrier; 256 | 257 | /// The color of the barrier. 258 | /// 259 | /// If not provided, the default color will be used. 260 | final Color? barrierColor; 261 | 262 | /// A rectangular area that allows touch events to pass through the barrier. 263 | final Rect? touchThroughArea; 264 | 265 | /// The shape of the touch-through area. 266 | /// 267 | /// Defaults to [ClipAreaShape.oval]. 268 | /// 269 | /// See also: 270 | /// 271 | /// * [ClipAreaShape], which defines the possible touch-through area shapes. 272 | final ClipAreaShape touchThroughAreaShape; 273 | 274 | /// The corner radius of the touch-through area. 275 | /// 276 | /// Defaults to `5.0`. 277 | final double touchThroughAreaCornerRadius; 278 | 279 | /// EdgeInsetsGeometry for the overlay. 280 | /// 281 | /// Defaults to `const EdgeInsets.all(10)`. 282 | final EdgeInsetsGeometry overlayDimensions; 283 | 284 | /// EdgeInsetsGeometry for the bubble. 285 | /// 286 | /// Defaults to `const EdgeInsets.all(10)`. 287 | final EdgeInsetsGeometry bubbleDimensions; 288 | 289 | /// Whether to hide the tooltip when tapped. 290 | /// 291 | /// Defaults to `false`. 292 | final bool hideTooltipOnTap; 293 | 294 | /// Whether to hide the tooltip when the barrier is tapped. 295 | /// 296 | /// Defaults to `true`. 297 | final bool hideTooltipOnBarrierTap; 298 | 299 | /// Whether to toggle the tooltip's visibility when tapped. 300 | /// 301 | /// Defaults to `false`. 302 | final bool toggleOnTap; 303 | final bool showOnTap; 304 | 305 | /// Whether to show a blur filter behind the tooltip. 306 | /// 307 | /// Defaults to `false`. 308 | final bool showDropBoxFilter; 309 | 310 | /// The sigmaX value for the blur filter (if `showDropBoxFilter` is `true`). 311 | /// 312 | /// Defaults to `5.0`. 313 | final double sigmaX; 314 | 315 | /// The sigmaY value for the blur filter (if `showDropBoxFilter` is `true`). 316 | /// 317 | /// Defaults to `5.0`. 318 | final double sigmaY; 319 | 320 | /// A list of box shadows to apply to the tooltip. 321 | final List? boxShadows; 322 | 323 | /// Whether the tooltip should be click-through. 324 | /// 325 | /// Defaults to `false`. 326 | final bool clickThrough; 327 | 328 | SuperTooltip({ 329 | Key? key, 330 | required this.content, 331 | this.popupDirection = TooltipDirection.down, 332 | this.controller, 333 | this.onLongPress, 334 | this.onShow, 335 | this.onHide, 336 | this.popupDirectionBuilder, 337 | /** 338 | * showCloseButton 339 | * This will enable the closeButton 340 | */ 341 | this.showCloseButton = false, 342 | this.closeButtonType = CloseButtonType.inside, 343 | this.closeButtonColor, 344 | this.closeButtonSize, 345 | this.showBarrier, 346 | this.barrierColor, 347 | this.snapsFarAwayVertically = false, 348 | this.snapsFarAwayHorizontally = false, 349 | this.hasShadow, 350 | this.shadowColor, 351 | this.shadowBlurRadius, 352 | this.shadowSpreadRadius, 353 | this.shadowOffset, 354 | this.top, 355 | this.right, 356 | this.bottom, 357 | this.left, 358 | // TD: Make edgeinsets instead 359 | this.minimumOutsideMargin = 20.0, 360 | this.verticalOffset = 0.0, 361 | this.elevation = 0.0, 362 | // TD: The native flutter tooltip uses verticalOffset 363 | // to space the tooltip from the child. But we'll likely 364 | // need just offset, since it's 4 way directional 365 | // this.verticalOffset = 24.0, 366 | this.backgroundColor, 367 | 368 | // 369 | // 370 | // 371 | this.decorationBuilder, 372 | this.child, 373 | this.borderColor = Colors.black, 374 | this.constraints = const BoxConstraints( 375 | minHeight: 0.0, 376 | maxHeight: double.infinity, 377 | minWidth: 0.0, 378 | maxWidth: double.infinity, 379 | ), 380 | this.fadeInDuration = const Duration(milliseconds: 150), 381 | this.fadeOutDuration = const Duration(milliseconds: 0), 382 | this.arrowLength = 20.0, 383 | this.arrowBaseWidth = 20.0, 384 | this.arrowTipRadius = 0.0, 385 | this.arrowTipDistance = 2.0, 386 | this.touchThroughAreaShape = ClipAreaShape.oval, 387 | this.touchThroughAreaCornerRadius = 5.0, 388 | this.touchThroughArea, 389 | this.borderWidth = 0.0, 390 | this.borderRadius = 10.0, 391 | this.overlayDimensions = const EdgeInsets.all(10), 392 | this.bubbleDimensions = const EdgeInsets.all(10), 393 | this.hideTooltipOnTap = false, 394 | this.sigmaX = 5.0, 395 | this.sigmaY = 5.0, 396 | this.showDropBoxFilter = false, 397 | this.hideTooltipOnBarrierTap = true, 398 | this.toggleOnTap = false, 399 | this.showOnTap = true, 400 | this.boxShadows, 401 | this.clickThrough = false, 402 | }) : assert(showDropBoxFilter ? showBarrier ?? false : true, 403 | 'showDropBoxFilter or showBarrier can\'t be false | null'), 404 | super(key: key); 405 | 406 | /// Key used to identify the inside close button. 407 | static Key insideCloseButtonKey = const Key("InsideCloseButtonKey"); 408 | 409 | /// Key used to identify the outside close button. 410 | static Key outsideCloseButtonKey = const Key("OutsideCloseButtonKey"); 411 | 412 | /// Key used to identify the barrier. 413 | static Key barrierKey = const Key("barrierKey"); 414 | 415 | /// Key used to identify the bubble. 416 | static Key bubbleKey = const Key("bubbleKey"); 417 | 418 | @override 419 | State createState() => _SuperTooltipState(); 420 | } 421 | 422 | class _SuperTooltipState extends State 423 | with SingleTickerProviderStateMixin { 424 | final LayerLink _layerLink = LayerLink(); 425 | late AnimationController _animationController; 426 | SuperTooltipController? _superTooltipController; 427 | OverlayEntry? _entry; 428 | OverlayEntry? _barrierEntry; 429 | OverlayEntry? blur; 430 | 431 | bool showCloseButton = false; 432 | CloseButtonType closeButtonType = CloseButtonType.inside; 433 | Color? closeButtonColor; 434 | double? closeButtonSize; 435 | late bool showBarrier; 436 | Color? barrierColor; 437 | late bool hasShadow; 438 | late Color shadowColor; 439 | late double shadowBlurRadius; 440 | late double shadowSpreadRadius; 441 | late Offset shadowOffset; 442 | late bool showBlur; 443 | 444 | @override 445 | void initState() { 446 | _animationController = AnimationController( 447 | duration: widget.fadeInDuration, 448 | reverseDuration: widget.fadeOutDuration, 449 | vsync: this, 450 | ); 451 | _superTooltipController = widget.controller ?? SuperTooltipController(); 452 | _superTooltipController!.addListener(_onChangeNotifier); 453 | 454 | // TD: Mouse stuff 455 | super.initState(); 456 | } 457 | 458 | @override 459 | void didUpdateWidget(SuperTooltip oldWidget) { 460 | if (_superTooltipController != widget.controller) { 461 | _superTooltipController!.removeListener(_onChangeNotifier); 462 | _superTooltipController = widget.controller ?? SuperTooltipController(); 463 | _superTooltipController!.addListener(_onChangeNotifier); 464 | } 465 | super.didUpdateWidget(oldWidget); 466 | } 467 | 468 | // @override 469 | @override 470 | void dispose() { 471 | if (_entry != null) _removeEntries(); 472 | _superTooltipController?.removeListener(_onChangeNotifier); 473 | _animationController.dispose(); 474 | super.dispose(); 475 | } 476 | 477 | @override 478 | Widget build(BuildContext context) { 479 | showCloseButton = widget.showCloseButton; 480 | closeButtonType = widget.closeButtonType; 481 | closeButtonColor = widget.closeButtonColor ?? Colors.black; 482 | closeButtonSize = widget.closeButtonSize ?? 30.0; 483 | showBarrier = widget.showBarrier ?? true; 484 | barrierColor = widget.barrierColor ?? Colors.black54; 485 | hasShadow = widget.hasShadow ?? true; 486 | shadowColor = widget.shadowColor ?? Colors.black54; 487 | shadowBlurRadius = widget.shadowBlurRadius ?? 10.0; 488 | shadowSpreadRadius = widget.shadowSpreadRadius ?? 5.0; 489 | shadowOffset = widget.shadowOffset ?? Offset.zero; 490 | showBlur = widget.showDropBoxFilter; 491 | 492 | return CompositedTransformTarget( 493 | link: _layerLink, 494 | child: GestureDetector( 495 | onTap: () { 496 | if (widget.toggleOnTap && _superTooltipController!.isVisible) { 497 | _superTooltipController!.hideTooltip(); 498 | } else { 499 | if (widget.showOnTap) { 500 | _superTooltipController!.showTooltip(); 501 | } 502 | } 503 | }, 504 | onLongPress: widget.onLongPress, 505 | child: widget.child, 506 | ), 507 | ); 508 | } 509 | 510 | /// Called when the [_superTooltipController] notifies its listeners. 511 | /// 512 | /// This method is used to show or hide the tooltip based on the event type. 513 | /// If the event is [Event.show], the [_showTooltip] method is called. If the 514 | /// event is [Event.hide], the [_hideTooltip] method is called. 515 | void _onChangeNotifier() { 516 | switch (_superTooltipController!.event) { 517 | // Show the tooltip. 518 | case Event.show: 519 | _showTooltip(); 520 | break; 521 | 522 | // Hide the tooltip. 523 | case Event.hide: 524 | _hideTooltip(); 525 | break; 526 | } 527 | } 528 | 529 | /// Creates the overlay entries for the tooltip, barrier, and blur filter (if enabled). 530 | /// 531 | /// The overlay entries are inserted into the [Overlay] using the [OverlayState.insertAll] method. 532 | /// The order of insertion is: blur filter overlay entry, barrier overlay entry, and tooltip overlay entry. 533 | void _createOverlayEntries() { 534 | // Find the render box of the widget. 535 | final renderBox = context.findRenderObject() as RenderBox; 536 | 537 | // Find the overlay state. 538 | final overlayState = Overlay.of(context); 539 | 540 | // Find the overlay render box (if available). 541 | RenderBox? overlay; 542 | 543 | // ignore: unnecessary_null_comparison 544 | if (overlayState != null) { 545 | overlay = overlayState.context.findRenderObject() as RenderBox?; 546 | } 547 | 548 | // Calculate the size of the widget. 549 | final size = renderBox.size; 550 | 551 | // Calculate the target position relative to the global coordinate system. 552 | final target = renderBox.localToGlobal(size.center(Offset.zero)); 553 | final animation = CurvedAnimation( 554 | parent: _animationController, 555 | curve: Curves.fastOutSlowIn, 556 | ); 557 | final offsetToTarget = Offset( 558 | -target.dx + size.width / 2, 559 | -target.dy + size.height / 2, 560 | ); 561 | final backgroundColor = 562 | widget.backgroundColor ?? Theme.of(context).cardColor; 563 | 564 | var constraints = widget.constraints; 565 | var preferredDirection = 566 | widget.popupDirectionBuilder?.call() ?? widget.popupDirection; 567 | var left = widget.left; 568 | var right = widget.right; 569 | var top = widget.top; 570 | var bottom = widget.bottom; 571 | 572 | if (widget.snapsFarAwayVertically) { 573 | constraints = constraints.copyWith(maxHeight: null); 574 | left = right = 0.0; 575 | 576 | if (overlay != null) { 577 | if (target.dy > overlay.size.center(Offset.zero).dy) { 578 | preferredDirection = TooltipDirection.up; 579 | top = 0.0; 580 | } else { 581 | preferredDirection = TooltipDirection.down; 582 | bottom = 0.0; 583 | } 584 | } else { 585 | // overlay is null - set default values 586 | preferredDirection = TooltipDirection.down; 587 | bottom = 0.0; 588 | } 589 | } else if (widget.snapsFarAwayHorizontally) { 590 | constraints = constraints.copyWith(maxHeight: null); 591 | top = bottom = 0.0; 592 | 593 | if (overlay != null) { 594 | if (target.dx < overlay.size.center(Offset.zero).dx) { 595 | preferredDirection = TooltipDirection.right; 596 | right = 0.0; 597 | } else { 598 | preferredDirection = TooltipDirection.left; 599 | left = 0.0; 600 | } 601 | } else { 602 | // overlay is null - set default values 603 | preferredDirection = TooltipDirection.left; 604 | left = 0.0; 605 | } 606 | } 607 | 608 | _barrierEntry = showBarrier 609 | ? OverlayEntry( 610 | builder: (context) => FadeTransition( 611 | opacity: animation, 612 | child: GestureDetector( 613 | onTap: widget.hideTooltipOnBarrierTap 614 | ? _superTooltipController!.hideTooltip 615 | : null, 616 | child: Container( 617 | key: SuperTooltip.barrierKey, 618 | decoration: ShapeDecoration( 619 | shape: ShapeOverlay( 620 | clipAreaCornerRadius: widget.touchThroughAreaCornerRadius, 621 | clipAreaShape: widget.touchThroughAreaShape, 622 | clipRect: widget.touchThroughArea, 623 | barrierColor: barrierColor, 624 | overlayDimensions: widget.overlayDimensions, 625 | ), 626 | ), 627 | ), 628 | ), 629 | ), 630 | ) 631 | : null; 632 | 633 | blur = showBlur 634 | ? OverlayEntry( 635 | builder: (BuildContext context) => FadeTransition( 636 | opacity: animation, 637 | child: BackdropFilter( 638 | filter: ImageFilter.blur( 639 | sigmaX: widget.sigmaX, 640 | sigmaY: widget.sigmaY, 641 | ), 642 | child: Container( 643 | width: double.infinity, 644 | height: double.infinity, 645 | ), 646 | ), 647 | ), 648 | ) 649 | : null; 650 | _entry = OverlayEntry( 651 | builder: (BuildContext context) => IgnorePointer( 652 | ignoring: widget.clickThrough, 653 | child: FadeTransition( 654 | opacity: animation, 655 | child: Center( 656 | child: CompositedTransformFollower( 657 | link: _layerLink, 658 | showWhenUnlinked: false, 659 | offset: offsetToTarget, 660 | child: CustomSingleChildLayout( 661 | delegate: TooltipPositionDelegate( 662 | preferredDirection: preferredDirection, 663 | constraints: constraints, 664 | top: top, 665 | bottom: bottom, 666 | left: left, 667 | right: right, 668 | target: target, 669 | // verticalOffset: widget.verticalOffset, 670 | overlay: overlay, 671 | margin: widget.minimumOutsideMargin, 672 | snapsFarAwayHorizontally: widget.snapsFarAwayHorizontally, 673 | snapsFarAwayVertically: widget.snapsFarAwayVertically, 674 | ), 675 | // TD: Text fields and such will need a material ancestor 676 | // In order to function properly. Need to find more elegant way 677 | // to add this. 678 | child: Stack( 679 | fit: StackFit.passthrough, 680 | children: [ 681 | Material( 682 | color: Colors.transparent, 683 | child: GestureDetector( 684 | behavior: HitTestBehavior.opaque, 685 | onTap: () { 686 | if (widget.hideTooltipOnTap) { 687 | _superTooltipController!.hideTooltip(); 688 | } 689 | }, 690 | child: Container( 691 | key: SuperTooltip.bubbleKey, 692 | margin: SuperUtils.getTooltipMargin( 693 | arrowLength: widget.arrowLength, 694 | arrowTipDistance: widget.arrowTipDistance, 695 | closeButtonSize: closeButtonSize, 696 | preferredDirection: preferredDirection, 697 | closeButtonType: closeButtonType, 698 | showCloseButton: showCloseButton, 699 | ), 700 | padding: SuperUtils.getTooltipPadding( 701 | closeButtonSize: closeButtonSize, 702 | closeButtonType: closeButtonType, 703 | showCloseButton: showCloseButton, 704 | ), 705 | decoration: widget.decorationBuilder != null 706 | ? widget.decorationBuilder!(target) 707 | : ShapeDecoration( 708 | color: backgroundColor, 709 | shadows: hasShadow 710 | ? widget.boxShadows ?? 711 | [ 712 | BoxShadow( 713 | blurRadius: shadowBlurRadius, 714 | spreadRadius: shadowSpreadRadius, 715 | color: shadowColor, 716 | offset: shadowOffset, 717 | ), 718 | ] 719 | : null, 720 | shape: BubbleShape( 721 | arrowBaseWidth: widget.arrowBaseWidth, 722 | arrowTipDistance: widget.arrowTipDistance, 723 | arrowTipRadius: widget.arrowTipRadius, 724 | borderColor: widget.borderColor, 725 | borderRadius: widget.borderRadius, 726 | borderWidth: widget.borderWidth, 727 | bottom: bottom, 728 | left: left, 729 | preferredDirection: preferredDirection, 730 | right: right, 731 | target: target, 732 | top: top, 733 | bubbleDimensions: widget.bubbleDimensions, 734 | ), 735 | ), 736 | child: widget.content, 737 | ), 738 | ), 739 | ), 740 | _buildCloseButton(), 741 | ], 742 | ), 743 | ), 744 | ), 745 | ), 746 | ), 747 | ), 748 | ); 749 | 750 | // ignore: unnecessary_null_comparison 751 | if (overlayState != null) { 752 | // Insert the overlay entries for the tooltip, barrier, and blur filter 753 | // (if enabled). 754 | overlayState.insertAll([ 755 | // Insert the blur filter overlay entry if enabled. 756 | if (showBlur) blur!, 757 | 758 | // Insert the barrier overlay entry if enabled. 759 | if (showBarrier) _barrierEntry!, 760 | 761 | // Insert the tooltip overlay entry. 762 | _entry!, 763 | ]); 764 | } 765 | } 766 | 767 | /// Shows the tooltip. 768 | /// 769 | /// This method starts the fade-in animation and adds the overlay entries for 770 | /// the tooltip, barrier, and blur filter (if enabled). 771 | /// 772 | /// The [onShow] callback is called before the animation starts. After the 773 | /// animation completes, the [SuperTooltipController.complete] method is called 774 | /// to complete the show operation. 775 | /// 776 | /// If the tooltip is already visible, this method does nothing. 777 | Future _showTooltip() async { 778 | // Call the onShow callback before the animation starts. 779 | widget.onShow?.call(); 780 | 781 | // Already visible. 782 | if (_entry != null) return; 783 | 784 | // Create the overlay entries for the tooltip, barrier, and blur filter. 785 | _createOverlayEntries(); 786 | 787 | // Start the fade-in animation and wait for it to complete. 788 | await _animationController 789 | .forward() 790 | .whenComplete(_superTooltipController!.complete); 791 | } 792 | 793 | /// Removes the overlay entries for the tooltip, barrier, and blur filter. 794 | /// 795 | /// This function removes the overlay entries for the tooltip, barrier, and 796 | /// blur filter. It sets the [_entry], [_barrierEntry], and [blur] variables to 797 | /// `null` after the removal. 798 | void _removeEntries() { 799 | // Remove the tooltip overlay entry. 800 | _entry?.remove(); 801 | _entry = null; 802 | 803 | // Remove the barrier overlay entry. 804 | _barrierEntry?.remove(); 805 | _barrierEntry = null; 806 | 807 | // Remove the blur filter overlay entry. 808 | blur?.remove(); 809 | blur = null; 810 | } 811 | 812 | /// Hides the tooltip. 813 | /// 814 | /// This method starts the fade-out animation and removes the overlay entries 815 | /// for the tooltip, barrier, and blur filter (if enabled). 816 | /// 817 | /// The [onHide] callback is called before the animation starts. After the 818 | /// animation completes, the [SuperTooltipController.complete] method is called 819 | /// to complete the hide operation. 820 | /// 821 | /// Finally, the method removes the overlay entries for the tooltip, barrier, and 822 | /// blur filter. 823 | Future _hideTooltip() async { 824 | // Call the onHide callback before the animation starts. 825 | widget.onHide?.call(); 826 | 827 | // Start the fade-out animation and wait for it to complete. 828 | await _animationController 829 | .reverse() 830 | .whenComplete(_superTooltipController!.complete); 831 | 832 | // Remove the overlay entries for the tooltip, barrier, and blur filter. 833 | _removeEntries(); 834 | } 835 | 836 | /// Builds the close button widget based on the tooltip's configuration and 837 | /// the current [TooltipDirection]. 838 | /// 839 | /// The position of the close button is calculated based on the 840 | /// [closeButtonType] and the [TooltipDirection]. The close button is positioned 841 | /// within the tooltip's content area. 842 | /// 843 | /// Returns the close button widget wrapped in a [Positioned] widget. 844 | Widget _buildCloseButton() { 845 | // Return an empty widget if close button is not enabled. 846 | if (!showCloseButton) { 847 | return const SizedBox.shrink(); 848 | } 849 | 850 | // Calculate the position of the close button based on the tooltip direction. 851 | double right; 852 | double top; 853 | 854 | switch (widget.popupDirectionBuilder?.call() ?? widget.popupDirection) { 855 | // 856 | // LEFT: ------------------------------------- 857 | case TooltipDirection.left: 858 | right = widget.arrowLength + widget.arrowTipDistance + 3.0; 859 | if (closeButtonType == CloseButtonType.inside) { 860 | // If the close button is inside the tooltip, position it at the top. 861 | top = 2.0; 862 | } else if (closeButtonType == CloseButtonType.outside) { 863 | // If the close button is outside the tooltip, position it at the top. 864 | top = 0.0; 865 | } else { 866 | throw AssertionError(closeButtonType); 867 | } 868 | break; 869 | 870 | // RIGHT/UP: --------------------------------- 871 | case TooltipDirection.right: 872 | case TooltipDirection.up: 873 | right = 5.0; 874 | if (closeButtonType == CloseButtonType.inside) { 875 | // If the close button is inside the tooltip, position it at the top. 876 | top = 2.0; 877 | } else if (closeButtonType == CloseButtonType.outside) { 878 | // If the close button is outside the tooltip, position it at the top. 879 | top = 0.0; 880 | } else { 881 | throw AssertionError(closeButtonType); 882 | } 883 | break; 884 | 885 | // DOWN: ------------------------------------- 886 | case TooltipDirection.down: 887 | right = 2.0; 888 | if (closeButtonType == CloseButtonType.inside) { 889 | // If the close button is inside the tooltip, position it below the arrow. 890 | top = widget.arrowLength + widget.arrowTipDistance + 2.0; 891 | } else if (closeButtonType == CloseButtonType.outside) { 892 | // If the close button is outside the tooltip, position it at the top. 893 | top = 0.0; 894 | } else { 895 | throw AssertionError(closeButtonType); 896 | } 897 | break; 898 | 899 | // --------------------------------------------- 900 | 901 | default: 902 | throw AssertionError( 903 | widget.popupDirectionBuilder?.call() ?? widget.popupDirection, 904 | ); 905 | } 906 | 907 | // Wrap the close button in a [Positioned] widget to position it within 908 | // the tooltip's content area. 909 | return Positioned( 910 | right: right, 911 | top: top, 912 | child: Material( 913 | color: Colors.transparent, 914 | child: IconButton( 915 | key: closeButtonType == CloseButtonType.inside 916 | ? SuperTooltip.insideCloseButtonKey 917 | : SuperTooltip.outsideCloseButtonKey, 918 | icon: Icon( 919 | Icons.close_outlined, 920 | size: closeButtonSize, 921 | color: closeButtonColor, 922 | ), 923 | onPressed: () async => await widget.controller!.hideTooltip(), 924 | ), 925 | ), 926 | ); 927 | } 928 | } 929 | -------------------------------------------------------------------------------- /lib/src/super_tooltip_controller.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'enums.dart'; 6 | 7 | class SuperTooltipController extends ChangeNotifier { 8 | late Completer _completer; 9 | bool _isVisible = false; 10 | bool get isVisible => _isVisible; 11 | 12 | late Event event; 13 | 14 | Future showTooltip() { 15 | event = Event.show; 16 | _completer = Completer(); 17 | notifyListeners(); 18 | return _completer.future.whenComplete(() => _isVisible = true); 19 | } 20 | 21 | Future hideTooltip() { 22 | event = Event.hide; 23 | _completer = Completer(); 24 | notifyListeners(); 25 | return _completer.future.whenComplete(() => _isVisible = false); 26 | } 27 | 28 | void complete() { 29 | if (!_completer.isCompleted) { 30 | _completer.complete(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/tooltip_position_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'enums.dart'; 4 | import 'utils.dart'; 5 | 6 | class TooltipPositionDelegate extends SingleChildLayoutDelegate { 7 | TooltipPositionDelegate({ 8 | required this.snapsFarAwayVertically, 9 | required this.snapsFarAwayHorizontally, 10 | required this.preferredDirection, 11 | required this.constraints, 12 | required this.margin, 13 | required this.top, 14 | required this.bottom, 15 | required this.left, 16 | required this.right, 17 | required this.target, 18 | // @required this.verticalOffset, 19 | required this.overlay, 20 | }); 21 | // assert(verticalOffset != null); 22 | 23 | final bool snapsFarAwayVertically; 24 | final bool snapsFarAwayHorizontally; 25 | // TD: Make this EdgeInsets 26 | final double margin; 27 | final Offset target; 28 | // final double verticalOffset; 29 | final RenderBox? overlay; 30 | final BoxConstraints constraints; 31 | 32 | final TooltipDirection preferredDirection; 33 | final double? top, bottom, left, right; 34 | 35 | @override 36 | BoxConstraints getConstraintsForChild(BoxConstraints constraints) { 37 | // TD: when margin is EdgeInsets, look into 38 | // constraints.deflate(margin); 39 | 40 | var newConstraints = constraints; 41 | 42 | switch (preferredDirection) { 43 | case TooltipDirection.up: 44 | case TooltipDirection.down: 45 | newConstraints = SuperUtils.verticalConstraints( 46 | constraints: newConstraints, 47 | margin: margin, 48 | bottom: bottom, 49 | isUp: preferredDirection == TooltipDirection.up, 50 | target: target, 51 | top: top, 52 | left: left, 53 | right: right, 54 | ); 55 | break; 56 | case TooltipDirection.right: 57 | case TooltipDirection.left: 58 | newConstraints = SuperUtils.horizontalConstraints( 59 | constraints: newConstraints, 60 | margin: margin, 61 | bottom: bottom, 62 | isRight: preferredDirection == TooltipDirection.right, 63 | target: target, 64 | top: top, 65 | left: left, 66 | right: right, 67 | ); 68 | break; 69 | } 70 | 71 | // TD: This scenerio should likely be avoided in the initial functions 72 | return newConstraints.copyWith( 73 | minHeight: newConstraints.minHeight > newConstraints.maxHeight 74 | ? newConstraints.maxHeight 75 | : newConstraints.minHeight, 76 | minWidth: newConstraints.minWidth > newConstraints.maxWidth 77 | ? newConstraints.maxWidth 78 | : newConstraints.minWidth, 79 | ); 80 | } 81 | 82 | @override 83 | Offset getPositionForChild(Size size, Size childSize) { 84 | // TD: If there isn't enough space for the child on the preferredDirection 85 | // use the opposite dirrection 86 | // 87 | // See: 88 | // return positionDependentBox( 89 | // size: size, 90 | // childSize: childSize, 91 | // target: target, 92 | // verticalOffset: verticalOffset, 93 | // preferBelow: preferBelow, 94 | // ); 95 | 96 | switch (preferredDirection) { 97 | case TooltipDirection.up: 98 | case TooltipDirection.down: 99 | final topOffset = preferredDirection == TooltipDirection.up 100 | ? top ?? target.dy - childSize.height 101 | : target.dy; 102 | 103 | return Offset( 104 | SuperUtils.leftMostXtoTarget( 105 | childSize: childSize, 106 | left: left, 107 | margin: margin, 108 | right: right, 109 | size: size, 110 | target: target, 111 | ), 112 | topOffset, 113 | ); 114 | 115 | case TooltipDirection.right: 116 | case TooltipDirection.left: 117 | final leftOffset = preferredDirection == TooltipDirection.left 118 | ? left ?? target.dx - childSize.width 119 | : target.dx; 120 | return Offset( 121 | leftOffset, 122 | SuperUtils.topMostYtoTarget( 123 | bottom: bottom, 124 | childSize: childSize, 125 | margin: margin, 126 | size: size, 127 | target: target, 128 | top: top, 129 | ), 130 | ); 131 | default: 132 | throw ArgumentError(preferredDirection); 133 | } 134 | } 135 | 136 | @override 137 | bool shouldRelayout(TooltipPositionDelegate oldDelegate) => true; 138 | } 139 | -------------------------------------------------------------------------------- /lib/src/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'enums.dart'; 5 | 6 | class SuperUtils { 7 | static EdgeInsets getTooltipMargin({ 8 | required CloseButtonType? closeButtonType, 9 | required double? closeButtonSize, 10 | required double arrowTipDistance, 11 | required double arrowLength, 12 | required TooltipDirection preferredDirection, 13 | required bool showCloseButton, 14 | }) { 15 | final top = !showCloseButton 16 | ? 0.0 17 | : (closeButtonType == CloseButtonType.outside) 18 | ? closeButtonSize! + 12 19 | : 0.0; 20 | 21 | switch (preferredDirection) { 22 | case TooltipDirection.down: 23 | return EdgeInsets.only(top: arrowTipDistance + arrowLength); 24 | 25 | case TooltipDirection.up: 26 | return EdgeInsets.only( 27 | bottom: arrowTipDistance + arrowLength, top: top); 28 | 29 | case TooltipDirection.left: 30 | return EdgeInsets.only(right: arrowTipDistance + arrowLength, top: top); 31 | 32 | case TooltipDirection.right: 33 | return EdgeInsets.only(left: arrowTipDistance + arrowLength, top: top); 34 | 35 | default: 36 | throw ArgumentError(preferredDirection); 37 | } 38 | } 39 | 40 | static EdgeInsets getTooltipPadding({ 41 | required CloseButtonType? closeButtonType, 42 | required double? closeButtonSize, 43 | required bool showCloseButton, 44 | }) { 45 | final top = !showCloseButton 46 | ? 0.0 47 | : (closeButtonType == CloseButtonType.inside) 48 | ? closeButtonSize! 49 | : 0.0; 50 | return EdgeInsets.only(top: top); 51 | } 52 | 53 | static double leftMostXtoTarget({ 54 | required double? left, 55 | required double? right, 56 | required double margin, 57 | required Size size, 58 | required Size childSize, 59 | required Offset target, 60 | }) { 61 | double leftMostXtoTarget; 62 | 63 | if (left != null) { 64 | leftMostXtoTarget = left; 65 | } else if (right != null) { 66 | // leftMostXtoTarget 67 | // ________________________ 68 | // | | 69 | // | childSize.width | 70 | // ________________________ 71 | // 72 | // topLeft -> | | | | <- topRight 73 | // | | | | 74 | // | | | | 75 | // ^ ^ 76 | // margin margin 77 | leftMostXtoTarget = max( 78 | size.topLeft(Offset.zero).dx + margin, 79 | size.topRight(Offset.zero).dx - margin - childSize.width - right, 80 | ); 81 | } else { 82 | leftMostXtoTarget = max( 83 | margin, 84 | min( 85 | target.dx - childSize.width / 2, 86 | size.topRight(Offset.zero).dx - margin - childSize.width, 87 | ), 88 | ); 89 | } 90 | 91 | return leftMostXtoTarget; 92 | } 93 | 94 | static double topMostYtoTarget({ 95 | required double? top, 96 | required double? bottom, 97 | required double margin, 98 | required Offset target, 99 | required Size size, 100 | required Size childSize, 101 | }) { 102 | double topmostYtoTarget; 103 | 104 | if (top != null) { 105 | topmostYtoTarget = top; 106 | } else if (bottom != null) { 107 | topmostYtoTarget = max( 108 | size.topLeft(Offset.zero).dy + margin, 109 | size.bottomRight(Offset.zero).dy - margin - childSize.height - bottom, 110 | ); 111 | } else { 112 | topmostYtoTarget = max( 113 | margin, 114 | min( 115 | target.dy - childSize.height / 2, 116 | size.bottomRight(Offset.zero).dy - margin - childSize.height, 117 | ), 118 | ); 119 | } 120 | 121 | return topmostYtoTarget; 122 | } 123 | 124 | static BoxConstraints horizontalConstraints({ 125 | required BoxConstraints constraints, 126 | required double? top, 127 | required double? bottom, 128 | required double? right, 129 | required double? left, 130 | required double margin, 131 | required bool isRight, 132 | required Offset target, 133 | }) { 134 | var maxHeight = constraints.maxHeight; 135 | var minWidth = constraints.minWidth; 136 | var maxWidth = constraints.maxWidth; 137 | 138 | if (top != null && bottom != null) { 139 | maxHeight = maxHeight - (top + bottom); 140 | } else if ((top != null && bottom == null) || 141 | (top == null && bottom != null)) { 142 | // make sure that the sum of top, bottom + _maxHeight isn't bigger than the screen Height. 143 | final sideDelta = (top ?? 0.0) + (bottom ?? 0.0) + margin; 144 | 145 | if (maxHeight > maxHeight - sideDelta) { 146 | maxHeight = maxHeight - sideDelta; 147 | } 148 | } else { 149 | if (maxHeight > maxHeight - 2 * margin) { 150 | maxHeight = maxHeight - 2 * margin; 151 | } 152 | } 153 | 154 | if (isRight) { 155 | if (right != null) { 156 | minWidth = maxWidth = maxWidth - right - target.dx; 157 | } else { 158 | maxWidth = min(maxWidth, maxWidth - target.dx) - margin; 159 | } 160 | } else { 161 | if (left != null) { 162 | minWidth = maxWidth = target.dx - left; 163 | } else { 164 | maxWidth = min(maxWidth, target.dx) - margin; 165 | } 166 | } 167 | 168 | return constraints.copyWith( 169 | maxHeight: maxHeight, 170 | minWidth: minWidth, 171 | maxWidth: maxWidth, 172 | ); 173 | } 174 | 175 | static BoxConstraints verticalConstraints({ 176 | required BoxConstraints constraints, 177 | required double margin, 178 | required bool isUp, 179 | required double? top, 180 | required double? left, 181 | required double? right, 182 | required double? bottom, 183 | required Offset target, 184 | }) { 185 | var minHeight = constraints.minHeight; 186 | var maxHeight = constraints.maxHeight; 187 | var maxWidth = constraints.maxWidth; 188 | 189 | if (left != null && right != null) { 190 | maxWidth = maxWidth - (left + right); 191 | } else if ((left != null && right == null) || 192 | (left == null && right != null)) { 193 | // make sure that the sum of left, right + maxwidth isn't bigger than the screen width. 194 | final sideDelta = (left ?? 0.0) + (right ?? 0.0) + margin; 195 | 196 | if (maxWidth > maxWidth - sideDelta) { 197 | maxWidth = maxWidth - sideDelta; 198 | } 199 | } else { 200 | if (maxWidth > maxWidth - 2 * margin) { 201 | maxWidth = maxWidth - 2 * margin; 202 | } 203 | } 204 | 205 | if (isUp) { 206 | if (top != null) { 207 | minHeight = maxHeight = target.dy - top; 208 | } else { 209 | maxHeight = min(maxHeight, target.dy) - margin; 210 | // TD: clamp minheight 211 | } 212 | } else { 213 | if (bottom != null) { 214 | minHeight = maxHeight = maxHeight - bottom - target.dy; 215 | } else { 216 | maxHeight = min(maxHeight, maxHeight - target.dy) - margin; 217 | // TD: clamp minheight 218 | } 219 | } 220 | 221 | return constraints.copyWith( 222 | minHeight: minHeight, 223 | maxHeight: maxHeight, 224 | maxWidth: maxWidth, 225 | ); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /lib/super_tooltip.dart: -------------------------------------------------------------------------------- 1 | library super_tooltip; 2 | 3 | export 'src/enums.dart'; 4 | export 'src/super_tooltip.dart'; 5 | export 'src/super_tooltip_controller.dart'; 6 | 7 | // References 8 | // https://github.com/escamoteur/super_tooltip 9 | // https://api.flutter.dev/flutter/painting/positionDependentBox.html 10 | // https://medium.com/saugo360/https-medium-com-saugo360-flutter-using-overlay-to-display-floating-widgets-2e6d0e8decb9 11 | -------------------------------------------------------------------------------- /makedoc.bat: -------------------------------------------------------------------------------- 1 | dartdoc --exclude 'dart:async,dart:collection,dart:convert,dart:core,dart:developer,dart:ffi,dart:html,dart:io,dart:isolate,dart:js,dart:js_util,dart:math,dart:typed_data,dart:ui' -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: super_tooltip 2 | description: Super flexible Tooltip class that gets opend in the screens overlay 3 | version: 2.0.9 4 | homepage: https://github.com/bensonarafat/super_tooltip 5 | 6 | 7 | environment: 8 | sdk: '>=2.18.6 <4.0.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://www.dartlang.org/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | 24 | # To add assets to your package, add an assets section, like this: 25 | # assets: 26 | # - images/a_dot_burr.jpeg 27 | # - images/a_dot_ham.jpeg 28 | # 29 | # For details regarding assets in packages, see 30 | # https://flutter.io/assets-and-images/#from-packages 31 | # 32 | # An image asset can refer to one or more resolution-specific "variants", see 33 | # https://flutter.io/assets-and-images/#resolution-aware. 34 | 35 | # To add custom fonts to your package, add a fonts section here, 36 | # in this "flutter" section. Each entry in this list should have a 37 | # "family" key with the font family name, and a "fonts" key with a 38 | # list giving the asset and other descriptors for the font. For 39 | # example: 40 | # fonts: 41 | # - family: Schyler 42 | # fonts: 43 | # - asset: fonts/Schyler-Regular.ttf 44 | # - asset: fonts/Schyler-Italic.ttf 45 | # style: italic 46 | # - family: Trajan Pro 47 | # fonts: 48 | # - asset: fonts/TrajanPro.ttf 49 | # - asset: fonts/TrajanPro_Bold.ttf 50 | # weight: 700 51 | # 52 | # For details regarding fonts in packages, see 53 | # https://flutter.io/custom-fonts/#from-packages 54 | -------------------------------------------------------------------------------- /screenshots/screenshot1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/screenshots/screenshot1.gif -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/screenshots/screenshot2.png -------------------------------------------------------------------------------- /screenshots/screenshot3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bensonarafat/super_tooltip/3914d9b1e253cd77dd1bc6c65b4dea02660649f5/screenshots/screenshot3.gif --------------------------------------------------------------------------------