├── .github ├── FUNDING.yml └── dependabot.yml ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── 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-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── audio.mp3 │ ├── audio_data.json │ ├── dance_monkey.mp3 │ ├── dm.json │ ├── images │ │ ├── customizations │ │ │ ├── cpaf.png │ │ │ ├── pa.png │ │ │ ├── paf.png │ │ │ ├── paf2.png │ │ │ ├── pai.png │ │ │ ├── pf.png │ │ │ ├── pg.png │ │ │ ├── pgf.png │ │ │ ├── ra.png │ │ │ ├── rai.png │ │ │ ├── rg.png │ │ │ ├── sa.png │ │ │ └── sai.png │ │ ├── gifs │ │ │ ├── cpa_gif.gif │ │ │ ├── pa_gif.gif │ │ │ ├── ra_gif.gif │ │ │ └── sa_gif.gif │ │ ├── inactive │ │ │ ├── curved_polygon.png │ │ │ ├── polygon.png │ │ │ ├── rectangle.png │ │ │ └── squiggly.png │ │ └── logo │ │ │ └── logo.png │ ├── shape_of_you.mp3 │ ├── soy.json │ ├── sp.json │ └── surface_pressure.mp3 ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── 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 │ ├── load_audio_data.dart │ ├── main.dart │ └── waveforms_dashboard.dart ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── test │ └── widget_test.dart └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json ├── lib ├── flutter_audio_waveforms.dart └── src │ ├── const │ └── colors.dart │ ├── core │ ├── audio_waveform.dart │ └── waveform_painters_ab.dart │ ├── util │ ├── check_samples_equality.dart │ └── waveform_alignment.dart │ └── waveforms │ ├── curved_polygon_waveform │ ├── active_inactive_waveform_painter.dart │ └── curved_polygon_waveform.dart │ ├── polygon_waveform │ ├── active_waveform_painter.dart │ ├── inactive_waveform_painter.dart │ └── polygon_waveform.dart │ ├── rectangle_waveform │ ├── active_waveform_painter.dart │ ├── inactive_waveform_painter.dart │ └── rectangle_waveform.dart │ └── squiggly_waveform │ ├── active_inactive_waveform_painter.dart │ └── squiggly_waveform.dart ├── pubspec.lock ├── pubspec.yaml └── test └── flutter_audio_waveforms_test.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [rutvik110] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pub" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.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 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/ephemeral 64 | **/ios/Flutter/app.flx 65 | **/ios/Flutter/app.zip 66 | **/ios/Flutter/flutter_assets/ 67 | **/ios/Flutter/flutter_export_environment.sh 68 | **/ios/ServiceDefinitions.json 69 | **/ios/Runner/GeneratedPluginRegistrant.* 70 | 71 | # Exceptions to above rules. 72 | !**/ios/**/default.mode1v3 73 | !**/ios/**/default.mode2v3 74 | !**/ios/**/default.pbxuser 75 | !**/ios/**/default.perspectivev3 76 | 77 | .fvm/ -------------------------------------------------------------------------------- /.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: ffb2ecea5223acdd139a5039be2f9c796962833d 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.2.1+8 2 | 3 | * Refactor 4 | ## 1.2.1+7 5 | 6 | * Documentation update. 7 | ## 1.2.1+6 8 | 9 | * Migration to Flutter 3.0 10 | * Updated min dart sdk version to 2.17.0 11 | * Using super parameters 12 | ## 1.2.1+5 13 | 14 | * Documentation update. Included web demo link and info about new customization options added in previous update. 15 | ## 1.2.1+4 16 | 17 | * Added customization options `isRoundedRectangle` and `isCentered` to RectangleWaveform. Setting `isRoundedRectangle` to true draws rounded rectangles instead of regular ones. Setting `isCentered` to true would align each rectangle in the center along Y axis with respect to it's center along it's height. `isCentered` won't have any effect if `absolute` is set to true. 18 | ## 1.1.1+4 19 | 20 | * Updates in Api for declaring waveforms. `maxDuration` and `elapsedDuration` are now made optional when you're declaring a waveform. Avoids having to provide them when not needed like in case when you need a static waveform without any active waveform track. 21 | ## 1.1.1+3 22 | 23 | * Documentation update. 24 | ## 1.1.1+2 25 | 26 | * Minor bug fix related to processing samples internally. 27 | ## 1.1.0+2 28 | 29 | * New Waveform type `CurvedPolygonWaveform` added. 30 | ## 1.0.0+1 31 | 32 | * Documentation update. 33 | ## 1.0.0 34 | 35 | * Initial release. 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rutvik Tak 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | Pub.dev Badge 5 | MIT License Badge 6 |

7 | 8 | 9 | A UI library for easily adding audio waveforms to your apps, with several customization options. 10 | 11 | Web Demo - [Flutter Audio Waveforms Web Demo](https://rutvik110.github.io/Flutter-Audio-Waveforms-Demo/#/) 12 | 13 | # Features 14 | 15 | You can use the following available waveform types. 16 | 17 | * Polygon 18 | * Rectangle 19 | * Squiggly 20 | * Curved Polygon 21 | 22 |

23 | 24 | 25 | 26 | 27 | 28 |

29 | 30 |
31 | 32 | Need to add some gradient to your waveform? Say no more! You get it along with other customization options. 33 |

34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |

48 |
49 | 50 | Want an active track for your audio out of the box? 51 | You get that too! 52 |

53 | 54 | 55 | 56 | 57 | 58 |

59 | 60 |
61 | 62 | > Check out the short demo of what package offers [here](https://vimeo.com/660623448) 63 | 64 | # Getting started 65 | 66 | The package gives you the ability to add waveforms and customize them. 67 | It's mostly like a UI library for waveforms with an additional ability to show active track for playing audio. 68 | 69 | So it relies on you to provide the necessary audio data which it needs to draw the waveform. 70 | The data we need is basically a list of points/samples that represents that audio. 71 | 72 | You can use this [audiowaveform program](https://github.com/bbc/audiowaveform) to get the [audio json file](https://gist.github.com/rutvik110/946ee0f3036a18da1297e57c547ae241) which will provide us the samples. 73 | After installing this program on your machine, generate the json file for an audio by using this command in your terminal. 74 | ```dart 75 | audiowaveform -i test.mp3 -o test.json 76 | ``` 77 | 78 | The generated data needs to be processed following some rules which are necessary to get the waveforms drawn properly. To process the data use [this processor](https://gist.github.com/rutvik110/31a588244d288e89368e8704c1437d34). 79 | 80 | Once you have the processed data points list then you can just pass it down to any of the waveforms available and get started using them. 81 | 82 | > Check out [this article](https://medium.com/@TakRutvik/how-to-add-audiowaveforms-to-your-flutter-apps-c948c205d2c7) for detailed introduction on this section. 83 | 84 | 85 | 86 | # Usage 87 | 88 | Usage of all waveforms available is the same with only exception of having more/less customization options for different waveforms. 89 | 90 | 91 | ```dart 92 | // For a regular waveform 93 | PolygonWaveform( 94 | samples: [], 95 | height: height, 96 | width: width, 97 | ) 98 | 99 | // If you want active track for playing audio, pass [maxDuration] and [elapsedDuration] 100 | PolygonWaveform( 101 | samples: [], 102 | height: height, 103 | width: width, 104 | maxDuration: maxDuration, 105 | elapsedDuration: elapsedDuration, 106 | ) 107 | ``` 108 | 109 | > Find detailed [example here](https://github.com/rutvik110/flutter_audio_waveforms/blob/master/example/lib/main.dart). 110 | 111 | # Properties 112 | 113 | **maxDuration**: 114 | 115 | Maximum duration of the audio. 116 | 117 | **elapsedDuration**: 118 | 119 | Elapsed Duration of the audio. 120 | 121 | **samples**: 122 | 123 | List of the audio data samples. 124 | > Check the **Getting Started** section on how to generate this. 125 | 126 | **height** : 127 | 128 | Waveform height. 129 | 130 | **width** : 131 | 132 | Waveform width. 133 | 134 | 135 | ## Customization Options 136 | 137 | **inactiveColor** : 138 | 139 | Color of the inactive waveform. 140 | 141 | **activeColor** : 142 | 143 | Color of the active waveform. 144 | 145 | **inactiveGradient** : 146 | 147 | Gradient of the inactive waveform. 148 | 149 | **activeGradient** : 150 | 151 | Gradient of the active waveform. 152 | 153 | **absolute** : 154 | 155 | Waveform drawn is one sided either above x-axis or below it depending on what `invert` is set to. 156 | 157 | Defaults to `false`. 158 | 159 | **invert** : 160 | 161 | Flips/inverts the waveform upside down. 162 | 163 | Defaults to `false`. 164 | 165 | **borderWidth** : 166 | 167 | Width of the border around waveform. 168 | 169 | Available only for `RectangleWaveform`. 170 | 171 | **isRoundedRectangle** : 172 | 173 | If true then rounded rectangles are drawn instead of regular rectangles. 174 | 175 | Available only for `RectangleWaveform`. 176 | 177 | **isCentered** : 178 | 179 | If true then rectangles are centered along the Y-axis with respect to their center along their height.
180 | If [absolute] is true then this would've no effect. 181 | 182 | Available only for `RectangleWaveform`. 183 | 184 | **strokeWidth** : 185 | 186 | Waveform stroke width. 187 | 188 | Available only for `SquigglyWaveform`, `CurvedPolygonWaveform`. 189 | 190 | **inactiveBorderColor**: 191 | 192 | Border color for inactive waveform. 193 | 194 | Available only for `RectangleWaveform`. 195 | 196 | **activeBorderColor**: 197 | 198 | Border color for active waveform. 199 | 200 | Available only for `RectangleWaveform`. 201 | 202 | **showActiveWaveform**: 203 | 204 | Whether to show active waveform or not. 205 | 206 | Defaults to `true`. 207 | 208 | 209 | ### **More customization options coming soon!** 210 | 211 | # Contributing Guide 212 | 213 | * Feature request :
If you have any new feature in mind from which this package can benefit then please let me know by filing an [issue here](https://github.com/rutvik110/flutter_audio_waveforms/issues). 214 | 215 | * Improvements :
Got any suggestions on improving the package, anything from API to performance then let me know by filing the [issue here](https://github.com/rutvik110/flutter_audio_waveforms/issues). 216 | 217 | * Bugs:
If you happen to come across anything that shoudln't be happening then please file an [issue here](https://github.com/rutvik110/flutter_audio_waveforms/issues) describing what the bug is and how to reproduce it with attached code and preview if possible. 218 | 219 | # Additional information 220 | 221 | What started as a challenge out of curiosity, is now a package that I hope will be helpful to many of you and it was actually really fun building it. 222 | 223 | Learned some good stuff while working on it and I hope to make it much more going forward. 224 | 225 | If this package helped you then I would appreciate if you ⭐️ the repo which would be enough for me to keep continue working on it 🤓 and feel free to drop by and [say hi](https://twitter.com/TakRutvik) anytime. 226 | 227 | 228 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | 3 | linter: 4 | rules: 5 | 6 | analyzer: 7 | exclude: 8 | - test/ 9 | plugins: 10 | - dart_code_metrics 11 | # errors: 12 | 13 | 14 | 15 | dart_code_metrics: 16 | metrics: 17 | cyclomatic-complexity: 20 18 | number-of-arguments: 4 19 | maximum-nesting-level: 5 20 | metrics-exclude: 21 | - test/** 22 | rules: 23 | - newline-before-return 24 | - no-boolean-literal-compare 25 | - prefer-trailing-comma 26 | - prefer-conditional-expressions 27 | - no-equal-then-else 28 | anti-patterns: 29 | - long-method 30 | - long-parameter-list 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /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 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /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. 5 | 6 | version: 7 | revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 17 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 18 | - platform: android 19 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 20 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 21 | - platform: ios 22 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 23 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 24 | - platform: linux 25 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 26 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 27 | - platform: macos 28 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 29 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 30 | - platform: web 31 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 32 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 33 | - platform: windows 34 | create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 35 | base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | [source code](https://github.com/rutvik110/flutter_audio_waveforms/blob/master/example/lib/readme_example.dart) 2 | 3 | 4 | ```dart 5 | 6 | import 'package:audioplayers/audioplayers.dart'; 7 | import 'package:example/load_audio_data.dart'; 8 | import 'package:flutter/foundation.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter/services.dart'; 11 | import 'package:flutter_audio_waveforms/flutter_audio_waveforms.dart'; 12 | 13 | void main() { 14 | runApp(const MyApp()); 15 | } 16 | 17 | class MyApp extends StatelessWidget { 18 | const MyApp({Key? key}) : super(key: key); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return const MaterialApp( 23 | title: 'Flutter Audio Waveforms', 24 | home: Home(), 25 | ); 26 | } 27 | } 28 | 29 | class Home extends StatefulWidget { 30 | const Home({Key? key}) : super(key: key); 31 | 32 | @override 33 | State createState() => _HomeState(); 34 | } 35 | 36 | class _HomeState extends State { 37 | late Duration maxDuration; 38 | late Duration elapsedDuration; 39 | late AudioCache audioPlayer; 40 | late List samples; 41 | late int totalSamples; 42 | 43 | late List audioData; 44 | 45 | List> audioDataList = [ 46 | [ 47 | 'assets/dm.json', 48 | 'dance_monkey.mp3', 49 | ], 50 | [ 51 | 'assets/soy.json', 52 | 'shape_of_you.mp3', 53 | ], 54 | [ 55 | 'assets/sp.json', 56 | 'surface_pressure.mp3', 57 | ], 58 | ]; 59 | 60 | Future parseData() async { 61 | final json = await rootBundle.loadString(audioData[0]); 62 | Map audioDataMap = { 63 | "json": json, 64 | "totalSamples": totalSamples, 65 | }; 66 | final samplesData = await compute(loadparseJson, audioDataMap); 67 | await audioPlayer.load(audioData[1]); 68 | await audioPlayer.play(audioData[1]); 69 | // maxDuration in milliseconds 70 | await Future.delayed(const Duration(milliseconds: 200)); 71 | 72 | int maxDurationInmilliseconds = await audioPlayer.fixedPlayer!.getDuration(); 73 | 74 | maxDuration = Duration(milliseconds: maxDurationInmilliseconds); 75 | setState(() { 76 | samples = samplesData["samples"]; 77 | }); 78 | } 79 | 80 | @override 81 | void initState() { 82 | // TODO: implement initState 83 | super.initState(); 84 | // Change this value to number of audio samples you want. 85 | // Values between 256 and 1024 are good for showing [RectangleWaveform] and [SquigglyWaveform] 86 | // While the values above them are good for showing [PolygonWaveform] 87 | totalSamples = 1000; 88 | audioData = audioDataList[0]; 89 | audioPlayer = AudioCache( 90 | fixedPlayer: AudioPlayer(), 91 | ); 92 | 93 | samples = []; 94 | maxDuration = const Duration(milliseconds: 1000); 95 | elapsedDuration = const Duration(); 96 | parseData(); 97 | audioPlayer.fixedPlayer!.onPlayerCompletion.listen((_) { 98 | setState(() { 99 | elapsedDuration = maxDuration; 100 | }); 101 | }); 102 | audioPlayer.fixedPlayer!.onAudioPositionChanged 103 | .listen((Duration timeElapsed) { 104 | setState(() { 105 | elapsedDuration = timeElapsed; 106 | }); 107 | }); 108 | } 109 | 110 | @override 111 | Widget build(BuildContext context) { 112 | const sizedBox = SizedBox( 113 | height: 30, 114 | width: 30, 115 | ); 116 | return Scaffold( 117 | backgroundColor: Colors.black, 118 | appBar: AppBar( 119 | title: const Text('Flutter Audio Waveforms'), 120 | ), 121 | body: Column( 122 | mainAxisAlignment: MainAxisAlignment.center, 123 | children: [ 124 | PolygonWaveform( 125 | maxDuration: maxDuration, 126 | elapsedDuration: elapsedDuration, 127 | samples: samples, 128 | height: 300, 129 | width: MediaQuery.of(context).size.width, 130 | ), 131 | sizedBox, 132 | Row( 133 | mainAxisAlignment: MainAxisAlignment.center, 134 | children: [ 135 | ElevatedButton( 136 | onPressed: () { 137 | audioPlayer.fixedPlayer!.pause(); 138 | }, 139 | child: const Icon( 140 | Icons.pause, 141 | ), 142 | ), 143 | sizedBox, 144 | ElevatedButton( 145 | onPressed: () { 146 | audioPlayer.fixedPlayer!.resume(); 147 | }, 148 | child: const Icon(Icons.play_arrow), 149 | ), 150 | sizedBox, 151 | ElevatedButton( 152 | onPressed: () { 153 | setState(() { 154 | audioPlayer.fixedPlayer! 155 | .seek(const Duration(milliseconds: 0)); 156 | }); 157 | }, 158 | child: const Icon(Icons.replay_outlined), 159 | ), 160 | ], 161 | ) 162 | ], 163 | ), 164 | ); 165 | } 166 | } 167 | 168 | ``` -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /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 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.example.example" 47 | minSdkVersion 16 48 | targetSdkVersion 30 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /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 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.2.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/assets/audio.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/audio.mp3 -------------------------------------------------------------------------------- /example/assets/dance_monkey.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/dance_monkey.mp3 -------------------------------------------------------------------------------- /example/assets/images/customizations/cpaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/cpaf.png -------------------------------------------------------------------------------- /example/assets/images/customizations/pa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/pa.png -------------------------------------------------------------------------------- /example/assets/images/customizations/paf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/paf.png -------------------------------------------------------------------------------- /example/assets/images/customizations/paf2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/paf2.png -------------------------------------------------------------------------------- /example/assets/images/customizations/pai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/pai.png -------------------------------------------------------------------------------- /example/assets/images/customizations/pf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/pf.png -------------------------------------------------------------------------------- /example/assets/images/customizations/pg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/pg.png -------------------------------------------------------------------------------- /example/assets/images/customizations/pgf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/pgf.png -------------------------------------------------------------------------------- /example/assets/images/customizations/ra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/ra.png -------------------------------------------------------------------------------- /example/assets/images/customizations/rai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/rai.png -------------------------------------------------------------------------------- /example/assets/images/customizations/rg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/rg.png -------------------------------------------------------------------------------- /example/assets/images/customizations/sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/sa.png -------------------------------------------------------------------------------- /example/assets/images/customizations/sai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/customizations/sai.png -------------------------------------------------------------------------------- /example/assets/images/gifs/cpa_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/gifs/cpa_gif.gif -------------------------------------------------------------------------------- /example/assets/images/gifs/pa_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/gifs/pa_gif.gif -------------------------------------------------------------------------------- /example/assets/images/gifs/ra_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/gifs/ra_gif.gif -------------------------------------------------------------------------------- /example/assets/images/gifs/sa_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/gifs/sa_gif.gif -------------------------------------------------------------------------------- /example/assets/images/inactive/curved_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/inactive/curved_polygon.png -------------------------------------------------------------------------------- /example/assets/images/inactive/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/inactive/polygon.png -------------------------------------------------------------------------------- /example/assets/images/inactive/rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/inactive/rectangle.png -------------------------------------------------------------------------------- /example/assets/images/inactive/squiggly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/inactive/squiggly.png -------------------------------------------------------------------------------- /example/assets/images/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/images/logo/logo.png -------------------------------------------------------------------------------- /example/assets/shape_of_you.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/shape_of_you.mp3 -------------------------------------------------------------------------------- /example/assets/surface_pressure.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/assets/surface_pressure.mp3 -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 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 = 1300; 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 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | DEVELOPMENT_TEAM = 3VD63URX33; 292 | ENABLE_BITCODE = NO; 293 | INFOPLIST_FILE = Runner/Info.plist; 294 | LD_RUNPATH_SEARCH_PATHS = ( 295 | "$(inherited)", 296 | "@executable_path/Frameworks", 297 | ); 298 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 301 | SWIFT_VERSION = 5.0; 302 | VERSIONING_SYSTEM = "apple-generic"; 303 | }; 304 | name = Profile; 305 | }; 306 | 97C147031CF9000F007C117D /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | CLANG_ANALYZER_NONNULL = YES; 311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 312 | CLANG_CXX_LIBRARY = "libc++"; 313 | CLANG_ENABLE_MODULES = YES; 314 | CLANG_ENABLE_OBJC_ARC = YES; 315 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_COMMA = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_EMPTY_BODY = YES; 322 | CLANG_WARN_ENUM_CONVERSION = YES; 323 | CLANG_WARN_INFINITE_RECURSION = YES; 324 | CLANG_WARN_INT_CONVERSION = YES; 325 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 326 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 327 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 328 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 329 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 330 | CLANG_WARN_STRICT_PROTOTYPES = YES; 331 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 332 | CLANG_WARN_UNREACHABLE_CODE = YES; 333 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 334 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 335 | COPY_PHASE_STRIP = NO; 336 | DEBUG_INFORMATION_FORMAT = dwarf; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | ENABLE_TESTABILITY = YES; 339 | GCC_C_LANGUAGE_STANDARD = gnu99; 340 | GCC_DYNAMIC_NO_PIC = NO; 341 | GCC_NO_COMMON_BLOCKS = YES; 342 | GCC_OPTIMIZATION_LEVEL = 0; 343 | GCC_PREPROCESSOR_DEFINITIONS = ( 344 | "DEBUG=1", 345 | "$(inherited)", 346 | ); 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 354 | MTL_ENABLE_DEBUG_INFO = YES; 355 | ONLY_ACTIVE_ARCH = YES; 356 | SDKROOT = iphoneos; 357 | TARGETED_DEVICE_FAMILY = "1,2"; 358 | }; 359 | name = Debug; 360 | }; 361 | 97C147041CF9000F007C117D /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ALWAYS_SEARCH_USER_PATHS = NO; 365 | CLANG_ANALYZER_NONNULL = YES; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_COMMA = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 382 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 383 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 385 | CLANG_WARN_STRICT_PROTOTYPES = YES; 386 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 387 | CLANG_WARN_UNREACHABLE_CODE = YES; 388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 389 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 390 | COPY_PHASE_STRIP = NO; 391 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 392 | ENABLE_NS_ASSERTIONS = NO; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu99; 395 | GCC_NO_COMMON_BLOCKS = YES; 396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 398 | GCC_WARN_UNDECLARED_SELECTOR = YES; 399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 400 | GCC_WARN_UNUSED_FUNCTION = YES; 401 | GCC_WARN_UNUSED_VARIABLE = YES; 402 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 403 | MTL_ENABLE_DEBUG_INFO = NO; 404 | SDKROOT = iphoneos; 405 | SUPPORTED_PLATFORMS = iphoneos; 406 | SWIFT_COMPILATION_MODE = wholemodule; 407 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 408 | TARGETED_DEVICE_FAMILY = "1,2"; 409 | VALIDATE_PRODUCT = YES; 410 | }; 411 | name = Release; 412 | }; 413 | 97C147061CF9000F007C117D /* Debug */ = { 414 | isa = XCBuildConfiguration; 415 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 416 | buildSettings = { 417 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 418 | CLANG_ENABLE_MODULES = YES; 419 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 420 | DEVELOPMENT_TEAM = 3VD63URX33; 421 | ENABLE_BITCODE = NO; 422 | INFOPLIST_FILE = Runner/Info.plist; 423 | LD_RUNPATH_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "@executable_path/Frameworks", 426 | ); 427 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 428 | PRODUCT_NAME = "$(TARGET_NAME)"; 429 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 430 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 431 | SWIFT_VERSION = 5.0; 432 | VERSIONING_SYSTEM = "apple-generic"; 433 | }; 434 | name = Debug; 435 | }; 436 | 97C147071CF9000F007C117D /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 439 | buildSettings = { 440 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 441 | CLANG_ENABLE_MODULES = YES; 442 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 443 | DEVELOPMENT_TEAM = 3VD63URX33; 444 | ENABLE_BITCODE = NO; 445 | INFOPLIST_FILE = Runner/Info.plist; 446 | LD_RUNPATH_SEARCH_PATHS = ( 447 | "$(inherited)", 448 | "@executable_path/Frameworks", 449 | ); 450 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 451 | PRODUCT_NAME = "$(TARGET_NAME)"; 452 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 453 | SWIFT_VERSION = 5.0; 454 | VERSIONING_SYSTEM = "apple-generic"; 455 | }; 456 | name = Release; 457 | }; 458 | /* End XCBuildConfiguration section */ 459 | 460 | /* Begin XCConfigurationList section */ 461 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 462 | isa = XCConfigurationList; 463 | buildConfigurations = ( 464 | 97C147031CF9000F007C117D /* Debug */, 465 | 97C147041CF9000F007C117D /* Release */, 466 | 249021D3217E4FDB00AE95B9 /* Profile */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | 97C147061CF9000F007C117D /* Debug */, 475 | 97C147071CF9000F007C117D /* Release */, 476 | 249021D4217E4FDB00AE95B9 /* Profile */, 477 | ); 478 | defaultConfigurationIsVisible = 0; 479 | defaultConfigurationName = Release; 480 | }; 481 | /* End XCConfigurationList section */ 482 | }; 483 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 484 | } 485 | -------------------------------------------------------------------------------- /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 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /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 | @UIApplicationMain 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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/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 | CFBundleDisplayName 8 | Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/load_audio_data.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math' as math; 3 | 4 | Map loadparseJson(Map audioDataMap) { 5 | final data = jsonDecode(audioDataMap["json"]); 6 | 7 | final List rawSamples = List.castFrom(data['data']); 8 | List filteredData = []; 9 | // Change this value to number of audio samples you want. 10 | // Values between 256 and 1024 are good for showing [RectangleWaveform] and [SquigglyWaveform] 11 | // While the values above them are good for showing [PolygonWaveform] 12 | final int totalSamples = audioDataMap["totalSamples"]; 13 | final double blockSize = rawSamples.length / totalSamples; 14 | 15 | for (int i = 0; i < totalSamples; i++) { 16 | final double blockStart = 17 | blockSize * i; // the location of the first sample in the block 18 | int sum = 0; 19 | for (int j = 0; j < blockSize; j++) { 20 | sum = sum + 21 | rawSamples[(blockStart + j).toInt()] 22 | .toInt(); // find the sum of all the samples in the block 23 | 24 | } 25 | filteredData.add((sum / blockSize) 26 | .round() // take the average of the block and add it to the filtered data 27 | .toInt()); // divide the sum by the block size to get the average 28 | } 29 | final maxNum = filteredData.reduce((a, b) => math.max(a.abs(), b.abs())); 30 | 31 | final double multiplier = math.pow(maxNum, -1).toDouble(); 32 | 33 | final samples = filteredData.map((e) => (e * multiplier)).toList(); 34 | 35 | return { 36 | "samples": samples, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:audioplayers/audioplayers.dart'; 2 | import 'package:example/load_audio_data.dart'; 3 | import 'package:example/waveforms_dashboard.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter_audio_waveforms/flutter_audio_waveforms.dart'; 8 | 9 | void main() { 10 | runApp(const MyApp()); 11 | } 12 | 13 | class MyApp extends StatelessWidget { 14 | const MyApp({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return const MaterialApp( 19 | title: 'Flutter Audio Waveforms', 20 | home: WaveformsDashboard(), 21 | ); 22 | } 23 | } 24 | 25 | class Home extends StatefulWidget { 26 | const Home({Key? key}) : super(key: key); 27 | 28 | @override 29 | State createState() => _HomeState(); 30 | } 31 | 32 | class _HomeState extends State { 33 | late Duration maxDuration; 34 | late Duration elapsedDuration; 35 | late AudioCache audioPlayer; 36 | late List samples; 37 | late int totalSamples; 38 | 39 | late List audioData; 40 | 41 | List> audioDataList = [ 42 | [ 43 | 'assets/dm.json', 44 | 'dance_monkey.mp3', 45 | ], 46 | [ 47 | 'assets/soy.json', 48 | 'shape_of_you.mp3', 49 | ], 50 | [ 51 | 'assets/sp.json', 52 | 'surface_pressure.mp3', 53 | ], 54 | ]; 55 | 56 | Future parseData() async { 57 | final json = await rootBundle.loadString(audioData[0]); 58 | Map audioDataMap = { 59 | "json": json, 60 | "totalSamples": totalSamples, 61 | }; 62 | final samplesData = await compute(loadparseJson, audioDataMap); 63 | await audioPlayer.load(audioData[1]); 64 | await audioPlayer.play(audioData[1]); 65 | // maxDuration in milliseconds 66 | await Future.delayed(const Duration(milliseconds: 200)); 67 | 68 | int maxDurationInmilliseconds = 69 | await audioPlayer.fixedPlayer!.getDuration(); 70 | 71 | maxDuration = Duration(milliseconds: maxDurationInmilliseconds); 72 | setState(() { 73 | samples = samplesData["samples"]; 74 | }); 75 | } 76 | 77 | @override 78 | void initState() { 79 | // TODO: implement initState 80 | super.initState(); 81 | // Change this value to number of audio samples you want. 82 | // Values between 256 and 1024 are good for showing [RectangleWaveform] and [SquigglyWaveform] 83 | // While the values above them are good for showing [PolygonWaveform] 84 | totalSamples = 1000; 85 | audioData = audioDataList[0]; 86 | audioPlayer = AudioCache( 87 | fixedPlayer: AudioPlayer(), 88 | ); 89 | 90 | samples = []; 91 | maxDuration = const Duration(milliseconds: 1000); 92 | elapsedDuration = const Duration(); 93 | parseData(); 94 | audioPlayer.fixedPlayer!.onPlayerCompletion.listen((_) { 95 | setState(() { 96 | elapsedDuration = maxDuration; 97 | }); 98 | }); 99 | audioPlayer.fixedPlayer!.onAudioPositionChanged 100 | .listen((Duration timeElapsed) { 101 | setState(() { 102 | elapsedDuration = timeElapsed; 103 | }); 104 | }); 105 | } 106 | 107 | @override 108 | Widget build(BuildContext context) { 109 | const sizedBox = SizedBox( 110 | height: 30, 111 | width: 30, 112 | ); 113 | return Scaffold( 114 | backgroundColor: Colors.white, 115 | appBar: AppBar( 116 | title: const Text('Flutter Audio Waveforms'), 117 | ), 118 | body: Column( 119 | mainAxisAlignment: MainAxisAlignment.center, 120 | children: [ 121 | PolygonWaveform( 122 | maxDuration: maxDuration, 123 | elapsedDuration: elapsedDuration, 124 | samples: samples, 125 | height: 300, 126 | width: MediaQuery.of(context).size.width, 127 | ), 128 | sizedBox, 129 | Row( 130 | mainAxisAlignment: MainAxisAlignment.center, 131 | children: [ 132 | ElevatedButton( 133 | onPressed: () { 134 | audioPlayer.fixedPlayer!.pause(); 135 | }, 136 | child: const Icon( 137 | Icons.pause, 138 | ), 139 | ), 140 | sizedBox, 141 | ElevatedButton( 142 | onPressed: () { 143 | audioPlayer.fixedPlayer!.resume(); 144 | }, 145 | child: const Icon(Icons.play_arrow), 146 | ), 147 | sizedBox, 148 | ElevatedButton( 149 | onPressed: () { 150 | setState(() { 151 | audioPlayer.fixedPlayer! 152 | .seek(const Duration(milliseconds: 0)); 153 | }); 154 | }, 155 | child: const Icon(Icons.replay_outlined), 156 | ), 157 | ], 158 | ) 159 | ], 160 | ), 161 | ); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import audioplayers 9 | import path_provider_macos 10 | 11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 12 | AudioplayersPlugin.register(with: registry.registrar(forPlugin: "AudioplayersPlugin")) 13 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 14 | } 15 | -------------------------------------------------------------------------------- /example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /example/macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - audioplayers (0.0.1): 3 | - FlutterMacOS 4 | - FlutterMacOS (1.0.0) 5 | - path_provider_macos (0.0.1): 6 | - FlutterMacOS 7 | 8 | DEPENDENCIES: 9 | - audioplayers (from `Flutter/ephemeral/.symlinks/plugins/audioplayers/macos`) 10 | - FlutterMacOS (from `Flutter/ephemeral`) 11 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) 12 | 13 | EXTERNAL SOURCES: 14 | audioplayers: 15 | :path: Flutter/ephemeral/.symlinks/plugins/audioplayers/macos 16 | FlutterMacOS: 17 | :path: Flutter/ephemeral 18 | path_provider_macos: 19 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos 20 | 21 | SPEC CHECKSUMS: 22 | audioplayers: 8b48e22684b6e0d9df143b2d1bbd61dca9dab6b4 23 | FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 24 | path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 25 | 26 | PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 27 | 28 | COCOAPODS: 1.11.3 29 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.10.0" 12 | audioplayers: 13 | dependency: "direct main" 14 | description: 15 | name: audioplayers 16 | sha256: a565e7e3e8a21a823b8cd7fed0bde1eb3796a96b373374be557adecfb511fa6b 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "0.20.1" 20 | boolean_selector: 21 | dependency: transitive 22 | description: 23 | name: boolean_selector 24 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.1.1" 28 | characters: 29 | dependency: transitive 30 | description: 31 | name: characters 32 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.2.1" 36 | clock: 37 | dependency: transitive 38 | description: 39 | name: clock 40 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.1.1" 44 | collection: 45 | dependency: transitive 46 | description: 47 | name: collection 48 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.17.0" 52 | crypto: 53 | dependency: transitive 54 | description: 55 | name: crypto 56 | sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "3.0.2" 60 | cupertino_icons: 61 | dependency: "direct main" 62 | description: 63 | name: cupertino_icons 64 | sha256: "1989d917fbe8e6b39806207df5a3fdd3d816cbd090fac2ce26fb45e9a71476e5" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.0.4" 68 | fake_async: 69 | dependency: transitive 70 | description: 71 | name: fake_async 72 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.3.1" 76 | ffi: 77 | dependency: transitive 78 | description: 79 | name: ffi 80 | sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "1.2.1" 84 | file: 85 | dependency: "direct dev" 86 | description: 87 | name: file 88 | sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "6.1.4" 92 | flutter: 93 | dependency: "direct main" 94 | description: flutter 95 | source: sdk 96 | version: "0.0.0" 97 | flutter_audio_waveforms: 98 | dependency: "direct main" 99 | description: 100 | path: "/Users/rutviktak/flutter_projects/flutter_plugins/flutter_audio_waveforms/" 101 | relative: false 102 | source: path 103 | version: "1.2.1+8" 104 | flutter_lints: 105 | dependency: "direct dev" 106 | description: 107 | name: flutter_lints 108 | sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 109 | url: "https://pub.dev" 110 | source: hosted 111 | version: "1.0.4" 112 | flutter_test: 113 | dependency: "direct dev" 114 | description: flutter 115 | source: sdk 116 | version: "0.0.0" 117 | flutter_web_plugins: 118 | dependency: transitive 119 | description: flutter 120 | source: sdk 121 | version: "0.0.0" 122 | http: 123 | dependency: transitive 124 | description: 125 | name: http 126 | sha256: "2ed163531e071c2c6b7c659635112f24cb64ecbebf6af46b550d536c0b1aa112" 127 | url: "https://pub.dev" 128 | source: hosted 129 | version: "0.13.4" 130 | http_parser: 131 | dependency: transitive 132 | description: 133 | name: http_parser 134 | sha256: db3060f22889f3d9d55f6a217565486737037eec3609f7f3eca4d0c67ee0d8a0 135 | url: "https://pub.dev" 136 | source: hosted 137 | version: "4.0.1" 138 | js: 139 | dependency: transitive 140 | description: 141 | name: js 142 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "0.6.5" 146 | lints: 147 | dependency: transitive 148 | description: 149 | name: lints 150 | sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "1.0.1" 154 | matcher: 155 | dependency: transitive 156 | description: 157 | name: matcher 158 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "0.12.13" 162 | material_color_utilities: 163 | dependency: transitive 164 | description: 165 | name: material_color_utilities 166 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "0.2.0" 170 | meta: 171 | dependency: transitive 172 | description: 173 | name: meta 174 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "1.8.0" 178 | path: 179 | dependency: transitive 180 | description: 181 | name: path 182 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "1.8.2" 186 | path_provider: 187 | dependency: transitive 188 | description: 189 | name: path_provider 190 | sha256: "3f6e0d697dc557ed6589107c8c13eda5ad488285917788379bbf392e3e30ea37" 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "2.0.10" 194 | path_provider_android: 195 | dependency: transitive 196 | description: 197 | name: path_provider_android 198 | sha256: "8b759fb6c74955931e87f550cc9e890b0cccb7ef8e710943973efeaa9695c54d" 199 | url: "https://pub.dev" 200 | source: hosted 201 | version: "2.0.12" 202 | path_provider_ios: 203 | dependency: transitive 204 | description: 205 | name: path_provider_ios 206 | sha256: "060ca9249d85bda6ee4ea2ecb3f4698a32f73183e0dee4f469bee8e146eadc1f" 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "2.0.9" 210 | path_provider_linux: 211 | dependency: transitive 212 | description: 213 | name: path_provider_linux 214 | sha256: "367b9311fe9ce1421215bcc37dce9bde57b6640c7b790cee1974c2b0a691e074" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "2.1.6" 218 | path_provider_macos: 219 | dependency: transitive 220 | description: 221 | name: path_provider_macos 222 | sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "2.0.6" 226 | path_provider_platform_interface: 227 | dependency: transitive 228 | description: 229 | name: path_provider_platform_interface 230 | sha256: "27dc7a224fcd07444cb5e0e60423ccacea3e13cf00fc5282ac2c918132da931d" 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "2.0.4" 234 | path_provider_windows: 235 | dependency: transitive 236 | description: 237 | name: path_provider_windows 238 | sha256: "62dbb1bc45f1e7ba1094c9dd8ea46bdcffc254db7354b4988cb9326c9d2efcdd" 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "2.0.6" 242 | platform: 243 | dependency: transitive 244 | description: 245 | name: platform 246 | sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" 247 | url: "https://pub.dev" 248 | source: hosted 249 | version: "3.1.0" 250 | plugin_platform_interface: 251 | dependency: transitive 252 | description: 253 | name: plugin_platform_interface 254 | sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" 255 | url: "https://pub.dev" 256 | source: hosted 257 | version: "2.1.2" 258 | process: 259 | dependency: transitive 260 | description: 261 | name: process 262 | sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" 263 | url: "https://pub.dev" 264 | source: hosted 265 | version: "4.2.4" 266 | sky_engine: 267 | dependency: transitive 268 | description: flutter 269 | source: sdk 270 | version: "0.0.99" 271 | source_span: 272 | dependency: transitive 273 | description: 274 | name: source_span 275 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 276 | url: "https://pub.dev" 277 | source: hosted 278 | version: "1.9.1" 279 | stack_trace: 280 | dependency: transitive 281 | description: 282 | name: stack_trace 283 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 284 | url: "https://pub.dev" 285 | source: hosted 286 | version: "1.11.0" 287 | stream_channel: 288 | dependency: transitive 289 | description: 290 | name: stream_channel 291 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 292 | url: "https://pub.dev" 293 | source: hosted 294 | version: "2.1.1" 295 | string_scanner: 296 | dependency: transitive 297 | description: 298 | name: string_scanner 299 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 300 | url: "https://pub.dev" 301 | source: hosted 302 | version: "1.2.0" 303 | term_glyph: 304 | dependency: transitive 305 | description: 306 | name: term_glyph 307 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 308 | url: "https://pub.dev" 309 | source: hosted 310 | version: "1.2.1" 311 | test_api: 312 | dependency: transitive 313 | description: 314 | name: test_api 315 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 316 | url: "https://pub.dev" 317 | source: hosted 318 | version: "0.4.16" 319 | typed_data: 320 | dependency: transitive 321 | description: 322 | name: typed_data 323 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 324 | url: "https://pub.dev" 325 | source: hosted 326 | version: "1.3.0" 327 | uuid: 328 | dependency: transitive 329 | description: 330 | name: uuid 331 | sha256: "2469694ad079893e3b434a627970c33f2fa5adc46dfe03c9617546969a9a8afc" 332 | url: "https://pub.dev" 333 | source: hosted 334 | version: "3.0.6" 335 | vector_math: 336 | dependency: transitive 337 | description: 338 | name: vector_math 339 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 340 | url: "https://pub.dev" 341 | source: hosted 342 | version: "2.1.4" 343 | win32: 344 | dependency: transitive 345 | description: 346 | name: win32 347 | sha256: "4658d864d83cdaedcbf3e65ad93b71880a3e8c9ee1ff15d855f88fb2da66cb8a" 348 | url: "https://pub.dev" 349 | source: hosted 350 | version: "2.5.2" 351 | xdg_directories: 352 | dependency: transitive 353 | description: 354 | name: xdg_directories 355 | sha256: "060b6e1c891d956f72b5ac9463466c37cce3fa962a921532fc001e86fe93438e" 356 | url: "https://pub.dev" 357 | source: hosted 358 | version: "0.2.0+1" 359 | sdks: 360 | dart: ">=2.18.0 <3.0.0" 361 | flutter: ">=2.8.0" 362 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: "none" # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.17.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | 33 | flutter_audio_waveforms: 34 | path: /Users/rutviktak/flutter_projects/flutter_plugins/flutter_audio_waveforms/ # 1.0.0+1 35 | # The following adds the Cupertino Icons font to your application. 36 | # Use with the CupertinoIcons class for iOS style icons. 37 | cupertino_icons: ^1.0.2 38 | audioplayers: ^0.20.1 39 | 40 | dev_dependencies: 41 | flutter_test: 42 | sdk: flutter 43 | 44 | # The "flutter_lints" package below contains a set of recommended lints to 45 | # encourage good coding practices. The lint set provided by the package is 46 | # activated in the `analysis_options.yaml` file located at the root of your 47 | # package. See that file for information about deactivating specific lint 48 | # rules and activating additional ones. 49 | flutter_lints: ^1.0.0 50 | file: ^6.1.4 51 | 52 | # For information on the generic Dart part of this file, see the 53 | # following page: https://dart.dev/tools/pub/pubspec 54 | 55 | # The following section is specific to Flutter. 56 | flutter: 57 | # The following line ensures that the Material Icons font is 58 | # included with your application, so that you can use the icons in 59 | # the material Icons class. 60 | uses-material-design: true 61 | 62 | # To add assets to your application, add an assets section, like this: 63 | assets: 64 | - assets/ 65 | 66 | # An image asset can refer to one or more resolution-specific "variants", see 67 | # https://flutter.dev/assets-and-images/#resolution-aware. 68 | 69 | # For details regarding adding assets from package dependencies, see 70 | # https://flutter.dev/assets-and-images/#from-packages 71 | 72 | # To add custom fonts to your application, add a fonts section here, 73 | # in this "flutter" section. Each entry in this list should have a 74 | # "family" key with the font family name, and a "fonts" key with a 75 | # list giving the asset and other descriptors for the font. For 76 | # example: 77 | # fonts: 78 | # - family: Schyler 79 | # fonts: 80 | # - asset: fonts/Schyler-Regular.ttf 81 | # - asset: fonts/Schyler-Italic.ttf 82 | # style: italic 83 | # - family: Trajan Pro 84 | # fonts: 85 | # - asset: fonts/TrajanPro.ttf 86 | # - asset: fonts/TrajanPro_Bold.ttf 87 | # weight: 700 88 | # 89 | # For details regarding fonts from package dependencies, 90 | # see https://flutter.dev/custom-fonts/#from-packages 91 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutvik110/flutter_audio_waveforms/8e80eb85227e4f9f18461d01b7031e5784a8c11a/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | example 30 | 31 | 32 | 33 | 36 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/flutter_audio_waveforms.dart: -------------------------------------------------------------------------------- 1 | export 'package:flutter_audio_waveforms/src/core/audio_waveform.dart'; 2 | export 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 3 | export 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 4 | export 'package:flutter_audio_waveforms/src/waveforms/curved_polygon_waveform/curved_polygon_waveform.dart'; 5 | export 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/polygon_waveform.dart'; 6 | export 'package:flutter_audio_waveforms/src/waveforms/rectangle_waveform/rectangle_waveform.dart'; 7 | export 'package:flutter_audio_waveforms/src/waveforms/squiggly_waveform/squiggly_waveform.dart'; 8 | -------------------------------------------------------------------------------- /lib/src/const/colors.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: public_member_api_docs 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | const Color opaqueBlack = Color(0x00000000); 6 | -------------------------------------------------------------------------------- /lib/src/core/audio_waveform.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 5 | import 'package:flutter_audio_waveforms/src/util/check_samples_equality.dart'; 6 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 7 | 8 | /// [AudioWaveform] is a custom StatefulWidget that other Waveform classes 9 | /// extend to. 10 | /// 11 | /// This class handles the common functionality, properties and provides the 12 | /// most common waveform details to the subclasses. This details then can be 13 | /// used by the [WaveformPainter] to paint the waveform. 14 | /// 15 | /// Anything that can be shared and used across all waveforms should 16 | /// be handled by this class. 17 | /// 18 | 19 | bool debugMaxandElapsedDuration( 20 | Duration? maxDuration, 21 | Duration? elapsedDuration, 22 | ) { 23 | return maxDuration != null || elapsedDuration != null 24 | ? elapsedDuration != null && maxDuration != null 25 | : true; 26 | } 27 | 28 | abstract class AudioWaveform extends StatefulWidget { 29 | /// Constructor for [AudioWaveform] 30 | AudioWaveform({ 31 | Key? key, 32 | required this.samples, 33 | required this.height, 34 | required this.width, 35 | this.maxDuration, 36 | this.elapsedDuration, 37 | required this.showActiveWaveform, 38 | this.absolute = false, 39 | this.invert = false, 40 | }) : assert( 41 | debugMaxandElapsedDuration( 42 | maxDuration, 43 | elapsedDuration, 44 | ), 45 | 'Both maxDuration and elapsedDuration must be provided.', 46 | ), 47 | assert( 48 | maxDuration == null ? true : maxDuration.inMilliseconds > 0, 49 | 'maxDuration must be greater than 0', 50 | ), 51 | assert( 52 | elapsedDuration == null ? true : elapsedDuration.inMilliseconds >= 0, 53 | 'maxDuration must be greater than 0', 54 | ), 55 | assert( 56 | elapsedDuration == null || maxDuration == null 57 | ? true 58 | : elapsedDuration.inMilliseconds <= maxDuration.inMilliseconds, 59 | 'elapsedDuration must be less than or equal to maxDuration', 60 | ), 61 | waveformAlignment = absolute 62 | ? invert 63 | ? WaveformAlignment.top 64 | : WaveformAlignment.bottom 65 | : WaveformAlignment.center, 66 | super(key: key); 67 | 68 | /// Audio samples raw input. 69 | /// This raw samples are processed before being used to paint the waveform. 70 | final List samples; 71 | 72 | /// Height of the canvas on which the waveform will be drawn. 73 | final double height; 74 | 75 | /// Width of the canvas on which the waveform will be drawn. 76 | final double width; 77 | 78 | /// Maximum duration of the audio. 79 | final Duration? maxDuration; 80 | 81 | /// Elapsed duration of the audio. 82 | final Duration? elapsedDuration; 83 | 84 | /// Makes the waveform absolute. 85 | /// Draws the waveform along the positive y-axis. 86 | /// Samples are processed such that we end up with positive sample values. 87 | final bool absolute; 88 | 89 | /// Inverts/Flips the waveform along x-axis. 90 | /// Samples are processed such that we end up with samples having opposite 91 | /// sign. 92 | final bool invert; 93 | 94 | /// Whether to show the active waveform or not. 95 | final bool showActiveWaveform; 96 | 97 | /// Alignment of the waveform in the canvas. 98 | @protected 99 | final WaveformAlignment waveformAlignment; 100 | 101 | @override 102 | AudioWaveformState createState(); 103 | } 104 | 105 | /// State of the [AudioWaveform] 106 | abstract class AudioWaveformState extends State { 107 | /// Samples after processing. 108 | /// This are used to paint the waveform. 109 | late List _processedSamples; 110 | 111 | ///Getter for processed samples. 112 | List get processedSamples => _processedSamples; 113 | 114 | late double _sampleWidth; 115 | 116 | ///Getter for sample width. 117 | double get sampleWidth => _sampleWidth; 118 | 119 | ///Method for subsclass to update the processed samples 120 | @protected 121 | // ignore: use_setters_to_change_properties 122 | void updateProcessedSamples(List updatedSamples) { 123 | _processedSamples = updatedSamples; 124 | } 125 | 126 | /// Active index of the sample in the raw samples. 127 | /// 128 | /// Used to obtain the [activeSamples] for the audio as the 129 | /// audio progresses. 130 | /// This is calculated based on the [elapsedDuration], [maxDuration] and the 131 | /// raw samples. 132 | /// 133 | /// final elapsedTimeRatio = elapsedDuration.inMilliseconds / maxDuration.inMilliseconds; 134 | /// _activeIndex = (widget.samples.length * elapsedTimeRatio).round(); 135 | late int _activeIndex; 136 | 137 | /// Active samples that are used to draw the ActiveWaveform. 138 | /// This are calculated using [_activeIndex] and are subList of the 139 | /// [_processedSamples] at any given time. 140 | late List _activeSamples; 141 | 142 | ///Getter for active samples. 143 | List get activeSamples => _activeSamples; 144 | 145 | ///Getter for maxDuration 146 | Duration? get maxDuration => widget.maxDuration; 147 | 148 | ///getter for elapsedDuration 149 | Duration? get elapsedDuration => widget.elapsedDuration; 150 | 151 | ///Whether to show active waveform or not 152 | bool get showActiveWaveform => widget.showActiveWaveform; 153 | 154 | ///Whether to invert/flip waveform or not 155 | bool get invert => widget.absolute ? !widget.invert : widget.invert; 156 | 157 | ///Whether to show absolute waveform or not 158 | bool get absolute => widget.absolute; 159 | 160 | ///Getter for waveformAlignment. 161 | WaveformAlignment get waveformAlignment => widget.waveformAlignment; 162 | 163 | /// Raw samples are processed before used following some 164 | /// techniques. This is to have consistent samples that can be used to draw 165 | /// the waveform properly. 166 | @protected 167 | void processSamples() { 168 | final rawSamples = widget.samples; 169 | 170 | _processedSamples = rawSamples 171 | .map((e) => absolute ? e.abs() * widget.height : e * widget.height) 172 | .toList(); 173 | 174 | final maxNum = 175 | _processedSamples.reduce((a, b) => math.max(a.abs(), b.abs())); 176 | 177 | if (maxNum > 0) { 178 | final multiplier = math.pow(maxNum, -1).toDouble(); 179 | final finalHeight = absolute ? widget.height : widget.height / 2; 180 | final finalMultiplier = multiplier * finalHeight; 181 | 182 | _processedSamples = _processedSamples 183 | .map( 184 | (e) => invert ? -e * finalMultiplier : e * finalMultiplier, 185 | ) 186 | .toList(); 187 | } 188 | } 189 | 190 | /// Calculates the width that each sample would take. 191 | /// This is later used in the Painters to calculate the Offset along x-axis 192 | /// from the start for any sample while painting. 193 | void _calculateSampleWidth() { 194 | _sampleWidth = widget.width / (_processedSamples.length); 195 | } 196 | 197 | /// Updates the [_activeIndex] whenever the duration changes. 198 | @protected 199 | void _updateActiveIndex() { 200 | // if (activeIndex != null) { 201 | // _activeIndex = activeIndex; 202 | 203 | // return; 204 | // } 205 | if (maxDuration != null && elapsedDuration != null) { 206 | final elapsedTimeRatio = 207 | elapsedDuration!.inMilliseconds / maxDuration!.inMilliseconds; 208 | 209 | _activeIndex = (widget.samples.length * elapsedTimeRatio).round(); 210 | } 211 | } 212 | 213 | /// Updates [_activeSamples] based on the [_activeIndex]. 214 | @protected 215 | void _updateActiveSamples() { 216 | _activeSamples = _processedSamples.sublist(0, _activeIndex); 217 | } 218 | 219 | /// Gets the ratio of elapsedDuration to maxDuration. 220 | /// Used by waveforms that show active track with help of stops in gradient while painting. 221 | /// eg. CurvedPolygonWaveform, SquigglyWaveform 222 | 223 | double get activeRatio => _calculateActiveRatio(); 224 | 225 | double _calculateActiveRatio() { 226 | if (maxDuration != null && elapsedDuration != null) { 227 | return showActiveWaveform 228 | ? elapsedDuration!.inMilliseconds / maxDuration!.inMilliseconds 229 | : 0.0; 230 | } 231 | 232 | return 0; 233 | } 234 | 235 | @override 236 | void initState() { 237 | super.initState(); 238 | 239 | _processedSamples = widget.samples; 240 | _activeIndex = 0; 241 | _activeSamples = []; 242 | _sampleWidth = 0; 243 | 244 | if (_processedSamples.isNotEmpty) { 245 | processSamples(); 246 | _calculateSampleWidth(); 247 | } 248 | } 249 | 250 | @override 251 | void didUpdateWidget(covariant T oldWidget) { 252 | super.didUpdateWidget(oldWidget); 253 | if (!checkforSamplesEquality(widget.samples, oldWidget.samples) && 254 | widget.samples.isNotEmpty) { 255 | processSamples(); 256 | _calculateSampleWidth(); 257 | _updateActiveIndex(); 258 | _updateActiveSamples(); 259 | } 260 | if (widget.showActiveWaveform) { 261 | if (widget.elapsedDuration != oldWidget.elapsedDuration) { 262 | _updateActiveIndex(); 263 | _updateActiveSamples(); 264 | } 265 | } 266 | if (widget.height != oldWidget.height || widget.width != oldWidget.width) { 267 | processSamples(); 268 | _calculateSampleWidth(); 269 | _updateActiveSamples(); 270 | } 271 | if (widget.absolute != oldWidget.absolute) { 272 | processSamples(); 273 | _updateActiveSamples(); 274 | } 275 | if (widget.invert != oldWidget.invert) { 276 | processSamples(); 277 | _updateActiveSamples(); 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /lib/src/core/waveform_painters_ab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/src/const/colors.dart'; 3 | import 'package:flutter_audio_waveforms/src/util/check_samples_equality.dart'; 4 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 5 | 6 | /// A Painter class that all the types of Waveform Painters extend to. 7 | /// The memebers of this class are essential to paint any type of waveform. 8 | abstract class WaveformPainter extends CustomPainter { 9 | /// Constructor for the WaveformPainter. 10 | WaveformPainter({ 11 | required this.samples, 12 | required this.color, 13 | required this.gradient, 14 | required this.waveformAlignment, 15 | required this.sampleWidth, 16 | required this.style, 17 | }); 18 | 19 | /// Samples that are used to paint the waveform. 20 | final List samples; 21 | 22 | /// Color of the waveform. 23 | final Color color; 24 | 25 | /// Gradient of the waveform. 26 | final Gradient? gradient; 27 | 28 | /// Alignment of the waveform. 29 | final WaveformAlignment waveformAlignment; 30 | 31 | /// Width of each sample. 32 | final double sampleWidth; 33 | 34 | /// The style of the waveform. 35 | final PaintingStyle style; 36 | } 37 | 38 | /// A Painter class that all other ActiveWaveform Painters extend to. 39 | /// The members declared in this class are essential to draw ActiveWaveforms. 40 | /// This types of waveform painters draws the active part of the waveform of 41 | /// the audio being played. 42 | 43 | abstract class ActiveWaveformPainter extends WaveformPainter { 44 | // ignore: public_member_api_docs 45 | ActiveWaveformPainter({ 46 | required Color color, 47 | required Gradient? gradient, 48 | // Do we really need to pass the samples here?. I believe 49 | // [ActiveWaveformPainter] should only care about the [activeSamples] value. 50 | // If [samples] changes, then [activeSamples] should change as well so it's 51 | // redundant to check for [samples] equality and to pass them here. 52 | // Only if ActiveWaveformPainter depends on samples in future for any 53 | // reasons, then we should pass them here. 54 | // required List samples, 55 | required double sampleWidth, 56 | required this.activeSamples, 57 | required WaveformAlignment waveformAlignment, 58 | PaintingStyle style = PaintingStyle.stroke, 59 | this.borderWidth = 0.0, 60 | this.borderColor = opaqueBlack, 61 | }) : super( 62 | samples: [], //samples, 63 | color: color, 64 | gradient: gradient, 65 | waveformAlignment: waveformAlignment, 66 | sampleWidth: sampleWidth, 67 | style: style, 68 | ); 69 | 70 | ///The active samples used to paint the waveform. 71 | final List activeSamples; 72 | 73 | /// Stroke/Border Width 74 | final double borderWidth; 75 | 76 | /// Stroke/Border Width 77 | final Color borderColor; 78 | 79 | /// Get shoudlRepaintValue 80 | bool getShouldRepaintValue(covariant ActiveWaveformPainter oldDelegate) { 81 | return !checkforSamplesEquality(activeSamples, oldDelegate.activeSamples) || 82 | color != oldDelegate.color || 83 | gradient != oldDelegate.gradient || 84 | waveformAlignment != oldDelegate.waveformAlignment || 85 | sampleWidth != oldDelegate.sampleWidth || 86 | style != oldDelegate.style || 87 | borderWidth != oldDelegate.borderWidth || 88 | borderColor != oldDelegate.borderColor; 89 | } 90 | 91 | /// Whether the waveform should be rePainted or not. 92 | @override 93 | bool shouldRepaint(covariant ActiveWaveformPainter oldDelegate) { 94 | return getShouldRepaintValue(oldDelegate); 95 | } 96 | } 97 | 98 | /// A Painter class that all other InActiveWaveform Painters extend to. 99 | /// This types of waveform painters draws the whole waveform of the audio 100 | /// being played. 101 | abstract class InActiveWaveformPainter extends WaveformPainter { 102 | // ignore: public_member_api_docs 103 | InActiveWaveformPainter({ 104 | required Color color, 105 | required Gradient? gradient, 106 | required List samples, 107 | required WaveformAlignment waveformAlignment, 108 | required double sampleWidth, 109 | PaintingStyle style = PaintingStyle.stroke, 110 | this.borderWidth = 0.0, 111 | this.borderColor = opaqueBlack, 112 | }) : super( 113 | samples: samples, 114 | color: color, 115 | gradient: gradient, 116 | waveformAlignment: waveformAlignment, 117 | sampleWidth: sampleWidth, 118 | style: style, 119 | ); 120 | 121 | /// Stroke/Border Width 122 | final double borderWidth; 123 | 124 | /// Stroke/Border Width 125 | final Color borderColor; 126 | 127 | /// Get shoudlRepaintValue 128 | bool getShouldRepaintValue(covariant InActiveWaveformPainter oldDelegate) { 129 | return !checkforSamplesEquality(samples, oldDelegate.samples) || 130 | color != oldDelegate.color || 131 | gradient != oldDelegate.gradient || 132 | waveformAlignment != oldDelegate.waveformAlignment || 133 | sampleWidth != oldDelegate.sampleWidth || 134 | style != oldDelegate.style || 135 | borderWidth != oldDelegate.borderWidth || 136 | borderColor != oldDelegate.borderColor; 137 | } 138 | 139 | /// Whether the waveform should be rePainted or not. 140 | @override 141 | bool shouldRepaint(covariant InActiveWaveformPainter oldDelegate) { 142 | return getShouldRepaintValue(oldDelegate); 143 | } 144 | } 145 | 146 | /// A Painter class that all other ActiveInActiveWaveform Painters extend to. 147 | /// The members of this class are essential to draw any waveform that manages 148 | /// the painting of both active and inActive waveform within itself. 149 | abstract class ActiveInActiveWaveformPainter extends WaveformPainter { 150 | // ignore: public_member_api_docs 151 | ActiveInActiveWaveformPainter({ 152 | required this.activeColor, 153 | required List samples, 154 | required double sampleWidth, 155 | required this.inactiveColor, 156 | required this.activeRatio, 157 | required WaveformAlignment waveformAlignment, 158 | PaintingStyle style = PaintingStyle.stroke, 159 | required this.strokeWidth, 160 | }) : super( 161 | samples: samples, 162 | color: inactiveColor, 163 | gradient: null, 164 | waveformAlignment: waveformAlignment, 165 | sampleWidth: sampleWidth, 166 | style: style, 167 | ); 168 | 169 | ///The color of the active waveform. 170 | final Color inactiveColor; 171 | 172 | ///The color of the inactive waveform. 173 | final Color activeColor; 174 | 175 | ///The ratio of the elapsedDuration to the maxDuration. 176 | final double activeRatio; 177 | 178 | /// Stroke Width 179 | final double strokeWidth; 180 | 181 | /// Get shoudlRepaintValue 182 | bool getShouldRepaintValue( 183 | covariant ActiveInActiveWaveformPainter oldDelegate, 184 | ) { 185 | return activeRatio != oldDelegate.activeRatio || 186 | activeColor != oldDelegate.activeColor || 187 | inactiveColor != oldDelegate.inactiveColor || 188 | !checkforSamplesEquality(samples, oldDelegate.samples) || 189 | color != oldDelegate.color || 190 | gradient != oldDelegate.gradient || 191 | waveformAlignment != oldDelegate.waveformAlignment || 192 | sampleWidth != oldDelegate.sampleWidth || 193 | strokeWidth != oldDelegate.strokeWidth || 194 | style != oldDelegate.style; 195 | } 196 | 197 | /// Whether the waveform should be rePainted or not. 198 | @override 199 | bool shouldRepaint(covariant ActiveInActiveWaveformPainter oldDelegate) { 200 | return getShouldRepaintValue(oldDelegate); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /lib/src/util/check_samples_equality.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | 3 | /// Checks for new and old samples equality to decide whether to process samples 4 | /// again or not when samples are updated. 5 | bool Function(List list1, List list2) checkforSamplesEquality = 6 | const ListEquality().equals; 7 | -------------------------------------------------------------------------------- /lib/src/util/waveform_alignment.dart: -------------------------------------------------------------------------------- 1 | ///Waveform align enum 2 | enum WaveformAlignment { 3 | ///Aligns waveform to the top of the canvas. 4 | top, 5 | 6 | ///Aligns waveform to the center of the canvas. 7 | 8 | center, 9 | 10 | ///Aligns waveform to the bottom of the canvas. 11 | 12 | bottom, 13 | } 14 | 15 | ///Extension to get Offset height based on waveform align 16 | extension WaveformAlignmentExtension on WaveformAlignment { 17 | ///Gets offset height based on waveform align 18 | double getAlignPosition(double height) { 19 | switch (this) { 20 | case WaveformAlignment.top: 21 | return 0; 22 | case WaveformAlignment.center: 23 | return height / 2; 24 | case WaveformAlignment.bottom: 25 | return height; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/waveforms/curved_polygon_waveform/active_inactive_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 3 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/polygon_waveform.dart'; 5 | 6 | ///InActiveWaveformPainter for the [PolygonWaveform] 7 | class CurvedPolygonActiveInActiveWaveformPainter 8 | extends ActiveInActiveWaveformPainter { 9 | // ignore: public_member_api_docs 10 | CurvedPolygonActiveInActiveWaveformPainter({ 11 | required super.samples, 12 | required super.waveformAlignment, 13 | required super.sampleWidth, 14 | required super.activeRatio, 15 | required super.inactiveColor, 16 | required super.activeColor, 17 | required super.strokeWidth, 18 | required super.style, 19 | }); 20 | 21 | @override 22 | // ignore: long-method 23 | void paint(Canvas canvas, Size size) { 24 | final paint = Paint() 25 | ..style = style 26 | ..color = color 27 | ..strokeJoin = StrokeJoin.round 28 | ..strokeCap = StrokeCap.round 29 | ..strokeWidth = strokeWidth 30 | ..shader = LinearGradient( 31 | begin: const Alignment(-1.001, 0), 32 | end: const Alignment(1.001, 0), 33 | colors: [ 34 | activeColor, 35 | inactiveColor, 36 | ], 37 | stops: [activeRatio, 0], 38 | ).createShader( 39 | Rect.fromLTWH(0, 0, size.width, size.height), 40 | ); 41 | 42 | final path = Path(); 43 | 44 | final bezierSamplesList = []; 45 | for (var i = 0; i < samples.length; i++) { 46 | final currentPoint = samples[i]; 47 | final nextPoint = i + 1 > samples.length - 1 ? 0.0 : samples[i + 1]; 48 | bezierSamplesList.add(currentPoint); 49 | // Addition of this two average points helps to get that curved effect. 50 | final averagePoint = (nextPoint + currentPoint) / 2; 51 | bezierSamplesList.add(averagePoint); 52 | final averagePoint2 = (nextPoint + averagePoint) / 2; 53 | bezierSamplesList.add(averagePoint2); 54 | } 55 | 56 | bezierSamplesList.add(0); 57 | final updatedWidth = size.width / bezierSamplesList.length; 58 | 59 | for (var i = 0; i < bezierSamplesList.length; i += 3) { 60 | final x = updatedWidth * i; 61 | final y = bezierSamplesList[i]; 62 | final doNotDrawPath = i + 1 > bezierSamplesList.length - 1 || 63 | i + 2 > bezierSamplesList.length - 1 || 64 | i + 3 > bezierSamplesList.length - 1; 65 | 66 | if (!doNotDrawPath) { 67 | final x1 = updatedWidth * (i + 1); 68 | final y1 = bezierSamplesList[i + 1]; 69 | final x2 = updatedWidth * (i + 2); 70 | final y2 = bezierSamplesList[i + 2]; 71 | 72 | path.cubicTo(x, y, x1, y1, x2, y2); 73 | } 74 | } 75 | 76 | //Gets the [alignPosition] depending on [waveformAlignment] 77 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 78 | 79 | //Shifts the path along y-axis by amount of [alignPosition] 80 | final shiftedPath = path.shift(Offset(0, alignPosition)); 81 | 82 | canvas.drawPath(shiftedPath, paint); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/src/waveforms/curved_polygon_waveform/curved_polygon_waveform.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/src/core/audio_waveform.dart'; 3 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/curved_polygon_waveform/active_inactive_waveform_painter.dart'; 5 | 6 | /// [CurvedPolygonWaveform] paints a squiggly waveform. 7 | /// The painter for this waveform is of the type [ActiveInActiveWaveformPainter] 8 | /// 9 | /// {@tool snippet} 10 | /// Example : 11 | /// ```dart 12 | /// CurvedPolygonWaveform( 13 | /// maxDuration: maxDuration, 14 | /// elapsedDuration: elapsedDuration, 15 | /// samples: samples, 16 | /// height: 300, 17 | /// width: MediaQuery.of(context).size.width, 18 | /// ) 19 | ///``` 20 | /// {@end-tool} 21 | class CurvedPolygonWaveform extends AudioWaveform { 22 | // ignore: public_member_api_docs 23 | CurvedPolygonWaveform({ 24 | super.key, 25 | required super.samples, 26 | required super.height, 27 | required super.width, 28 | super.maxDuration, 29 | super.elapsedDuration, 30 | this.activeColor = Colors.red, 31 | this.inactiveColor = Colors.blue, 32 | this.strokeWidth = 1.0, 33 | this.style = PaintingStyle.stroke, 34 | super.showActiveWaveform = true, 35 | super.absolute = false, 36 | super.invert = false, 37 | }) : assert(strokeWidth >= 0, "strokeWidth can't be negative."); 38 | 39 | /// The color of the active portion of the waveform. 40 | final Color activeColor; 41 | 42 | /// The color of the inactive portion of the waveform. 43 | final Color inactiveColor; 44 | 45 | /// The stroke width of the waveform. 46 | final double strokeWidth; 47 | 48 | /// waveform style 49 | final PaintingStyle style; 50 | 51 | @override 52 | AudioWaveformState createState() => 53 | _SquigglyWaveformState(); 54 | } 55 | 56 | class _SquigglyWaveformState extends AudioWaveformState { 57 | @override 58 | Widget build(BuildContext context) { 59 | if (widget.samples.isEmpty) { 60 | return const SizedBox.shrink(); 61 | } 62 | final processedSamples = this.processedSamples; 63 | final activeRatio = this.activeRatio; 64 | final waveformAlignment = this.waveformAlignment; 65 | 66 | return CustomPaint( 67 | size: Size(widget.width, widget.height), 68 | isComplex: true, 69 | painter: CurvedPolygonActiveInActiveWaveformPainter( 70 | samples: processedSamples, 71 | activeColor: widget.activeColor, 72 | inactiveColor: widget.inactiveColor, 73 | activeRatio: activeRatio, 74 | waveformAlignment: waveformAlignment, 75 | strokeWidth: widget.strokeWidth, 76 | sampleWidth: sampleWidth, 77 | style: widget.style, 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/src/waveforms/polygon_waveform/active_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 3 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/polygon_waveform.dart'; 5 | 6 | ///ActiveWaveformPainter for the [PolygonWaveform] 7 | class PolygonActiveWaveformPainter extends ActiveWaveformPainter { 8 | // ignore: public_member_api_docs 9 | PolygonActiveWaveformPainter({ 10 | required super.color, 11 | super.gradient, 12 | required super.activeSamples, 13 | required super.waveformAlignment, 14 | required super.style, 15 | required super.sampleWidth, 16 | }); 17 | 18 | @override 19 | void paint(Canvas canvas, Size size) { 20 | final continousActivePaint = Paint() 21 | ..style = style 22 | ..color = color 23 | ..shader = gradient?.createShader( 24 | Rect.fromLTWH(0, 0, size.width, size.height), 25 | ); 26 | 27 | final path = Path(); 28 | final isStroked = style == PaintingStyle.stroke; 29 | 30 | for (var i = 0; i < activeSamples.length; i++) { 31 | final x = sampleWidth * i; 32 | final y = activeSamples[i]; 33 | if (isStroked) { 34 | path.lineTo(x, y); 35 | } else { 36 | if (i == activeSamples.length - 1) { 37 | path.lineTo(x, 0); 38 | } else { 39 | path.lineTo(x, y); 40 | } 41 | } 42 | } 43 | 44 | //Gets the [alignPosition] depending on [waveformAlignment] 45 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 46 | 47 | //Shifts the path along y-axis by amount of [alignPosition] 48 | final shiftedPath = path.shift(Offset(0, alignPosition)); 49 | 50 | canvas.drawPath(shiftedPath, continousActivePaint); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/waveforms/polygon_waveform/inactive_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 3 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/polygon_waveform.dart'; 5 | 6 | ///InActiveWaveformPainter for the [PolygonWaveform] 7 | class PolygonInActiveWaveformPainter extends InActiveWaveformPainter { 8 | // ignore: public_member_api_docs 9 | PolygonInActiveWaveformPainter({ 10 | super.color = Colors.white, 11 | super.gradient, 12 | required super.samples, 13 | required super.waveformAlignment, 14 | required super.style, 15 | required super.sampleWidth, 16 | }); 17 | 18 | /// Style of the waveform 19 | 20 | @override 21 | void paint(Canvas canvas, Size size) { 22 | final paint = Paint() 23 | ..style = style 24 | ..color = color 25 | ..shader = gradient?.createShader( 26 | Rect.fromLTWH(0, 0, size.width, size.height), 27 | ); 28 | 29 | final path = Path(); 30 | 31 | for (var i = 0; i < samples.length; i++) { 32 | final x = sampleWidth * i; 33 | final y = samples[i]; 34 | 35 | if (i == samples.length - 1) { 36 | path.lineTo(x, 0); 37 | } else { 38 | path.lineTo(x, y); 39 | } 40 | } 41 | 42 | //Gets the [alignPosition] depending on [waveformAlignment] 43 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 44 | 45 | //Shifts the path along y-axis by amount of [alignPosition] 46 | final shiftedPath = path.shift(Offset(0, alignPosition)); 47 | 48 | canvas.drawPath(shiftedPath, paint); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/waveforms/polygon_waveform/polygon_waveform.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/flutter_audio_waveforms.dart'; 3 | import 'package:flutter_audio_waveforms/src/core/audio_waveform.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/active_waveform_painter.dart'; 5 | import 'package:flutter_audio_waveforms/src/waveforms/polygon_waveform/inactive_waveform_painter.dart'; 6 | 7 | /// [PolygonWaveform] paints the standard waveform that is used for audio 8 | /// waveforms, a sharp continuous line joining the points of a waveform. 9 | /// 10 | /// {@tool snippet} 11 | /// Example : 12 | /// ```dart 13 | /// PolygonWaveform( 14 | /// maxDuration: maxDuration, 15 | /// elapsedDuration: elapsedDuration, 16 | /// samples: samples, 17 | /// height: 300, 18 | /// width: MediaQuery.of(context).size.width, 19 | /// ) 20 | ///``` 21 | /// {@end-tool} 22 | class PolygonWaveform extends AudioWaveform { 23 | // ignore: public_member_api_docs 24 | PolygonWaveform({ 25 | super.key, 26 | required super.samples, 27 | required super.height, 28 | required super.width, 29 | super.maxDuration, 30 | super.elapsedDuration, 31 | this.activeColor = Colors.red, 32 | this.inactiveColor = Colors.blue, 33 | this.activeGradient, 34 | this.inactiveGradient, 35 | this.style = PaintingStyle.stroke, 36 | super.showActiveWaveform = true, 37 | super.absolute = false, 38 | super.invert = false, 39 | }); 40 | 41 | /// active waveform color 42 | final Color activeColor; 43 | 44 | /// inactive waveform color 45 | final Color inactiveColor; 46 | 47 | /// active waveform gradient 48 | final Gradient? activeGradient; 49 | 50 | /// inactive waveform gradient 51 | final Gradient? inactiveGradient; 52 | 53 | /// waveform style 54 | final PaintingStyle style; 55 | 56 | @override 57 | AudioWaveformState createState() => _PolygonWaveformState(); 58 | } 59 | 60 | class _PolygonWaveformState extends AudioWaveformState { 61 | @override 62 | Widget build(BuildContext context) { 63 | if (widget.samples.isEmpty) { 64 | return const SizedBox.shrink(); 65 | } 66 | final processedSamples = this.processedSamples; 67 | final activeSamples = this.activeSamples; 68 | final showActiveWaveform = this.showActiveWaveform; 69 | final waveformAlignment = this.waveformAlignment; 70 | final sampleWidth = this.sampleWidth; 71 | 72 | return Stack( 73 | children: [ 74 | RepaintBoundary( 75 | child: CustomPaint( 76 | size: Size(widget.width, widget.height), 77 | isComplex: true, 78 | painter: PolygonInActiveWaveformPainter( 79 | samples: processedSamples, 80 | style: widget.style, 81 | color: widget.inactiveColor, 82 | gradient: widget.inactiveGradient, 83 | waveformAlignment: waveformAlignment, 84 | sampleWidth: sampleWidth, 85 | ), 86 | ), 87 | ), 88 | if (showActiveWaveform) 89 | CustomPaint( 90 | isComplex: true, 91 | size: Size(widget.width, widget.height), 92 | painter: PolygonActiveWaveformPainter( 93 | style: widget.style, 94 | color: widget.activeColor, 95 | activeSamples: activeSamples, 96 | gradient: widget.activeGradient, 97 | waveformAlignment: waveformAlignment, 98 | sampleWidth: sampleWidth, 99 | ), 100 | ), 101 | ], 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/src/waveforms/rectangle_waveform/active_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: public_member_api_docs 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 5 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 6 | import 'package:flutter_audio_waveforms/src/waveforms/rectangle_waveform/rectangle_waveform.dart'; 7 | 8 | ///ActiveWaveformPainter for the [RectangleWaveform] 9 | class RectangleActiveWaveformPainter extends ActiveWaveformPainter { 10 | // ignore: public_member_api_docs 11 | RectangleActiveWaveformPainter({ 12 | required super.color, 13 | required super.activeSamples, 14 | required super.waveformAlignment, 15 | required super.sampleWidth, 16 | required super.borderColor, 17 | required super.borderWidth, 18 | required this.isRoundedRectangle, 19 | required this.isCentered, 20 | super.gradient, 21 | super.style = PaintingStyle.fill, 22 | }); 23 | final bool isRoundedRectangle; 24 | final bool isCentered; 25 | 26 | @override 27 | void paint(Canvas canvas, Size size) { 28 | final activeTrackPaint = Paint() 29 | ..style = style 30 | ..color = color 31 | ..shader = gradient?.createShader( 32 | Rect.fromLTWH(0, 0, size.width, size.height), 33 | ); 34 | 35 | final borderPaint = Paint() 36 | ..style = PaintingStyle.stroke 37 | ..color = borderColor 38 | ..strokeWidth = borderWidth; 39 | 40 | //Gets the [alignPosition] depending on [waveformAlignment] 41 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 42 | 43 | if (isRoundedRectangle) { 44 | drawRoundedRectangles( 45 | canvas, 46 | alignPosition, 47 | activeTrackPaint, 48 | borderPaint, 49 | waveformAlignment, 50 | isCentered, 51 | ); 52 | } else { 53 | drawRegularRectangles( 54 | canvas, 55 | alignPosition, 56 | activeTrackPaint, 57 | borderPaint, 58 | waveformAlignment, 59 | isCentered, 60 | ); 61 | } 62 | } 63 | 64 | // ignore: long-parameter-list 65 | void drawRegularRectangles( 66 | Canvas canvas, 67 | double alignPosition, 68 | Paint paint, 69 | Paint borderPaint, 70 | WaveformAlignment waveformAlignment, 71 | bool isCentered, 72 | ) { 73 | for (var i = 0; i < activeSamples.length; i++) { 74 | final x = sampleWidth * i; 75 | final isAbsolute = waveformAlignment != WaveformAlignment.center; 76 | final y = 77 | isCentered && !isAbsolute ? activeSamples[i] * 2 : activeSamples[i]; 78 | final positionFromTop = 79 | isCentered && !isAbsolute ? alignPosition - y / 2 : alignPosition; 80 | //Draws the filled rectangles of the waveform. 81 | canvas 82 | ..drawRect( 83 | Rect.fromLTWH(x, positionFromTop, sampleWidth, y), 84 | paint, 85 | ) 86 | //Draws the border for the rectangles of the waveform. 87 | ..drawRect( 88 | Rect.fromLTWH(x, positionFromTop, sampleWidth, y), 89 | borderPaint, 90 | ); 91 | } 92 | } 93 | 94 | // ignore: long-parameter-list 95 | void drawRoundedRectangles( 96 | Canvas canvas, 97 | double alignPosition, 98 | Paint paint, 99 | Paint borderPaint, 100 | WaveformAlignment waveformAlignment, 101 | bool isCentered, 102 | ) { 103 | for (var i = 0; i < activeSamples.length; i++) { 104 | if (i.isEven) { 105 | final x = sampleWidth * i; 106 | final isAbsolute = waveformAlignment != WaveformAlignment.center; 107 | final y = isAbsolute 108 | ? activeSamples[i] 109 | : !isCentered 110 | ? activeSamples[i] 111 | : activeSamples[i] * 2; 112 | final positionFromTop = isAbsolute 113 | ? alignPosition 114 | : !isCentered 115 | ? alignPosition 116 | : alignPosition - y / 2; 117 | 118 | //Draws the filled rectangles of the waveform. 119 | canvas 120 | ..drawRRect( 121 | RRect.fromRectAndRadius( 122 | Rect.fromLTWH(x, positionFromTop, sampleWidth, y), 123 | Radius.circular(x), 124 | ), 125 | paint, 126 | ) 127 | //Draws the border for the rectangles of the waveform. 128 | ..drawRRect( 129 | RRect.fromRectAndRadius( 130 | Rect.fromLTWH(x, positionFromTop, sampleWidth, y), 131 | Radius.circular(x), 132 | ), 133 | borderPaint, 134 | ); 135 | } 136 | } 137 | } 138 | 139 | @override 140 | bool shouldRepaint(covariant RectangleActiveWaveformPainter oldDelegate) { 141 | // TODO: implement shouldRepaint 142 | return getShouldRepaintValue(oldDelegate) || 143 | isRoundedRectangle != oldDelegate.isRoundedRectangle || 144 | isCentered != oldDelegate.isCentered; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/src/waveforms/rectangle_waveform/inactive_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: public_member_api_docs 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 5 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 6 | import 'package:flutter_audio_waveforms/src/waveforms/rectangle_waveform/rectangle_waveform.dart'; 7 | 8 | ///InActiveWaveformPainter for the [RectangleWaveform]. 9 | class RectangleInActiveWaveformPainter extends InActiveWaveformPainter { 10 | // ignore: public_member_api_docs 11 | RectangleInActiveWaveformPainter({ 12 | super.color = Colors.white, 13 | super.gradient, 14 | required super.samples, 15 | required super.waveformAlignment, 16 | required super.sampleWidth, 17 | required super.borderColor, 18 | required super.borderWidth, 19 | required this.isRoundedRectangle, 20 | required this.isCentered, 21 | super.style = PaintingStyle.fill, 22 | }); 23 | 24 | final bool isRoundedRectangle; 25 | final bool isCentered; 26 | 27 | @override 28 | void paint(Canvas canvas, Size size) { 29 | final paint = Paint() 30 | ..style = style 31 | ..color = color 32 | ..shader = gradient?.createShader( 33 | Rect.fromLTWH(0, 0, size.width, size.height), 34 | ); 35 | final borderPaint = Paint() 36 | ..style = PaintingStyle.stroke 37 | ..color = borderColor 38 | ..strokeWidth = borderWidth; 39 | //Gets the [alignPosition] depending on [waveformAlignment] 40 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 41 | final isAbsolute = waveformAlignment != WaveformAlignment.center; 42 | 43 | if (isRoundedRectangle) { 44 | drawRoundedRectangles( 45 | canvas, 46 | alignPosition, 47 | paint, 48 | borderPaint, 49 | waveformAlignment, 50 | isCentered, 51 | isAbsolute, 52 | ); 53 | } else { 54 | drawRegularRectangles( 55 | canvas, 56 | alignPosition, 57 | paint, 58 | borderPaint, 59 | waveformAlignment, 60 | isCentered, 61 | isAbsolute, 62 | ); 63 | } 64 | } 65 | 66 | // ignore: long-parameter-list 67 | void drawRegularRectangles( 68 | Canvas canvas, 69 | double alignPosition, 70 | Paint paint, 71 | Paint borderPaint, 72 | WaveformAlignment waveformAlignment, 73 | bool isCentered, 74 | bool isAbsolute, 75 | ) { 76 | final isCenteredAndNotAbsolute = isCentered && !isAbsolute; 77 | for (var i = 0; i < samples.length; i++) { 78 | final x = sampleWidth * i; 79 | final y = isCenteredAndNotAbsolute ? samples[i] * 2 : samples[i]; 80 | final positionFromTop = 81 | isCenteredAndNotAbsolute ? alignPosition - y / 2 : alignPosition; 82 | final rectangle = Rect.fromLTWH(x, positionFromTop, sampleWidth, y); 83 | 84 | //Draws the filled rectangles of the waveform. 85 | canvas 86 | ..drawRect( 87 | rectangle, 88 | paint, 89 | ) 90 | //Draws the border for the rectangles of the waveform. 91 | ..drawRect( 92 | rectangle, 93 | borderPaint, 94 | ); 95 | } 96 | } 97 | 98 | // ignore: long-parameter-list 99 | void drawRoundedRectangles( 100 | Canvas canvas, 101 | double alignPosition, 102 | Paint paint, 103 | Paint borderPaint, 104 | WaveformAlignment waveformAlignment, 105 | bool isCentered, 106 | bool isAbsolute, 107 | ) { 108 | final radius = Radius.circular(sampleWidth); 109 | final isAbsoluteAndNotCentered = isAbsolute || !isCentered; 110 | for (var i = 0; i < samples.length; i++) { 111 | if (i.isEven) { 112 | final x = sampleWidth * i; 113 | final y = isAbsoluteAndNotCentered ? samples[i] : samples[i] * 2; 114 | final positionFromTop = 115 | isAbsoluteAndNotCentered ? alignPosition : alignPosition - y / 2; 116 | final rectangle = Rect.fromLTWH(x, positionFromTop, sampleWidth, y); 117 | //Draws the filled rectangles of the waveform. 118 | canvas 119 | ..drawRRect( 120 | RRect.fromRectAndRadius( 121 | rectangle, 122 | radius, 123 | ), 124 | paint, 125 | ) 126 | //Draws the border for the rectangles of the waveform. 127 | ..drawRRect( 128 | RRect.fromRectAndRadius( 129 | rectangle, 130 | radius, 131 | ), 132 | borderPaint, 133 | ); 134 | } 135 | } 136 | } 137 | 138 | @override 139 | bool shouldRepaint(covariant RectangleInActiveWaveformPainter oldDelegate) { 140 | // TODO: implement shouldRepaint 141 | return getShouldRepaintValue(oldDelegate) || 142 | isRoundedRectangle != oldDelegate.isRoundedRectangle || 143 | isCentered != oldDelegate.isCentered; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /lib/src/waveforms/rectangle_waveform/rectangle_waveform.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_audio_waveforms/flutter_audio_waveforms.dart'; 3 | import 'package:flutter_audio_waveforms/src/core/audio_waveform.dart'; 4 | import 'package:flutter_audio_waveforms/src/waveforms/rectangle_waveform/active_waveform_painter.dart'; 5 | import 'package:flutter_audio_waveforms/src/waveforms/rectangle_waveform/inactive_waveform_painter.dart'; 6 | 7 | /// [RectangleWaveform] paints a waveform where each sample is represented as 8 | /// rectangle block. It's inspired by the @soundcloud audio track on web. 9 | /// 10 | /// {@tool snippet} 11 | /// Example : 12 | /// ```dart 13 | /// RectangleWaveform( 14 | /// maxDuration: maxDuration, 15 | /// elapsedDuration: elapsedDuration, 16 | /// samples: samples, 17 | /// height: 300, 18 | /// width: MediaQuery.of(context).size.width, 19 | /// ) 20 | ///``` 21 | /// {@end-tool} 22 | class RectangleWaveform extends AudioWaveform { 23 | // ignore: public_member_api_docs 24 | RectangleWaveform({ 25 | super.key, 26 | required super.samples, 27 | required super.height, 28 | required super.width, 29 | super.maxDuration, 30 | super.elapsedDuration, 31 | this.activeColor = Colors.red, 32 | this.inactiveColor = Colors.blue, 33 | this.activeGradient, 34 | this.inactiveGradient, 35 | this.borderWidth = 1.0, 36 | this.activeBorderColor = Colors.white, 37 | this.inactiveBorderColor = Colors.white, 38 | super.showActiveWaveform = true, 39 | super.absolute = false, 40 | super.invert = false, 41 | this.isRoundedRectangle = false, 42 | this.isCentered = false, 43 | }) : assert( 44 | borderWidth >= 0 && borderWidth <= 1.0, 45 | 'BorderWidth must be between 0 and 1', 46 | ); 47 | 48 | /// The color of the active waveform. 49 | final Color activeColor; 50 | 51 | /// The color of the inactive waveform. 52 | final Color inactiveColor; 53 | 54 | /// The gradient of the active waveform. 55 | final Gradient? activeGradient; 56 | 57 | /// The gradient of the inactive waveform. 58 | final Gradient? inactiveGradient; 59 | 60 | /// The width of the border of the waveform. 61 | final double borderWidth; 62 | 63 | /// The color of the active waveform border. 64 | final Color activeBorderColor; 65 | 66 | /// The color of the inactive waveform border. 67 | final Color inactiveBorderColor; 68 | 69 | /// If true then rounded rectangles are drawn instead of regular rectangles. 70 | final bool isRoundedRectangle; 71 | 72 | /// If true then rectangles are centered along the Y-axis with respect to 73 | /// their center along their height. 74 | /// 75 | /// If [absolute] is true then this would've no effect. 76 | final bool isCentered; 77 | 78 | @override 79 | AudioWaveformState createState() => 80 | _RectangleWaveformState(); 81 | } 82 | 83 | class _RectangleWaveformState extends AudioWaveformState { 84 | @override 85 | Widget build(BuildContext context) { 86 | if (widget.samples.isEmpty) { 87 | return const SizedBox.shrink(); 88 | } 89 | final processedSamples = this.processedSamples; 90 | final activeSamples = this.activeSamples; 91 | final showActiveWaveform = this.showActiveWaveform; 92 | final waveformAlignment = this.waveformAlignment; 93 | final sampleWidth = this.sampleWidth; 94 | 95 | return Stack( 96 | children: [ 97 | RepaintBoundary( 98 | child: CustomPaint( 99 | size: Size(widget.width, widget.height), 100 | isComplex: true, 101 | painter: RectangleInActiveWaveformPainter( 102 | samples: processedSamples, 103 | color: widget.inactiveColor, 104 | gradient: widget.inactiveGradient, 105 | waveformAlignment: waveformAlignment, 106 | borderColor: widget.inactiveBorderColor, 107 | borderWidth: widget.borderWidth, 108 | sampleWidth: sampleWidth, 109 | isRoundedRectangle: widget.isRoundedRectangle, 110 | isCentered: widget.isCentered, 111 | ), 112 | ), 113 | ), 114 | if (showActiveWaveform) 115 | CustomPaint( 116 | size: Size(widget.width, widget.height), 117 | isComplex: true, 118 | painter: RectangleActiveWaveformPainter( 119 | color: widget.activeColor, 120 | activeSamples: activeSamples, 121 | gradient: widget.activeGradient, 122 | waveformAlignment: waveformAlignment, 123 | borderColor: widget.activeBorderColor, 124 | borderWidth: widget.borderWidth, 125 | sampleWidth: sampleWidth, 126 | isRoundedRectangle: widget.isRoundedRectangle, 127 | isCentered: widget.isCentered, 128 | ), 129 | ), 130 | ], 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/src/waveforms/squiggly_waveform/active_inactive_waveform_painter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 5 | import 'package:flutter_audio_waveforms/src/util/waveform_alignment.dart'; 6 | import 'package:flutter_audio_waveforms/src/waveforms/squiggly_waveform/squiggly_waveform.dart'; 7 | 8 | ///Painter for the [SquigglyWaveform] 9 | /// Handles Painting both InActive and Active Waveforms. 10 | class SquigglyWaveformPainter extends ActiveInActiveWaveformPainter { 11 | // ignore: public_member_api_docs 12 | SquigglyWaveformPainter({ 13 | required super.activeColor, 14 | required super.samples, 15 | required super.inactiveColor, 16 | required super.activeRatio, 17 | required super.waveformAlignment, 18 | required super.sampleWidth, 19 | required super.strokeWidth, 20 | required this.absolute, 21 | required this.invert, 22 | }); 23 | 24 | ///Whether to draw the absolute waveform or not 25 | final bool absolute; 26 | 27 | ///Whether to invert the waveform or not 28 | final bool invert; 29 | 30 | @override 31 | void paint(Canvas canvas, Size size) { 32 | final paint = Paint() 33 | ..style = PaintingStyle.stroke 34 | ..strokeWidth = strokeWidth 35 | ..strokeCap = StrokeCap.round 36 | ..strokeJoin = StrokeJoin.round 37 | ..shader = LinearGradient( 38 | begin: const Alignment(-1.001, 0), 39 | end: const Alignment(1.001, 0), 40 | colors: [activeColor, inactiveColor], 41 | stops: [activeRatio, 0], 42 | ).createShader( 43 | Rect.fromLTWH(0, 0, size.width, size.height), 44 | ); 45 | 46 | final waveformPath = Path(); 47 | if (!absolute) { 48 | paintDefaultWaveform(waveformPath, sampleWidth, invert); 49 | } else if (absolute && !invert) { 50 | downwardFacingAbsoluteWaveform(waveformPath, sampleWidth); 51 | } else { 52 | upwardFacingAbsoluteWaveform(waveformPath, sampleWidth); 53 | } 54 | 55 | final alignPosition = waveformAlignment.getAlignPosition(size.height); 56 | 57 | final shiftedPath = waveformPath.shift(Offset(0, alignPosition)); 58 | 59 | canvas.drawPath(shiftedPath, paint); 60 | } 61 | 62 | /// Draws the default waveform 63 | // ignore: avoid_positional_boolean_parameters 64 | void paintDefaultWaveform(Path waveformPath, double pointWidth, bool invert) { 65 | for (var i = 0; i < samples.length; i++) { 66 | final value = samples[i]; 67 | final upOrDown = invert ? i.isOdd : i.isEven; 68 | final x = pointWidth * i; 69 | final x2 = pointWidth * (i + 1); 70 | final y2 = i != samples.length - 1 71 | ? upOrDown 72 | ? -value 73 | : value 74 | : 0.0; 75 | final diameter = x2 - x; 76 | final radius = diameter / 2; 77 | waveformPath 78 | ..lineTo(x, y2) 79 | ..lineTo(x, upOrDown ? y2 - diameter : y2 + diameter) 80 | ..addArc( 81 | Rect.fromCircle( 82 | center: 83 | Offset(x2 - radius, upOrDown ? y2 - diameter : y2 + diameter), 84 | radius: radius, 85 | ), 86 | -math.pi, 87 | upOrDown ? math.pi : -math.pi, 88 | ) 89 | ..lineTo(x2, y2); 90 | } 91 | } 92 | 93 | /// Draws the downward facing absolute waveform 94 | void upwardFacingAbsoluteWaveform(Path waveformPath, double pointWidth) { 95 | for (var i = 0; i < samples.length; i++) { 96 | final value = samples[i]; 97 | final x = pointWidth * i; 98 | final x2 = pointWidth * (i + 1); 99 | final y2 = value; 100 | final diameter = x2 - x; 101 | final radius = diameter / 2; 102 | waveformPath 103 | ..lineTo(x, y2) 104 | ..lineTo(x, y2 + diameter) 105 | ..addArc( 106 | Rect.fromCircle( 107 | center: Offset(x2 - radius, y2 + diameter), 108 | radius: radius, 109 | ), 110 | -math.pi, 111 | -math.pi, 112 | ) 113 | ..lineTo(x2, 0); 114 | } 115 | waveformPath.lineTo(0, 0); 116 | } 117 | 118 | /// Draws the upward facing absolute waveform 119 | void downwardFacingAbsoluteWaveform(Path waveformPath, double pointWidth) { 120 | for (var i = 0; i < samples.length; i++) { 121 | final value = samples[i]; 122 | final x = pointWidth * i; 123 | final x2 = pointWidth * (i + 1); 124 | final y2 = -value; 125 | final diameter = x2 - x; 126 | final radius = diameter / 2; 127 | waveformPath 128 | ..lineTo(x, y2) 129 | ..lineTo(x, y2 - diameter) 130 | ..addArc( 131 | Rect.fromCircle( 132 | center: Offset(x2 - radius, y2 - diameter), 133 | radius: radius, 134 | ), 135 | math.pi, 136 | math.pi, 137 | ) 138 | ..lineTo(x2, 0); 139 | } 140 | 141 | waveformPath.lineTo(0, 0); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /lib/src/waveforms/squiggly_waveform/squiggly_waveform.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_audio_waveforms/src/core/audio_waveform.dart'; 5 | import 'package:flutter_audio_waveforms/src/core/waveform_painters_ab.dart'; 6 | import 'package:flutter_audio_waveforms/src/waveforms/squiggly_waveform/active_inactive_waveform_painter.dart'; 7 | 8 | /// [SquigglyWaveform] paints a squiggly waveform. 9 | /// The painter for this waveform is of the type [ActiveInActiveWaveformPainter] 10 | /// 11 | /// {@tool snippet} 12 | /// Example : 13 | /// ```dart 14 | /// SquigglyWaveform( 15 | /// maxDuration: maxDuration, 16 | /// elapsedDuration: elapsedDuration, 17 | /// samples: samples, 18 | /// height: 300, 19 | /// width: MediaQuery.of(context).size.width, 20 | /// ) 21 | ///``` 22 | /// {@end-tool} 23 | class SquigglyWaveform extends AudioWaveform { 24 | // ignore: public_member_api_docs 25 | SquigglyWaveform({ 26 | super.key, 27 | required super.samples, 28 | required super.height, 29 | required super.width, 30 | super.maxDuration, 31 | super.elapsedDuration, 32 | this.activeColor = Colors.red, 33 | this.inactiveColor = Colors.blue, 34 | this.strokeWidth = 1.0, 35 | super.showActiveWaveform = true, 36 | super.absolute = false, 37 | super.invert = false, 38 | }) : assert(strokeWidth >= 0, "strokeWidth can't be negative."); 39 | 40 | /// The color of the active portion of the waveform. 41 | final Color activeColor; 42 | 43 | /// The color of the inactive portion of the waveform. 44 | final Color inactiveColor; 45 | 46 | /// The stroke width of the waveform. 47 | final double strokeWidth; 48 | 49 | @override 50 | AudioWaveformState createState() => 51 | _SquigglyWaveformState(); 52 | } 53 | 54 | class _SquigglyWaveformState extends AudioWaveformState { 55 | @override 56 | void processSamples() { 57 | final rawSamples = widget.samples; 58 | // ignore: omit_local_variable_types 59 | List processedSamples = 60 | rawSamples.map((e) => e.abs() * widget.height).toList(); 61 | 62 | final maxNum = 63 | processedSamples.reduce((a, b) => math.max(a.abs(), b.abs())); 64 | 65 | if (maxNum > 0) { 66 | final multiplier = math.pow(maxNum, -1).toDouble(); 67 | final finalHeight = absolute ? widget.height : widget.height / 2; 68 | final finalMultiplier = multiplier * finalHeight; 69 | 70 | processedSamples = processedSamples 71 | .map( 72 | (e) => e * finalMultiplier, 73 | ) 74 | .toList(); 75 | } 76 | updateProcessedSamples(processedSamples); 77 | } 78 | 79 | @override 80 | Widget build(BuildContext context) { 81 | if (widget.samples.isEmpty) { 82 | return const SizedBox.shrink(); 83 | } 84 | final processedSamples = this.processedSamples; 85 | final activeRatio = this.activeRatio; 86 | final waveformAlignment = this.waveformAlignment; 87 | 88 | return CustomPaint( 89 | size: Size(widget.width, widget.height), 90 | isComplex: true, 91 | painter: SquigglyWaveformPainter( 92 | samples: processedSamples, 93 | activeColor: widget.activeColor, 94 | inactiveColor: widget.inactiveColor, 95 | activeRatio: activeRatio, 96 | waveformAlignment: waveformAlignment, 97 | absolute: widget.absolute, 98 | invert: widget.invert, 99 | strokeWidth: widget.strokeWidth, 100 | sampleWidth: sampleWidth, 101 | ), 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: "4826f97faae3af9761f26c52e56b2aa5ffd18d2c1721d984ad85137721c25f43" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "31.0.0" 12 | analyzer: 13 | dependency: "direct dev" 14 | description: 15 | name: analyzer 16 | sha256: "7337610c3f9cd13e6b7c6bb0f410644091cf63c9a1436e73352a70f3286abb03" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.8.0" 20 | analyzer_plugin: 21 | dependency: transitive 22 | description: 23 | name: analyzer_plugin 24 | sha256: f25ddec490a021485c9d9cd02ded1563962bc4c5193f15560d8a63a93c0d0c60 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "0.8.0" 28 | ansicolor: 29 | dependency: transitive 30 | description: 31 | name: ansicolor 32 | sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "2.0.1" 36 | args: 37 | dependency: transitive 38 | description: 39 | name: args 40 | sha256: "0bd9a99b6eb96f07af141f0eb53eace8983e8e5aa5de59777aca31684680ef22" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.3.0" 44 | async: 45 | dependency: transitive 46 | description: 47 | name: async 48 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "2.10.0" 52 | boolean_selector: 53 | dependency: transitive 54 | description: 55 | name: boolean_selector 56 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "2.1.1" 60 | characters: 61 | dependency: transitive 62 | description: 63 | name: characters 64 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.2.1" 68 | cli_util: 69 | dependency: transitive 70 | description: 71 | name: cli_util 72 | sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "0.3.5" 76 | clock: 77 | dependency: transitive 78 | description: 79 | name: clock 80 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "1.1.1" 84 | collection: 85 | dependency: "direct main" 86 | description: 87 | name: collection 88 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "1.17.0" 92 | convert: 93 | dependency: transitive 94 | description: 95 | name: convert 96 | sha256: f08428ad63615f96a27e34221c65e1a451439b5f26030f78d790f461c686d65d 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "3.0.1" 100 | crypto: 101 | dependency: transitive 102 | description: 103 | name: crypto 104 | sha256: cf75650c66c0316274e21d7c43d3dea246273af5955bd94e8184837cd577575c 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "3.0.1" 108 | csslib: 109 | dependency: transitive 110 | description: 111 | name: csslib 112 | sha256: d1cd6d6e4b39a4ad295204722b8608f19981677b223f3e942c0b5a33dcf57ec0 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "0.17.1" 116 | dart_code_metrics: 117 | dependency: "direct dev" 118 | description: 119 | name: dart_code_metrics 120 | sha256: fdb36d04ecb1f9e4f563b4e99a6c4738f2c1e8f271c0840fb3c032926fdaf041 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "4.8.0" 124 | dart_style: 125 | dependency: transitive 126 | description: 127 | name: dart_style 128 | sha256: "2cac5b2dfcd79df1b57c117934d2d04e03f0420c0c6ea7bbf02836fcd34e131f" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "2.2.0" 132 | fake_async: 133 | dependency: transitive 134 | description: 135 | name: fake_async 136 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "1.3.1" 140 | file: 141 | dependency: transitive 142 | description: 143 | name: file 144 | sha256: b69516f2c26a5bcac4eee2e32512e1a5205ab312b3536c1c1227b2b942b5f9ad 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "6.1.2" 148 | flutter: 149 | dependency: "direct main" 150 | description: flutter 151 | source: sdk 152 | version: "0.0.0" 153 | flutter_test: 154 | dependency: "direct dev" 155 | description: flutter 156 | source: sdk 157 | version: "0.0.0" 158 | glob: 159 | dependency: transitive 160 | description: 161 | name: glob 162 | sha256: "8321dd2c0ab0683a91a51307fa844c6db4aa8e3981219b78961672aaab434658" 163 | url: "https://pub.dev" 164 | source: hosted 165 | version: "2.0.2" 166 | html: 167 | dependency: transitive 168 | description: 169 | name: html 170 | sha256: bfef906cbd4e78ef49ae511d9074aebd1d2251482ef601a280973e8b58b51bbf 171 | url: "https://pub.dev" 172 | source: hosted 173 | version: "0.15.0" 174 | js: 175 | dependency: transitive 176 | description: 177 | name: js 178 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 179 | url: "https://pub.dev" 180 | source: hosted 181 | version: "0.6.5" 182 | matcher: 183 | dependency: transitive 184 | description: 185 | name: matcher 186 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 187 | url: "https://pub.dev" 188 | source: hosted 189 | version: "0.12.13" 190 | material_color_utilities: 191 | dependency: transitive 192 | description: 193 | name: material_color_utilities 194 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 195 | url: "https://pub.dev" 196 | source: hosted 197 | version: "0.2.0" 198 | meta: 199 | dependency: transitive 200 | description: 201 | name: meta 202 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 203 | url: "https://pub.dev" 204 | source: hosted 205 | version: "1.8.0" 206 | package_config: 207 | dependency: transitive 208 | description: 209 | name: package_config 210 | sha256: a4d5ede5ca9c3d88a2fef1147a078570c861714c806485c596b109819135bc12 211 | url: "https://pub.dev" 212 | source: hosted 213 | version: "2.0.2" 214 | path: 215 | dependency: transitive 216 | description: 217 | name: path 218 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 219 | url: "https://pub.dev" 220 | source: hosted 221 | version: "1.8.2" 222 | pub_semver: 223 | dependency: transitive 224 | description: 225 | name: pub_semver 226 | sha256: b5a5fcc6425ea43704852ba4453ba94b08c2226c63418a260240c3a054579014 227 | url: "https://pub.dev" 228 | source: hosted 229 | version: "2.1.0" 230 | sky_engine: 231 | dependency: transitive 232 | description: flutter 233 | source: sdk 234 | version: "0.0.99" 235 | source_span: 236 | dependency: transitive 237 | description: 238 | name: source_span 239 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 240 | url: "https://pub.dev" 241 | source: hosted 242 | version: "1.9.1" 243 | stack_trace: 244 | dependency: transitive 245 | description: 246 | name: stack_trace 247 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 248 | url: "https://pub.dev" 249 | source: hosted 250 | version: "1.11.0" 251 | stream_channel: 252 | dependency: transitive 253 | description: 254 | name: stream_channel 255 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 256 | url: "https://pub.dev" 257 | source: hosted 258 | version: "2.1.1" 259 | string_scanner: 260 | dependency: transitive 261 | description: 262 | name: string_scanner 263 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 264 | url: "https://pub.dev" 265 | source: hosted 266 | version: "1.2.0" 267 | term_glyph: 268 | dependency: transitive 269 | description: 270 | name: term_glyph 271 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 272 | url: "https://pub.dev" 273 | source: hosted 274 | version: "1.2.1" 275 | test_api: 276 | dependency: transitive 277 | description: 278 | name: test_api 279 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 280 | url: "https://pub.dev" 281 | source: hosted 282 | version: "0.4.16" 283 | typed_data: 284 | dependency: transitive 285 | description: 286 | name: typed_data 287 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 288 | url: "https://pub.dev" 289 | source: hosted 290 | version: "1.3.0" 291 | vector_math: 292 | dependency: transitive 293 | description: 294 | name: vector_math 295 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 296 | url: "https://pub.dev" 297 | source: hosted 298 | version: "2.1.4" 299 | very_good_analysis: 300 | dependency: "direct dev" 301 | description: 302 | name: very_good_analysis 303 | sha256: cecd7a0e92978dbece97c255502c8965f2db3439cde5a11f4b2c65f1955911ee 304 | url: "https://pub.dev" 305 | source: hosted 306 | version: "2.4.0" 307 | watcher: 308 | dependency: transitive 309 | description: 310 | name: watcher 311 | sha256: e42dfcc48f67618344da967b10f62de57e04bae01d9d3af4c2596f3712a88c99 312 | url: "https://pub.dev" 313 | source: hosted 314 | version: "1.0.1" 315 | yaml: 316 | dependency: transitive 317 | description: 318 | name: yaml 319 | sha256: "3cee79b1715110341012d27756d9bae38e650588acd38d3f3c610822e1337ace" 320 | url: "https://pub.dev" 321 | source: hosted 322 | version: "3.1.0" 323 | sdks: 324 | dart: ">=2.18.0 <3.0.0" 325 | flutter: ">=1.17.0" 326 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_audio_waveforms 2 | description: A UI library for easily adding audio waveforms to your apps, with several customization options. 3 | version: 1.2.1+8 4 | homepage: https://github.com/rutvik110/flutter_audio_waveforms 5 | 6 | environment: 7 | sdk: ">=2.17.0 <3.0.0" 8 | flutter: ">=1.17.0" 9 | 10 | dependencies: 11 | collection: ^1.15.0 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | analyzer: ^2.8.0 19 | dart_code_metrics: ^4.8.0 20 | very_good_analysis: ^2.4.0 21 | 22 | # For information on the generic Dart part of this file, see the 23 | # following page: https://dart.dev/tools/pub/pubspec 24 | 25 | # The following section is specific to Flutter. 26 | flutter: 27 | 28 | # To add assets to your package, add an assets section, like this: 29 | # assets: 30 | # - images/a_dot_burr.jpeg 31 | # - images/a_dot_ham.jpeg 32 | # 33 | # For details regarding assets in packages, see 34 | # https://flutter.dev/assets-and-images/#from-packages 35 | # 36 | # An image asset can refer to one or more resolution-specific "variants", see 37 | # https://flutter.dev/assets-and-images/#resolution-aware. 38 | 39 | # To add custom fonts to your package, add a fonts section here, 40 | # in this "flutter" section. Each entry in this list should have a 41 | # "family" key with the font family name, and a "fonts" key with a 42 | # list giving the asset and other descriptors for the font. For 43 | # example: 44 | # fonts: 45 | # - family: Schyler 46 | # fonts: 47 | # - asset: fonts/Schyler-Regular.ttf 48 | # - asset: fonts/Schyler-Italic.ttf 49 | # style: italic 50 | # - family: Trajan Pro 51 | # fonts: 52 | # - asset: fonts/TrajanPro.ttf 53 | # - asset: fonts/TrajanPro_Bold.ttf 54 | # weight: 700 55 | # 56 | # For details regarding fonts in packages, see 57 | # https://flutter.dev/custom-fonts/#from-packages 58 | -------------------------------------------------------------------------------- /test/flutter_audio_waveforms_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | // test('adds one to input values', () { 5 | // final calculator = Calculator(); 6 | // expect(calculator.addOne(2), 3); 7 | // expect(calculator.addOne(-7), -6); 8 | // expect(calculator.addOne(0), 1); 9 | // }); 10 | } 11 | --------------------------------------------------------------------------------