diff --git a/packages/syncfusion_flutter_barcodes/CHANGELOG.md b/packages/syncfusion_flutter_barcodes/CHANGELOG.md index 225109ca3..dab7c46e9 100644 --- a/packages/syncfusion_flutter_barcodes/CHANGELOG.md +++ b/packages/syncfusion_flutter_barcodes/CHANGELOG.md @@ -2,6 +2,18 @@ * No changes. +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter barcodes widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter barcodes widget has been updated to Flutter SDK 3.35. + ## [30.1.37] - 06/25/2025 **General** diff --git a/packages/syncfusion_flutter_datagrid/example/android/app/build.gradle b/packages/syncfusion_flutter_barcodes/example/android/app/build.gradle.kts similarity index 69% rename from packages/syncfusion_flutter_datagrid/example/android/app/build.gradle rename to packages/syncfusion_flutter_barcodes/example/android/app/build.gradle.kts index b5511a9a3..70f9d0fed 100644 --- a/packages/syncfusion_flutter_datagrid/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_barcodes/example/android/app/build.gradle.kts @@ -1,27 +1,27 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { - namespace = "com.example.example" + namespace = "com.example.barcodes_example" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.example" + applicationId = "com.example.barcodes_example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_barcodes/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_barcodes/example/android/app/src/main/AndroidManifest.xml index 74a78b939..1f81f0522 100644 --- a/packages/syncfusion_flutter_barcodes/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_barcodes/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ ("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_barcodes/example/android/gradle.properties b/packages/syncfusion_flutter_barcodes/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_barcodes/example/android/gradle.properties +++ b/packages/syncfusion_flutter_barcodes/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_barcodes/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_barcodes/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_barcodes/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_barcodes/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_barcodes/example/android/settings.gradle b/packages/syncfusion_flutter_barcodes/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/syncfusion_flutter_barcodes/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_barcodes/example/android/settings.gradle.kts b/packages/syncfusion_flutter_barcodes/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_barcodes/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_barcodes/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_barcodes/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_barcodes/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/base/barcode_generator.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/base/barcode_generator.dart index 9c1d85f4e..4a30f8cfa 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/base/barcode_generator.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/base/barcode_generator.dart @@ -373,12 +373,12 @@ class _SfBarcodeGeneratorState extends State { return Container( color: widget.backgroundColor ?? _barcodeThemeData.backgroundColor, child: SfBarcodeGeneratorRenderObjectWidget( - value: widget.value!, + value: widget.value, symbology: widget.symbology, foregroundColor: widget.barColor ?? _barcodeThemeData.barColor, showText: widget.showValue, textSpacing: widget.textSpacing, - textStyle: _barcodeThemeData.textStyle!, + textStyle: _barcodeThemeData.textStyle, symbologyRenderer: _symbologyRenderer, textSize: _textSize, textAlign: widget.textAlign, diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/codabar_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/codabar_renderer.dart index 2d83daaba..942ea9a31 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/codabar_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/codabar_renderer.dart @@ -19,7 +19,7 @@ class CodabarRenderer extends SymbologyRenderer { '8': '100110101', '9': '110100101', '-': '101001101', - '\$': '101100101', + r'$': '101100101', ':': '1101011011', '/': '1101101011', '.': '1101101101', @@ -70,7 +70,7 @@ class CodabarRenderer extends SymbologyRenderer { ? offset.dx : getLeftPosition( barTotalLength, - symbology!.module!, + symbology!.module, size.width, offset.dx, ); @@ -85,7 +85,7 @@ class CodabarRenderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { // Calculates the bar length based on number of individual bar codes - final int singleModule = (size.width ~/ barTotalLength).toInt(); + final int singleModule = size.width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (size.width - (barTotalLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code128_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code128_renderer.dart index ebdb6b788..a332df190 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code128_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code128_renderer.dart @@ -16,7 +16,7 @@ class Code128Renderer extends SymbologyRenderer { code128ACharacterSets.add('!'); code128ACharacterSets.add('"'); code128ACharacterSets.add('#'); - code128ACharacterSets.add('\$'); + code128ACharacterSets.add(r'$'); code128ACharacterSets.add('%'); code128ACharacterSets.add('&'); // ignore: avoid_escaping_inner_quotes @@ -73,7 +73,7 @@ class Code128Renderer extends SymbologyRenderer { code128ACharacterSets.add('Y'); code128ACharacterSets.add('Z'); code128ACharacterSets.add('['); - code128ACharacterSets.add('\\'); + code128ACharacterSets.add(r'\'); code128ACharacterSets.add(']'); code128ACharacterSets.add('^'); code128ACharacterSets.add('_'); @@ -126,7 +126,7 @@ class Code128Renderer extends SymbologyRenderer { code128BCharacterSets.add('!'); code128BCharacterSets.add('"'); code128BCharacterSets.add('#'); - code128BCharacterSets.add('\$'); + code128BCharacterSets.add(r'$'); code128BCharacterSets.add('%'); code128BCharacterSets.add('&'); // ignore: avoid_escaping_inner_quotes @@ -183,7 +183,7 @@ class Code128Renderer extends SymbologyRenderer { code128BCharacterSets.add('Y'); code128BCharacterSets.add('Z'); code128BCharacterSets.add('['); - code128BCharacterSets.add('\\'); + code128BCharacterSets.add(r'\'); code128BCharacterSets.add(']'); code128BCharacterSets.add('^'); code128BCharacterSets.add('_'); @@ -669,7 +669,7 @@ class Code128Renderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { // Calculates the bar length based on number of individual bar codes - final int singleModule = (size.width ~/ totalBarLength).toInt(); + final int singleModule = size.width ~/ totalBarLength; ratio = singleModule.toDouble(); final double leftPadding = (size.width - (totalBarLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_extended_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_extended_renderer.dart index 203f6207c..5041db210 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_extended_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_extended_renderer.dart @@ -7,32 +7,32 @@ class Code39ExtendedRenderer extends Code39Renderer { Code39ExtendedRenderer({Symbology? symbology}) : super(symbology: symbology) { _code39ExtendedMap = { '0': '%U', - '1': '\$A', - '2': '\$B', - '3': '\$C', - '4': '\$D', - '5': '\$E', - '6': '\$F', - '7': '\$G', - '8': '\$H', - '9': '\$I', - '10': '\$J', - '11': '\$K', - '12': '\$L', - '13': '\$M', - '14': '\$N', - '15': '\$O', - '16': '\$P', - '17': '\$Q', - '18': '\$R', - '19': '\$S', - '20': '\$T', - '21': '\$U', - '22': '\$V', - '23': '\$W', - '24': '\$X', - '25': '\$Y', - '26': '\$Z', + '1': r'$A', + '2': r'$B', + '3': r'$C', + '4': r'$D', + '5': r'$E', + '6': r'$F', + '7': r'$G', + '8': r'$H', + '9': r'$I', + '10': r'$J', + '11': r'$K', + '12': r'$L', + '13': r'$M', + '14': r'$N', + '15': r'$O', + '16': r'$P', + '17': r'$Q', + '18': r'$R', + '19': r'$S', + '20': r'$T', + '21': r'$U', + '22': r'$V', + '23': r'$W', + '24': r'$X', + '25': r'$Y', + '26': r'$Z', '27': '%A', '28': '%B', '29': '%C', diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_renderer.dart index 565b2cd0b..3f021a73f 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code39_renderer.dart @@ -140,7 +140,7 @@ class Code39Renderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { // Calculates the bar length based on number of individual bar codes - final int singleModule = (size.width ~/ barTotalLength).toInt(); + final int singleModule = size.width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (size.width - (barTotalLength * ratio)) / 2; left += leftPadding; @@ -209,7 +209,7 @@ class Code39Renderer extends SymbologyRenderer { /// Represents the code bar value String _getCode39Character() { const String code39Character = - '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *\$/+%'; + r'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%'; return code39Character; } } diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code93_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code93_renderer.dart index ba2fce3bd..36f18d895 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code93_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/code93_renderer.dart @@ -6,7 +6,7 @@ import 'symbology_base_renderer.dart'; /// Represents the code93 renderer class class Code93Renderer extends SymbologyRenderer { /// Creates the code93 renderer - Code93Renderer({Symbology? symbology}) : super(symbology: symbology!) { + Code93Renderer({Symbology? symbology}) : super(symbology: symbology) { _character = _getCode93Character(); } @@ -67,11 +67,11 @@ class Code93Renderer extends SymbologyRenderer { '-': '36', '.': '37', ' ': '38', - '\$': '39', + r'$': '39', '/': '40', '+': '41', '%': '42', - '(\$)': '43', + r'($)': '43', '(/)': '44', '(+)': '45', '(%)': '46', @@ -120,11 +120,11 @@ class Code93Renderer extends SymbologyRenderer { '-': '100101110', '.': '111010100', ' ': '111010010', - '\$': '111001010', + r'$': '111001010', '/': '101101110', '+': '101110110', '%': '110101110', - '(\$)': '100100110', + r'($)': '100100110', '(/)': '111010110', '(+)': '100110010', '(%)': '111011010', @@ -166,7 +166,7 @@ class Code93Renderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { //Calculates the bar length based on number of individual bar codes - final int singleModule = (size.width ~/ barTotalLength).toInt(); + final int singleModule = size.width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (size.width - (barTotalLength * ratio)) / 2; left += leftPadding; @@ -264,7 +264,7 @@ class Code93Renderer extends SymbologyRenderer { /// Retuns the supported input symbol String _getCode93Character() { const String code93Character = - '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *\$/+%'; + r'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%'; return code93Character; } } diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean13_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean13_renderer.dart index 427c51c20..50cb6c44f 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean13_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean13_renderer.dart @@ -88,7 +88,7 @@ class EAN13Renderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { // Calculates the bar length based on number of individual bar codes - final int singleModule = (width ~/ barTotalLength).toInt(); + final int singleModule = width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (width - (barTotalLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean8_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean8_renderer.dart index c5b8321f2..040db8c82 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean8_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/ean8_renderer.dart @@ -76,7 +76,7 @@ class EAN8Renderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { // Calculates the bar length based on number of individual bar codes - final int singleModule = (size.width ~/ barTotalLength).toInt(); + final int singleModule = size.width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (size.width - (barTotalLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upca_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upca_renderer.dart index cc45289ad..c2c309aa0 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upca_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upca_renderer.dart @@ -98,7 +98,7 @@ class UPCARenderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { //Calculates the bar length based on number of individual bar codes - final int singleModule = (width ~/ barTotalLength).toInt(); + final int singleModule = width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (width - (barTotalLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upce_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upce_renderer.dart index 38b944db8..1619e50b4 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upce_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/one_dimensional/upce_renderer.dart @@ -84,7 +84,7 @@ class UPCERenderer extends SymbologyRenderer { ratio = symbology!.module!.toDouble(); } else { //Calculates the bar length based on number of individual bar codes - final int singleModule = (width ~/ barTotalLength).toInt(); + final int singleModule = width ~/ barTotalLength; ratio = singleModule.toDouble(); final double leftPadding = (width - (barTotalLength * ratio)) / 2; left += leftPadding; diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/datamatrix_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/datamatrix_renderer.dart index b4781413b..de2a24c6f 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/datamatrix_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/datamatrix_renderer.dart @@ -1243,7 +1243,7 @@ class DataMatrixRenderer extends SymbologyRenderer { int bIndex = blockErrorWords; for (int i = block + (step * blockDataWords); i < total; i += step) { - correctionCodeWordArray[i] = blockByte[--bIndex]!; + correctionCodeWordArray[i] = blockByte[--bIndex]; } if (bIndex != 0) { @@ -1492,7 +1492,7 @@ class DataMatrixRenderer extends SymbologyRenderer { } if (showValue) { - final Offset textOffset = Offset(offset.dx, yPosition.toDouble()); + final Offset textOffset = Offset(offset.dx, yPosition); drawText( canvas, textOffset, diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart index ccb2da71c..943b437db 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart @@ -6,8 +6,8 @@ class ErrorCorrectionCodeWords { /// Creates the error correction code word ErrorCorrectionCodeWords({this.codeVersion, this.correctionLevel}) { _codeValue = QRCodeValue( - qrCodeVersion: codeVersion!, - errorCorrectionLevel: correctionLevel!, + qrCodeVersion: codeVersion, + errorCorrectionLevel: correctionLevel, ); eccw = _codeValue.noOfErrorCorrectionCodeWord; } diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_renderer.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_renderer.dart index 0ce548cd0..09b85f797 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_renderer.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_renderer.dart @@ -767,7 +767,7 @@ class QRCodeRenderer extends SymbologyRenderer { _encodedText[i].codeUnitAt(0) > 47) { } else if ((_encodedText[i].codeUnitAt(0) < 91 && _encodedText[i].codeUnitAt(0) > 64) || - _encodedText[i] == '\$' || + _encodedText[i] == r'$' || _encodedText[i] == '%' || _encodedText[i] == '*' || _encodedText[i] == '+' || @@ -1970,10 +1970,10 @@ class QRCodeRenderer extends SymbologyRenderer { ); canvas.drawRect(rect, paint); - x = (x + dimension).toInt(); + x = x + dimension; } - yPosition = (yPosition + dimension).toInt(); + yPosition = yPosition + dimension; } if (showValue) { diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_values.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_values.dart index 3f948a99b..a577155fa 100644 --- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_values.dart +++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/qr_code_values.dart @@ -950,7 +950,7 @@ class QRCodeValue { case ' ': valueInInt = 36; break; - case '\$': + case r'$': valueInInt = 37; break; case '%': diff --git a/packages/syncfusion_flutter_barcodes/pubspec.yaml b/packages/syncfusion_flutter_barcodes/pubspec.yaml index c4697c799..4f401ee6a 100644 --- a/packages/syncfusion_flutter_barcodes/pubspec.yaml +++ b/packages/syncfusion_flutter_barcodes/pubspec.yaml @@ -1,11 +1,11 @@ name: syncfusion_flutter_barcodes description: Flutter Barcodes generator library is used to generate and display data in the machine-readable, industry-standard 1D and 2D barcodes. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_barcodes environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" flutter: uses-material-design: true @@ -15,5 +15,3 @@ dependencies: sdk: flutter syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_calendar/CHANGELOG.md b/packages/syncfusion_flutter_calendar/CHANGELOG.md index 0ef65ee74..89391086a 100644 --- a/packages/syncfusion_flutter_calendar/CHANGELOG.md +++ b/packages/syncfusion_flutter_calendar/CHANGELOG.md @@ -2,6 +2,34 @@ * No changes. +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter calendar widget has been updated to Flutter SDK 3.38. + +## [31.2.5] - 11/04/2025 + +**General** + +* The translation for “No events” has been modified to “Etkinlik yok” from “Olay yok” for Turkish language. + +## [31.2.4] - 10/28/2025 + +**Enhancements** + +* \#FB70566 - The display of exceeding events has been improved for all-day events with [appointmentBuilder](https://pub.dev/documentation/syncfusion_flutter_calendar/latest/calendar/SfCalendar/appointmentBuilder.html) customization. + +**Breaking changes** + +* \#FB70575 - The [leadingDateTextStyle](https://pub.dev/documentation/syncfusion_flutter_calendar/latest/calendar/MonthCellStyle/leadingDatesTextStyle.html) now applies to dates in the previous month, while the [trailingDateTextStyle](https://pub.dev/documentation/syncfusion_flutter_calendar/latest/calendar/MonthCellStyle/trailingDatesTextStyle.html) applies to dates in the next month in the month view. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter calendar widget has been updated to Flutter SDK 3.35. + ## [30.1.37] - 06/25/2025 **General** diff --git a/packages/syncfusion_flutter_calendar/example/android/app/build.gradle.kts b/packages/syncfusion_flutter_calendar/example/android/app/build.gradle.kts index 21ecea973..a4e22a57b 100644 --- a/packages/syncfusion_flutter_calendar/example/android/app/build.gradle.kts +++ b/packages/syncfusion_flutter_calendar/example/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.example" + namespace = "com.example.calendar_example" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.example" + applicationId = "com.example.calendar_example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/packages/syncfusion_flutter_calendar/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_calendar/example/android/app/src/main/AndroidManifest.xml index 74a78b939..83b0d723b 100644 --- a/packages/syncfusion_flutter_calendar/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_calendar/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ timeIntervalMinutes - ? timeIntervalMinutes - : minimumAppointmentMinutes; + ? calendar + .timeSlotViewSettings + .minimumAppointmentDuration! + .inMinutes + : 0; + minimumAppointmentMinutes = + minimumAppointmentMinutes > timeIntervalMinutes + ? timeIntervalMinutes + : minimumAppointmentMinutes; if (minimumAppointmentMinutes > 0 && !isTimelineMonth) { final int timeIntervalMinutes = calendar.timeSlotViewSettings.timeInterval.inMinutes; minimumAppointmentMinutes = minimumAppointmentMinutes > timeIntervalMinutes - ? timeIntervalMinutes - : minimumAppointmentMinutes; + ? timeIntervalMinutes + : minimumAppointmentMinutes; if (getDifference( currentAppointmentStartTime, currentAppointmentEndTime, @@ -845,12 +848,13 @@ class AppointmentHelper { int? resourceIndex, ]) { final bool isTimeline = CalendarViewHelper.isTimelineView(view); - final List normalAppointments = visibleAppointments - .where( - (CalendarAppointment app) => - _iterateAppointment(app, isTimeline, isAllDay), - ) - .toList(); + final List normalAppointments = + visibleAppointments + .where( + (CalendarAppointment app) => + _iterateAppointment(app, isTimeline, isAllDay), + ) + .toList(); normalAppointments.sort( (CalendarAppointment app1, CalendarAppointment app2) => app1.actualStartTime.compareTo(app2.actualStartTime), @@ -952,14 +956,18 @@ class AppointmentHelper { intersectingApps = []; dict[dict.keys.length] = intersectingApps; } else if (intersectingApps.isNotEmpty) { - position = intersectingApps - .reduce( - (AppointmentView currentAppview, AppointmentView nextAppview) => - currentAppview.maxPositions > nextAppview.maxPositions - ? currentAppview - : nextAppview, - ) - .maxPositions; + position = + intersectingApps + .reduce( + ( + AppointmentView currentAppview, + AppointmentView nextAppview, + ) => + currentAppview.maxPositions > nextAppview.maxPositions + ? currentAppview + : nextAppview, + ) + .maxPositions; } intersectingApps.add(currentAppView); @@ -977,14 +985,18 @@ class AppointmentHelper { intersectingApps = []; dict[dict.keys.length] = intersectingApps; } else if (intersectingApps.isNotEmpty) { - maxPosition = intersectingApps - .reduce( - (AppointmentView currentAppview, AppointmentView nextAppview) => - currentAppview.maxPositions > nextAppview.maxPositions - ? currentAppview - : nextAppview, - ) - .maxPositions; + maxPosition = + intersectingApps + .reduce( + ( + AppointmentView currentAppview, + AppointmentView nextAppview, + ) => + currentAppview.maxPositions > nextAppview.maxPositions + ? currentAppview + : nextAppview, + ) + .maxPositions; if (currentAppView.position == maxPosition) { maxPosition++; @@ -1215,20 +1227,22 @@ class AppointmentHelper { ); } - spannedAppointment.startTime = spannedAppointment.isAllDay - ? appointment.actualStartTime - : convertTimeToAppointmentTimeZone( - appointment.actualStartTime, - calendarTimeZone, - appointment.startTimeZone, - ); - spannedAppointment.endTime = spannedAppointment.isAllDay - ? appointment.actualEndTime - : convertTimeToAppointmentTimeZone( - appointment.actualEndTime, - calendarTimeZone, - appointment.endTimeZone, - ); + spannedAppointment.startTime = + spannedAppointment.isAllDay + ? appointment.actualStartTime + : convertTimeToAppointmentTimeZone( + appointment.actualStartTime, + calendarTimeZone, + appointment.startTimeZone, + ); + spannedAppointment.endTime = + spannedAppointment.isAllDay + ? appointment.actualEndTime + : convertTimeToAppointmentTimeZone( + appointment.actualEndTime, + calendarTimeZone, + appointment.endTimeZone, + ); // Adding Spanned Appointment only when the Appointment range // within the VisibleDate @@ -1285,20 +1299,22 @@ class AppointmentHelper { ); } - spannedAppointment.startTime = spannedAppointment.isAllDay - ? appointment.actualStartTime - : convertTimeToAppointmentTimeZone( - appointment.actualStartTime, - calendarTimeZone, - appointment.startTimeZone, - ); - spannedAppointment.endTime = spannedAppointment.isAllDay - ? appointment.actualEndTime - : convertTimeToAppointmentTimeZone( - appointment.actualEndTime, - calendarTimeZone, - appointment.endTimeZone, - ); + spannedAppointment.startTime = + spannedAppointment.isAllDay + ? appointment.actualStartTime + : convertTimeToAppointmentTimeZone( + appointment.actualStartTime, + calendarTimeZone, + appointment.startTimeZone, + ); + spannedAppointment.endTime = + spannedAppointment.isAllDay + ? appointment.actualEndTime + : convertTimeToAppointmentTimeZone( + appointment.actualEndTime, + calendarTimeZone, + appointment.endTimeZone, + ); // Adding Spanned Appointment only when the Appointment range // within the VisibleDate @@ -1344,20 +1360,22 @@ class AppointmentHelper { ); } - spannedAppointment.startTime = spannedAppointment.isAllDay - ? appointment.actualStartTime - : convertTimeToAppointmentTimeZone( - appointment.actualStartTime, - calendarTimeZone, - appointment.startTimeZone, - ); - spannedAppointment.endTime = spannedAppointment.isAllDay - ? appointment.actualEndTime - : convertTimeToAppointmentTimeZone( - appointment.actualEndTime, - calendarTimeZone, - appointment.endTimeZone, - ); + spannedAppointment.startTime = + spannedAppointment.isAllDay + ? appointment.actualStartTime + : convertTimeToAppointmentTimeZone( + appointment.actualStartTime, + calendarTimeZone, + appointment.startTimeZone, + ); + spannedAppointment.endTime = + spannedAppointment.isAllDay + ? appointment.actualEndTime + : convertTimeToAppointmentTimeZone( + appointment.actualEndTime, + calendarTimeZone, + appointment.endTimeZone, + ); // Adding Spanned Appointment only when the Appointment range // within the VisibleDate @@ -1423,20 +1441,22 @@ class AppointmentHelper { ); } - spannedAppointment.startTime = spannedAppointment.isAllDay - ? appointment.actualStartTime - : convertTimeToAppointmentTimeZone( - appointment.actualStartTime, - calendarTimeZone, - appointment.startTimeZone, - ); - spannedAppointment.endTime = spannedAppointment.isAllDay - ? appointment.actualEndTime - : convertTimeToAppointmentTimeZone( - appointment.actualEndTime, - calendarTimeZone, - appointment.endTimeZone, - ); + spannedAppointment.startTime = + spannedAppointment.isAllDay + ? appointment.actualStartTime + : convertTimeToAppointmentTimeZone( + appointment.actualStartTime, + calendarTimeZone, + appointment.startTimeZone, + ); + spannedAppointment.endTime = + spannedAppointment.isAllDay + ? appointment.actualEndTime + : convertTimeToAppointmentTimeZone( + appointment.actualEndTime, + calendarTimeZone, + appointment.endTimeZone, + ); // Adding Spanned Appointment only when the Appointment range // within the VisibleDate @@ -1470,31 +1490,34 @@ class AppointmentHelper { ) { final CalendarAppointment occurrenceAppointment = _copy(appointment); occurrenceAppointment.actualStartTime = recursiveDate; - occurrenceAppointment.startTime = occurrenceAppointment.isAllDay - ? occurrenceAppointment.actualStartTime - : convertTimeToAppointmentTimeZone( - occurrenceAppointment.actualStartTime, - calendarTimeZone, - occurrenceAppointment.startTimeZone, - ); - - final int minutes = getDifference( - appointment.actualStartTime, - appointment.actualEndTime, - ).inMinutes; + occurrenceAppointment.startTime = + occurrenceAppointment.isAllDay + ? occurrenceAppointment.actualStartTime + : convertTimeToAppointmentTimeZone( + occurrenceAppointment.actualStartTime, + calendarTimeZone, + occurrenceAppointment.startTimeZone, + ); + + final int minutes = + getDifference( + appointment.actualStartTime, + appointment.actualEndTime, + ).inMinutes; occurrenceAppointment.actualEndTime = DateTimeHelper.getDateTimeValue( addDuration( occurrenceAppointment.actualStartTime, Duration(minutes: minutes), ), ); - occurrenceAppointment.endTime = occurrenceAppointment.isAllDay - ? occurrenceAppointment.actualEndTime - : convertTimeToAppointmentTimeZone( - occurrenceAppointment.actualEndTime, - calendarTimeZone, - occurrenceAppointment.endTimeZone, - ); + occurrenceAppointment.endTime = + occurrenceAppointment.isAllDay + ? occurrenceAppointment.actualEndTime + : convertTimeToAppointmentTimeZone( + occurrenceAppointment.actualEndTime, + calendarTimeZone, + occurrenceAppointment.endTimeZone, + ); occurrenceAppointment.isSpanned = _isSpanned(occurrenceAppointment) && getDifference( @@ -1537,20 +1560,22 @@ class AppointmentHelper { final DateTime appStartTime = item.startTime; final DateTime appEndTime = item.endTime; item.data = item; - item.actualStartTime = !item.isAllDay - ? convertTimeToAppointmentTimeZone( - item.startTime, - item.startTimeZone, - calendarTimeZone, - ) - : item.startTime; - item.actualEndTime = !item.isAllDay - ? convertTimeToAppointmentTimeZone( - item.endTime, - item.endTimeZone, - calendarTimeZone, - ) - : item.endTime; + item.actualStartTime = + !item.isAllDay + ? convertTimeToAppointmentTimeZone( + item.startTime, + item.startTimeZone, + calendarTimeZone, + ) + : item.startTime; + item.actualEndTime = + !item.isAllDay + ? convertTimeToAppointmentTimeZone( + item.endTime, + item.endTimeZone, + calendarTimeZone, + ) + : item.endTime; _updateTimeForInvalidEndTime(item, calendarTimeZone); calendarAppointmentCollection.add(item); @@ -1625,20 +1650,22 @@ class AppointmentHelper { } app.data = appointmentObject; - app.actualStartTime = !app.isAllDay - ? convertTimeToAppointmentTimeZone( - app.startTime, - app.startTimeZone, - calendarTimeZone, - ) - : app.startTime; - app.actualEndTime = !app.isAllDay - ? convertTimeToAppointmentTimeZone( - app.endTime, - app.endTimeZone, - calendarTimeZone, - ) - : app.endTime; + app.actualStartTime = + !app.isAllDay + ? convertTimeToAppointmentTimeZone( + app.startTime, + app.startTimeZone, + calendarTimeZone, + ) + : app.startTime; + app.actualEndTime = + !app.isAllDay + ? convertTimeToAppointmentTimeZone( + app.endTime, + app.endTimeZone, + calendarTimeZone, + ) + : app.endTime; _updateTimeForInvalidEndTime(app, calendarTimeZone); return app; } @@ -1654,13 +1681,14 @@ class AppointmentHelper { scheduleTimeZone, appointment.endTimeZone, ); - appointment.actualEndTime = !appointment.isAllDay - ? convertTimeToAppointmentTimeZone( - appointment.endTime, - appointment.endTimeZone, - scheduleTimeZone, - ) - : appointment.endTime; + appointment.actualEndTime = + !appointment.isAllDay + ? convertTimeToAppointmentTimeZone( + appointment.endTime, + appointment.endTimeZone, + scheduleTimeZone, + ) + : appointment.endTime; } } @@ -1751,11 +1779,11 @@ class AppointmentHelper { /// here we identify based on the string and removed the appended string. occurrenceAppointment.notes = recDates.isNotEmpty && - isSameDate(occurrenceAppointment.startTime, recDates[0]) - ? appointment.notes - : appointment.notes == null - ? 'isOccurrenceAppointment' - : '${appointment.notes!}isOccurrenceAppointment'; + isSameDate(occurrenceAppointment.startTime, recDates[0]) + ? appointment.notes + : appointment.notes == null + ? 'isOccurrenceAppointment' + : '${appointment.notes!}isOccurrenceAppointment'; appointments.add(occurrenceAppointment); } } diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/month_appointment_helper.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/month_appointment_helper.dart index 507ea396f..646109fed 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/month_appointment_helper.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/month_appointment_helper.dart @@ -227,12 +227,14 @@ class MonthAppointmentHelper { final CalendarAppointment appointment2 = appointmentView2.appointment!; /// Calculate the both appointment start time based on isAllDay property. - final DateTime startTime1 = appointment1.isAllDay - ? AppointmentHelper.convertToStartTime(appointment1.exactStartTime) - : appointment1.exactStartTime; - final DateTime startTime2 = appointment2.isAllDay - ? AppointmentHelper.convertToStartTime(appointment2.exactStartTime) - : appointment2.exactStartTime; + final DateTime startTime1 = + appointment1.isAllDay + ? AppointmentHelper.convertToStartTime(appointment1.exactStartTime) + : appointment1.exactStartTime; + final DateTime startTime2 = + appointment2.isAllDay + ? AppointmentHelper.convertToStartTime(appointment2.exactStartTime) + : appointment2.exactStartTime; /// Check if both the appointments does not starts with same date then /// order the appointment based on its start time value. @@ -245,12 +247,14 @@ class MonthAppointmentHelper { return startTime1.compareTo(startTime2); } - final DateTime endTime1 = appointment1.isAllDay - ? AppointmentHelper.convertToEndTime(appointment1.exactEndTime) - : appointment1.exactEndTime; - final DateTime endTime2 = appointment2.isAllDay - ? AppointmentHelper.convertToEndTime(appointment2.exactEndTime) - : appointment2.exactEndTime; + final DateTime endTime1 = + appointment1.isAllDay + ? AppointmentHelper.convertToEndTime(appointment1.exactEndTime) + : appointment1.exactEndTime; + final DateTime endTime2 = + appointment2.isAllDay + ? AppointmentHelper.convertToEndTime(appointment2.exactEndTime) + : appointment2.exactEndTime; /// Check both the appointments have same start and end time then sort the /// appointments based on start time value. diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/recurrence_helper.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/recurrence_helper.dart index 4c665cd69..1e61a1a1c 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/recurrence_helper.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_engine/recurrence_helper.dart @@ -87,9 +87,8 @@ class RecurrenceHelper { recurrenceCount = int.parse(recurrenceCountString); } - final int dailyDayGap = rRule.contains('INTERVAL') - ? int.parse(intervalCountString) - : 1; + final int dailyDayGap = + rRule.contains('INTERVAL') ? int.parse(intervalCountString) : 1; DateTime? endDate; if (rRule.contains('UNTIL')) { /// Set the end date value from until date value. @@ -137,9 +136,10 @@ class RecurrenceHelper { /// NoEndDate specified rule returns empty collection issue fix. if (isSpecificDateRange) { - endDate = endDate == null || endDate.isAfter(specificEndDate) - ? specificEndDate - : endDate; + endDate = + endDate == null || endDate.isAfter(specificEndDate) + ? specificEndDate + : endDate; } int recurrenceIncrementCount = 0; @@ -162,10 +162,11 @@ class RecurrenceHelper { /// Total days difference between the visible start date and recurrence /// start date. - final int difference = AppointmentHelper.getDifference( - recurrenceInitialDate, - visibleInitialDate, - ).inDays; + final int difference = + AppointmentHelper.getDifference( + recurrenceInitialDate, + visibleInitialDate, + ).inDays; final int dayDifference = difference % dailyDayGap; /// Valid recurrences in between the visible start date and recurrence @@ -199,9 +200,10 @@ class RecurrenceHelper { final DateTime recurrenceEndDate = addDate.add(recurrenceDuration); if (incrementCount > 0 && !isSameDate(addDate, recurrenceEndDate)) { - final int durationDifference = recurrenceEndDate.hour > addDate.hour - ? recurrenceDuration.inDays - : recurrenceDuration.inDays + 1; + final int durationDifference = + recurrenceEndDate.hour > addDate.hour + ? recurrenceDuration.inDays + : recurrenceDuration.inDays + 1; final int intervalCount = ((durationDifference ~/ dailyDayGap) * dailyDayGap) + (durationDifference % dailyDayGap == 0 ? 0 : dailyDayGap); @@ -312,21 +314,20 @@ class RecurrenceHelper { final List weeklyRule = rRule.split(weeklySeparator); final List weeklyByDayRules = _findWeeklyRule(weeklyRule); - final int weeklyByDayPos = weeklyByDayRules.isNotEmpty - ? int.parse(weeklyByDayRules[1]) - : -1; + final int weeklyByDayPos = + weeklyByDayRules.isNotEmpty ? int.parse(weeklyByDayRules[1]) : -1; final int recurrenceStartHour = recurrenceStartDate.hour; final int recurrenceStartMinute = recurrenceStartDate.minute; final int recurrenceStartSecond = recurrenceStartDate.second; - final int recurrenceCount = recurrenceCountString.isNotEmpty - ? int.parse(recurrenceCountString) - : 0; + final int recurrenceCount = + recurrenceCountString.isNotEmpty ? int.parse(recurrenceCountString) : 0; int tempCount = 0; - final int weeklyWeekGap = ruleArray.length > 4 && rRule.contains('INTERVAL') - ? int.parse(intervalCountString) - : 1; + final int weeklyWeekGap = + ruleArray.length > 4 && rRule.contains('INTERVAL') + ? int.parse(intervalCountString) + : 1; assert(weeklyByDayPos != -1, 'Invalid weekly recurrence rule'); final List weekDays = []; final String ruleDaysString = weeklyRule[weeklyByDayPos]; @@ -490,9 +491,10 @@ class RecurrenceHelper { /// NoEndDate specified rule returns empty collection issue fix. if (isSpecificDateRange) { - endDate = endDate == null || endDate.isAfter(specificEndDate) - ? specificEndDate - : endDate; + endDate = + endDate == null || endDate.isAfter(specificEndDate) + ? specificEndDate + : endDate; } DateTime addDate = recurrenceStartDate; @@ -506,18 +508,17 @@ class RecurrenceHelper { /// Calculate the total days between the recurrence start and visible /// start date. - int daysDifference = AppointmentHelper.getDifference( - startDate, - specificStartDate, - ).inDays; + int daysDifference = + AppointmentHelper.getDifference(startDate, specificStartDate).inDays; final DateTime recurrenceEndDate = addDate.add(recurrenceDuration); /// Calculate day difference between the recurrence start and end date. - final int durationDifference = isSameDate(recurrenceEndDate, addDate) - ? 0 - : recurrenceEndDate.hour > addDate.hour - ? recurrenceDuration.inDays - : recurrenceDuration.inDays + 1; + final int durationDifference = + isSameDate(recurrenceEndDate, addDate) + ? 0 + : recurrenceEndDate.hour > addDate.hour + ? recurrenceDuration.inDays + : recurrenceDuration.inDays + 1; /// Remove the duration day difference from total days difference because /// if the recurrence placed saturday, sunday and it duration is 2 days @@ -551,9 +552,10 @@ class RecurrenceHelper { /// Calculate and remove the interval week after the initial week on /// total days difference. - final int initialWeekGap = isOccurrenceInInitialWeek - ? 0 - : DateTime.daysPerWeek * (weeklyWeekGap - 1); + final int initialWeekGap = + isOccurrenceInInitialWeek + ? 0 + : DateTime.daysPerWeek * (weeklyWeekGap - 1); daysDifference -= initialWeekGap; /// Calculate the total valid weeks(sunday to saturday) in between the @@ -615,21 +617,22 @@ class RecurrenceHelper { tempCount++; } - addDate = addDate.weekday == DateTime.saturday - ? AppointmentHelper.addDaysWithTime( - addDate, - ((weeklyWeekGap - 1) * DateTime.daysPerWeek) + 1, - recurrenceStartHour, - recurrenceStartMinute, - recurrenceStartSecond, - ) - : AppointmentHelper.addDaysWithTime( - addDate, - 1, - recurrenceStartHour, - recurrenceStartMinute, - recurrenceStartSecond, - ); + addDate = + addDate.weekday == DateTime.saturday + ? AppointmentHelper.addDaysWithTime( + addDate, + ((weeklyWeekGap - 1) * DateTime.daysPerWeek) + 1, + recurrenceStartHour, + recurrenceStartMinute, + recurrenceStartSecond, + ) + : AppointmentHelper.addDaysWithTime( + addDate, + 1, + recurrenceStartHour, + recurrenceStartMinute, + recurrenceStartSecond, + ); } return recDateCollection; @@ -688,9 +691,10 @@ class RecurrenceHelper { recCount = int.parse(recurCount); } - final int monthlyMonthGap = ruleArray.length > 4 && intervalCount.isNotEmpty - ? int.parse(intervalCount) - : 1; + final int monthlyMonthGap = + ruleArray.length > 4 && intervalCount.isNotEmpty + ? int.parse(intervalCount) + : 1; DateTime? endDate; if (rRule.contains('UNTIL')) { endDate = getUntilEndDate(untilValue); @@ -717,9 +721,10 @@ class RecurrenceHelper { /// NoEndDate specified rule returns empty collection issue fix. if (isSpecificDateRange && !rRule.contains('COUNT')) { - endDate = endDate == null || endDate.isAfter(specificEndDate) - ? specificEndDate - : endDate; + endDate = + endDate == null || endDate.isAfter(specificEndDate) + ? specificEndDate + : endDate; final int addedDateMonth = addDate.month; final int addedDateYear = addDate.year; @@ -838,11 +843,12 @@ class RecurrenceHelper { } monthValue += monthlyMonthGap; - monthDate = byMonthDay == -1 - ? AppointmentHelper.getMonthEndDate( - DateTime(yearValue, monthValue), - ).day - : monthDate; + monthDate = + byMonthDay == -1 + ? AppointmentHelper.getMonthEndDate( + DateTime(yearValue, monthValue), + ).day + : monthDate; addDate = DateTime( yearValue, monthValue, @@ -1024,15 +1030,17 @@ class RecurrenceHelper { } } - final int yearlyYearGap = ruleArray.length > 4 && intervalCount.isNotEmpty - ? int.parse(intervalCount) - : 1; + final int yearlyYearGap = + ruleArray.length > 4 && intervalCount.isNotEmpty + ? int.parse(intervalCount) + : 1; /// NoEndDate specified rule returns empty collection issue fix. if (isSpecificDateRange && !rRule.contains('COUNT')) { - endDate = endDate == null || endDate.isAfter(specificEndDate) - ? specificEndDate - : endDate; + endDate = + endDate == null || endDate.isAfter(specificEndDate) + ? specificEndDate + : endDate; final int addedDateYear = addDate.year; final int viewStartDateYear = specificStartDate.year; @@ -1053,17 +1061,19 @@ class RecurrenceHelper { int dayIndex = int.parse(byMonthDayCount); final int byMonthDay = dayIndex; if (byMonthDay == -1) { - dayIndex = AppointmentHelper.getMonthEndDate( - DateTime(addDate.year, monthIndex), - ).day; + dayIndex = + AppointmentHelper.getMonthEndDate( + DateTime(addDate.year, monthIndex), + ).day; } if (monthIndex < 0 || monthIndex > 12) { return recDateCollection; } - final int daysInMonth = DateTimeHelper.getDateTimeValue( - addDays(DateTime(addDate.year, addDate.month + 1), -1), - ).day; + final int daysInMonth = + DateTimeHelper.getDateTimeValue( + addDays(DateTime(addDate.year, addDate.month + 1), -1), + ).day; if (daysInMonth < dayIndex) { return recDateCollection; } @@ -1110,11 +1120,12 @@ class RecurrenceHelper { recDateCollection.add(addDate); } - dayIndex = byMonthDay == -1 - ? AppointmentHelper.getMonthEndDate( - DateTime(addDate.year + yearlyYearGap, monthIndex), - ).day - : addDate.day; + dayIndex = + byMonthDay == -1 + ? AppointmentHelper.getMonthEndDate( + DateTime(addDate.year + yearlyYearGap, monthIndex), + ).day + : addDate.day; addDate = DateTime( addDate.year + yearlyYearGap, @@ -1312,15 +1323,13 @@ class RecurrenceHelper { final String byMonthDayCount = resultList[15]; final String byMonthCount = resultList[17]; final List weeklyRules = _findWeeklyRule(weeklyRule); - final int weeklyByDayPos = weeklyRules.isNotEmpty - ? int.parse(weeklyRules[1]) - : -1; + final int weeklyByDayPos = + weeklyRules.isNotEmpty ? int.parse(weeklyRules[1]) : -1; if (rRule.contains('COUNT')) { recProp.recurrenceRange = RecurrenceRange.count; - recProp.recurrenceCount = recurCount.isNotEmpty - ? int.parse(recurCount) - : 0; + recProp.recurrenceCount = + recurCount.isNotEmpty ? int.parse(recurCount) : 0; } else if (rRule.contains('UNTIL')) { recProp.recurrenceRange = RecurrenceRange.endDate; recProp.endDate = getUntilEndDate(untilValue); @@ -1369,9 +1378,8 @@ class RecurrenceHelper { recProp.recurrenceType = RecurrenceType.monthly; if (byMonthDay == 'BYMONTHDAY') { recProp.week = 0; - recProp.dayOfMonth = byMonthDayCount.isNotEmpty - ? int.parse(byMonthDayCount) - : 1; + recProp.dayOfMonth = + byMonthDayCount.isNotEmpty ? int.parse(byMonthDayCount) : 1; } else if (byDay == 'BYDAY') { recProp.week = bySetPosCount.isNotEmpty ? int.parse(bySetPosCount) : 0; recProp.dayOfWeek = byDayValue.isNotEmpty ? _getWeekDay(byDayValue) : 1; @@ -1380,9 +1388,8 @@ class RecurrenceHelper { recProp.recurrenceType = RecurrenceType.yearly; if (byMonthDay == 'BYMONTHDAY') { recProp.month = byMonthCount.isNotEmpty ? int.parse(byMonthCount) : 1; - recProp.dayOfMonth = byMonthDayCount.isNotEmpty - ? int.parse(byMonthDayCount) - : 1; + recProp.dayOfMonth = + byMonthDayCount.isNotEmpty ? int.parse(byMonthDayCount) : 1; } else if (byDay == 'BYDAY') { recProp.month = byMonthCount.isNotEmpty ? int.parse(byMonthCount) : 1; recProp.week = bySetPosCount.isNotEmpty ? int.parse(bySetPosCount) : 0; @@ -1561,8 +1568,8 @@ class RecurrenceHelper { if (addDate.weekday != DateTime.saturday) { byDay = byDay.isNotEmpty && byDay.substring(byDay.length - 1) == 'A' - ? '$byDay,$dayKey' - : byDay + dayKey; + ? '$byDay,$dayKey' + : byDay + dayKey; } else { byDay = byDay + dayKey; } @@ -1572,9 +1579,10 @@ class RecurrenceHelper { } else { prevDate = addDate; count++; - byDay = byDay.isNotEmpty && byDay.substring(byDay.length - 1) == 'A' - ? '$byDay,$dayKey' - : byDay + dayKey; + byDay = + byDay.isNotEmpty && byDay.substring(byDay.length - 1) == 'A' + ? '$byDay,$dayKey' + : byDay + dayKey; dayCount++; } @@ -1631,22 +1639,23 @@ class RecurrenceHelper { dayKey = ''; } - addDate = addDate.weekday == DateTime.saturday - ? AppointmentHelper.addDaysWithTime( - addDate, - ((recurrenceProperties.interval - 1) * DateTime.daysPerWeek) + - 1, - startDate.hour, - startDate.minute, - startDate.second, - ) - : AppointmentHelper.addDaysWithTime( - addDate, - 1, - startDate.hour, - startDate.minute, - startDate.second, - ); + addDate = + addDate.weekday == DateTime.saturday + ? AppointmentHelper.addDaysWithTime( + addDate, + ((recurrenceProperties.interval - 1) * DateTime.daysPerWeek) + + 1, + startDate.hour, + startDate.minute, + startDate.second, + ) + : AppointmentHelper.addDaysWithTime( + addDate, + 1, + startDate.hour, + startDate.minute, + startDate.second, + ); i = i + 1; } @@ -1831,9 +1840,10 @@ class RecurrenceHelper { ) { final DateTime recPropStartDate = recurrenceProperties.startDate; final DateTime? recPropEndDate = recurrenceProperties.endDate; - final DateTime startDate = appStartTime.isAfter(recPropStartDate) - ? appStartTime - : recPropStartDate; + final DateTime startDate = + appStartTime.isAfter(recPropStartDate) + ? appStartTime + : recPropStartDate; final DateTime? endDate = recPropEndDate; final Duration diffTimeSpan = AppointmentHelper.getDifference( appStartTime, @@ -2069,9 +2079,10 @@ class RecurrenceHelper { if (untilString.contains('T')) { /// Z specifies UTC timezone offset, Checks the time zone is provided in /// the until end date value. - final DateTime endDate = untilString.contains('Z') - ? DateTime.parse(untilString).toLocal() - : DateTime.parse(untilString); + final DateTime endDate = + untilString.contains('Z') + ? DateTime.parse(untilString).toLocal() + : DateTime.parse(untilString); return endDate; } else { DateTime endDate = DateTime.parse(untilString); diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart index b7f337f5a..e6ae270d2 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart @@ -234,8 +234,8 @@ class _AgendaViewLayoutState extends State { appointment.isSpanned; final double appointmentHeight = (appointment.isAllDay || isSpanned) && !isLargerScheduleUI - ? agendaAllDayItemHeight - : agendaItemHeight; + ? agendaAllDayItemHeight + : agendaItemHeight; final Rect rect = Rect.fromLTWH( padding, yPosition, @@ -802,9 +802,10 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { final List semanticsNodes = []; for (int i = 0; i < semantics.length; i++) { final CustomPainterSemantics currentSemantics = semantics[i]; - final SemanticsNode newChild = _cacheNodes!.isNotEmpty - ? _cacheNodes!.removeAt(0) - : SemanticsNode(key: currentSemantics.key); + final SemanticsNode newChild = + _cacheNodes!.isNotEmpty + ? _cacheNodes!.removeAt(0) + : SemanticsNode(key: currentSemantics.key); final SemanticsProperties properties = currentSemantics.properties; final SemanticsConfiguration config = SemanticsConfiguration(); @@ -920,25 +921,26 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { return; } - final TextStyle appointmentTextStyle = monthViewSettings != null - ? themeData.textTheme.bodyMedium! - .copyWith(color: Colors.white, fontSize: 13) - .merge(monthViewSettings!.agendaStyle.appointmentTextStyle) - : themeData.textTheme.bodyMedium! - .copyWith( - color: - isLargerScheduleUI && - themeData.brightness == Brightness.light - ? Colors.black87 - : Colors.white, - fontSize: 13, - ) - .merge(scheduleViewSettings!.appointmentTextStyle); + final TextStyle appointmentTextStyle = + monthViewSettings != null + ? themeData.textTheme.bodyMedium! + .copyWith(color: Colors.white, fontSize: 13) + .merge(monthViewSettings!.agendaStyle.appointmentTextStyle) + : themeData.textTheme.bodyMedium! + .copyWith( + color: + isLargerScheduleUI && + themeData.brightness == Brightness.light + ? Colors.black87 + : Colors.white, + fontSize: 13, + ) + .merge(scheduleViewSettings!.appointmentTextStyle); final List appointmentStringFormats = appointmentTimeTextFormat == null - ? [] - : CalendarViewHelper.getListFromString(appointmentTimeTextFormat!); + ? [] + : CalendarViewHelper.getListFromString(appointmentTimeTextFormat!); final List sameDateAppointmentStringFormats = CalendarViewHelper.getListFromString('hh:mm a'); final List diffDateAppointmentStringFormats = @@ -971,9 +973,8 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { style: appointmentTextStyle, ); _updateTextPainterProperties(span); - double timeWidth = isLargerScheduleUI - ? (size.width - (2 * padding)) * 0.3 - : 0; + double timeWidth = + isLargerScheduleUI ? (size.width - (2 * padding)) * 0.3 : 0; timeWidth = timeWidth > 200 ? 200 : timeWidth; xPosition += timeWidth; @@ -1126,11 +1127,12 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { // The value taken from framework, for text style when there is no font // size given they have used 14 as the default font size. const double defaultFontSize = 14; - final double textSize = isMobilePlatform - ? appointmentTextStyle.fontSize ?? defaultFontSize - : appointmentTextStyle.fontSize != null - ? appointmentTextStyle.fontSize! * 1.5 - : defaultFontSize * 1.5; + final double textSize = + isMobilePlatform + ? appointmentTextStyle.fontSize ?? defaultFontSize + : appointmentTextStyle.fontSize != null + ? appointmentTextStyle.fontSize! * 1.5 + : defaultFontSize * 1.5; if (rect.width < textSize || rect.height < textSize) { return rect.width > rect.height ? rect.height : rect.width; } @@ -1228,8 +1230,8 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { /// Top and bottom padding 5 const double verticalPadding = 10; - final int maxLines = ((appointmentHeight - verticalPadding) / lineHeight) - .floor(); + final int maxLines = + ((appointmentHeight - verticalPadding) / lineHeight).floor(); if (maxLines > 1) { _textPainter.maxLines = isSpanned || isAllDay ? maxLines : maxLines - 1; } @@ -1272,11 +1274,15 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { Offset(xPosition + padding, yPosition + topPadding), ); - final List format = appointmentFormatString.isEmpty - ? (isSameDate(appointment.actualStartTime, appointment.actualEndTime) - ? sameDateAppointmentFormatString - : diffDateAppointmentFormatString) - : appointmentFormatString; + final List format = + appointmentFormatString.isEmpty + ? (isSameDate( + appointment.actualStartTime, + appointment.actualEndTime, + ) + ? sameDateAppointmentFormatString + : diffDateAppointmentFormatString) + : appointmentFormatString; final String startDateText = CalendarViewHelper.getLocalizedString( appointment.actualStartTime, format, @@ -1333,10 +1339,8 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { _updateTextPainterProperties(span); _updatePainterLinesCount(appointmentHeight, isSpanned: true); - final bool isNeedSpanIcon = !isSameDate( - appointment.exactEndTime, - selectedDate, - ); + final bool isNeedSpanIcon = + !isSameDate(appointment.exactEndTime, selectedDate); final double textSize = _getTextSize( rect, appointmentTextStyle, @@ -1395,9 +1399,10 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { double padding, ) { final TextSpan span = TextSpan( - text: selectedDate == null - ? localizations.noSelectedDateCalendarLabel - : localizations.noEventsCalendarLabel, + text: + selectedDate == null + ? localizations.noSelectedDateCalendarLabel + : localizations.noEventsCalendarLabel, style: themeData.textTheme.bodyMedium!.merge(placeholderTextStyle), ); @@ -1438,9 +1443,8 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { ) { _textPainter.textScaler = TextScaler.linear(textScaleFactor); final double centerYPosition = appointmentHeight / 2; - final double circleRadius = centerYPosition > padding - ? padding - : centerYPosition - 2; + final double circleRadius = + centerYPosition > padding ? padding : centerYPosition - 2; final double circleStartPosition = offset.dx + (3 * circleRadius); canvas.drawCircle( Offset( @@ -1481,9 +1485,10 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { canvas, Offset(xPosition + padding, yPosition + topPadding), ); - final List format = appointmentFormatString.isEmpty - ? sameDateAppointmentFormatString - : appointmentFormatString; + final List format = + appointmentFormatString.isEmpty + ? sameDateAppointmentFormatString + : appointmentFormatString; final String startDateText = CalendarViewHelper.getLocalizedString( appointment.actualStartTime, format, @@ -1495,9 +1500,10 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject { locale, ); final TextSpan span = TextSpan( - text: appointment.isAllDay || appointment.isSpanned - ? _localizations.allDayLabel - : '$startDateText - $endDateText', + text: + appointment.isAllDay || appointment.isSpanned + ? _localizations.allDayLabel + : '$startDateText - $endDateText', style: appointmentTextStyle, ); _textPainter.text = span; diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/allday_appointment_layout.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/allday_appointment_layout.dart index 13800f46c..c2c89fbe1 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/allday_appointment_layout.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/allday_appointment_layout.dart @@ -168,9 +168,10 @@ class _AllDayAppointmentLayoutState extends State { appointmentView.appointment!.actualStartTime.month, appointmentView.appointment!.actualStartTime.day, ); - final DateTime date = appStartTime.isBefore(initialVisibleDate) - ? initialVisibleDate - : appStartTime; + final DateTime date = + appStartTime.isBefore(initialVisibleDate) + ? initialVisibleDate + : appStartTime; final Widget child = widget.calendar.appointmentBuilder!( context, @@ -291,9 +292,10 @@ class _AllDayAppointmentLayoutState extends State { _updateCalendarStateDetails.allDayAppointmentViewCollection; final double cellWidth = (widget.width - widget.timeLabelWidth) / widget.visibleDates.length; - const double cornerRadius = (kAllDayAppointmentHeight * 0.1) > 2 - ? 2 - : kAllDayAppointmentHeight * 0.1; + const double cornerRadius = + (kAllDayAppointmentHeight * 0.1) > 2 + ? 2 + : kAllDayAppointmentHeight * 0.1; final double cellEndPadding = CalendarViewHelper.getCellEndPadding( widget.calendar.cellEndPadding, @@ -380,14 +382,15 @@ class _AllDayAppointmentLayoutState extends State { if (_appointmentCollection.isNotEmpty) { /// Calculate the maximum appointment position of all the appointment /// views in the widget. - maxPosition = _appointmentCollection - .reduce( - (AppointmentView currentAppView, AppointmentView nextAppView) => - currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + maxPosition = + _appointmentCollection + .reduce( + (AppointmentView currentAppView, AppointmentView nextAppView) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } if (maxPosition == -1) { @@ -405,14 +408,18 @@ class _AllDayAppointmentLayoutState extends State { int count = 0; if (appointmentViews.isNotEmpty) { /// Calculate the current index appointments max position. - maxPosition = appointmentViews - .reduce( - (AppointmentView currentAppView, AppointmentView nextAppView) => - currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + maxPosition = + appointmentViews + .reduce( + ( + AppointmentView currentAppView, + AppointmentView nextAppView, + ) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } if (maxPosition <= position) { continue; @@ -908,9 +915,11 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { } final int index = keys[i]; - final double leftPosition = isRTL - ? ((visibleDates.length - index - 1) * _cellWidth) + cellEndPadding - : timeLabelWidth + (index * _cellWidth); + final double leftPosition = + isRTL + ? ((visibleDates.length - index - 1) * _cellWidth) + + cellEndPadding + : timeLabelWidth + (index * _cellWidth); final Offset offset = Offset(leftPosition, maximumBottomPosition); final bool isHit = result.addWithPaintOffset( offset: offset, @@ -1014,9 +1023,11 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { final CalendarParentData childParentData = child.parentData! as CalendarParentData; final int index = keys[i]; - final double leftPosition = isRTL - ? ((visibleDates.length - index - 1) * _cellWidth) + cellEndPadding - : timeLabelWidth + (index * _cellWidth); + final double leftPosition = + isRTL + ? ((visibleDates.length - index - 1) * _cellWidth) + + cellEndPadding + : timeLabelWidth + (index * _cellWidth); childParentData.offset = Offset(leftPosition, maximumBottomPosition); child = childAfter(child); } @@ -1082,14 +1093,15 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { const double textPadding = 3; _maxPosition = 0; if (appointmentCollection.isNotEmpty) { - _maxPosition = appointmentCollection - .reduce( - (AppointmentView currentAppView, AppointmentView nextAppView) => - currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + _maxPosition = + appointmentCollection + .reduce( + (AppointmentView currentAppView, AppointmentView nextAppView) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } if (_maxPosition == -1) { @@ -1152,34 +1164,11 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { _addSelectionForAllDayPanel(context.canvas, size); } - if (isExpandable && _maxPosition > position && !isExpanding) { - if (child != null) { - final double endYPosition = - allDayPainterHeight - kAllDayAppointmentHeight; - final double cellEndPadding = CalendarViewHelper.getCellEndPadding( - calendar.cellEndPadding, - isMobilePlatform, - ); - final List keys = moreAppointmentIndex.keys.toList(); - for (final int index in keys) { - if (child == null) { - continue; - } - - final double xPosition = isRTL - ? ((visibleDates.length - index - 1) * _cellWidth) + - cellEndPadding - : timeLabelWidth + (index * _cellWidth); - context.paintChild(child, Offset(xPosition, endYPosition)); - child = childAfter(child); - } - } else { - _addExpanderText(context.canvas, position, textPadding); - } - } - if (isExpandable) { _addExpandOrCollapseIcon(context.canvas, size, position); + if (_maxPosition > position && !isExpanding) { + _addExpanderText(context.canvas, position, textPadding); + } } if (!_isHoveringAppointment) { @@ -1292,8 +1281,8 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { appointment.recurrenceRule!.isNotEmpty; final double recurrenceIconSize = isRecurrenceAppointment || appointment.recurrenceId != null - ? iconSize - : 0; + ? iconSize + : 0; double forwardSpanIconSize = 0; double backwardSpanIconSize = 0; @@ -1340,16 +1329,21 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { recurrenceIconSize + forwardSpanIconSize + backwardSpanIconSize; const double textPadding = 1; _textPainter.layout( - maxWidth: rect.width - totalIconSize - (2 * textPadding) >= 0 - ? rect.width - totalIconSize - (2 * textPadding) - : 0, + maxWidth: + rect.width - totalIconSize - (2 * textPadding) >= 0 + ? rect.width - totalIconSize - (2 * textPadding) + : 0, ); if (_textPainter.maxLines == 1 && _textPainter.height > rect.height) { return; } - final double xPosition = isRTL - ? rect.right - _textPainter.width - backwardSpanIconSize - textPadding - : rect.left + backwardSpanIconSize + textPadding; + final double xPosition = + isRTL + ? rect.right - + _textPainter.width - + backwardSpanIconSize - + textPadding + : rect.left + backwardSpanIconSize + textPadding; _textPainter.paint( context.canvas, Offset(xPosition, rect.top + (rect.height - _textPainter.height) / 2), @@ -1453,8 +1447,8 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { Offset( isRTL ? ((visibleDates.length - index) * _cellWidth) - - _textPainter.width - - textPadding + _textPainter.width - + textPadding : timeLabelWidth + (index * _cellWidth) + textPadding, endYPosition + ((kAllDayAppointmentHeight - _textPainter.height) / 2), ), @@ -1463,18 +1457,19 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { } void _addExpandOrCollapseIcon(Canvas canvas, Size size, int position) { - final int iconCodePoint = _maxPosition <= position - ? Icons.expand_less.codePoint - : Icons.expand_more.codePoint; + final int iconCodePoint = + _maxPosition <= position + ? Icons.expand_less.codePoint + : Icons.expand_more.codePoint; final TextSpan icon = TextSpan( text: String.fromCharCode(iconCodePoint), style: TextStyle( color: calendarTheme.viewHeaderDayTextStyle!.color, fontSize: calendar.viewHeaderStyle.dayTextStyle != null && - calendar.viewHeaderStyle.dayTextStyle!.fontSize != null - ? calendar.viewHeaderStyle.dayTextStyle!.fontSize! * 2 - : kAllDayAppointmentHeight + 5, + calendar.viewHeaderStyle.dayTextStyle!.fontSize != null + ? calendar.viewHeaderStyle.dayTextStyle!.fontSize! * 2 + : kAllDayAppointmentHeight + 5, fontFamily: 'MaterialIcons', ), ); @@ -1486,7 +1481,7 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { Offset( isRTL ? (size.width - timeLabelWidth) + - ((timeLabelWidth - _expanderTextPainter.width) / 2) + ((timeLabelWidth - _expanderTextPainter.width) / 2) : (timeLabelWidth - _expanderTextPainter.width) / 2, allDayPainterHeight - kAllDayAppointmentHeight + @@ -1531,9 +1526,10 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { appointmentView.startIndex <= index && appointmentView.endIndex > index) { selectionDecoration ??= BoxDecoration( - color: themeData.brightness == Brightness.light - ? Colors.white.withValues(alpha: 0.3) - : Colors.black.withValues(alpha: 0.4), + color: + themeData.brightness == Brightness.light + ? Colors.white.withValues(alpha: 0.3) + : Colors.black.withValues(alpha: 0.4), border: Border.all( color: calendarTheme.selectionBorderColor!, width: 2, @@ -1703,9 +1699,10 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { final List semanticsNodes = []; for (int i = 0; i < semantics.length; i++) { final CustomPainterSemantics currentSemantics = semantics[i]; - final SemanticsNode newChild = _cacheNodes!.isNotEmpty - ? _cacheNodes!.removeAt(0) - : SemanticsNode(key: currentSemantics.key); + final SemanticsNode newChild = + _cacheNodes!.isNotEmpty + ? _cacheNodes!.removeAt(0) + : SemanticsNode(key: currentSemantics.key); final SemanticsProperties properties = currentSemantics.properties; final SemanticsConfiguration config = SemanticsConfiguration(); @@ -1772,8 +1769,8 @@ class _AllDayAppointmentRenderObject extends CustomCalendarRenderObject { properties: SemanticsProperties( label: _maxPosition <= allDayPainterHeight ~/ kAllDayAppointmentHeight - ? 'Collapse all day section' - : 'Expand all day section', + ? 'Collapse all day section' + : 'Expand all day section', textDirection: TextDirection.ltr, ), ), diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart index 84daa9697..a51c09531 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart @@ -224,11 +224,12 @@ class _AppointmentLayoutState extends State { appointmentView.appointment!.actualStartTime.month, appointmentView.appointment!.actualStartTime.day, ); - final DateTime date = appointmentView.startIndex != -1 - ? widget.visibleDates[appointmentView.startIndex] - : appStartTime.isBefore(initialVisibleDate) - ? initialVisibleDate - : appStartTime; + final DateTime date = + appointmentView.startIndex != -1 + ? widget.visibleDates[appointmentView.startIndex] + : appStartTime.isBefore(initialVisibleDate) + ? initialVisibleDate + : appStartTime; final Widget child = widget.calendar.appointmentBuilder!( context, @@ -389,14 +390,14 @@ class _AppointmentLayoutState extends State { } final List appointments = []; - final int viewStartHour = widget.calendar.timeSlotViewSettings.startHour - .toInt(); + final int viewStartHour = + widget.calendar.timeSlotViewSettings.startHour.toInt(); final int viewStartMinutes = (viewStartHour * 60) + ((widget.calendar.timeSlotViewSettings.startHour - viewStartHour) * 60) .toInt(); - final int viewEndHour = widget.calendar.timeSlotViewSettings.endHour - .toInt(); + final int viewEndHour = + widget.calendar.timeSlotViewSettings.endHour.toInt(); final int viewEndMinutes = (viewEndHour * 60) + ((widget.calendar.timeSlotViewSettings.endHour - viewEndHour) * 60) @@ -512,9 +513,10 @@ class _AppointmentLayoutState extends State { return; } - double xPosition = widget.isRTL - ? widget.width - cellWidth - _weekNumberPanelWidth - : _weekNumberPanelWidth; + double xPosition = + widget.isRTL + ? widget.width - cellWidth - _weekNumberPanelWidth + : _weekNumberPanelWidth; double yPosition = 0; final int count = widget.visibleDates.length; DateTime visibleStartDate = AppointmentHelper.convertToStartTime( @@ -649,14 +651,15 @@ class _AppointmentLayoutState extends State { final List keys = _indexAppointments.keys.toList(); for (int i = 0; i < keys.length; i++) { final int index = keys[i]; - final int maxPosition = _indexAppointments[index]! - .reduce( - (AppointmentView currentAppView, AppointmentView nextAppView) => - currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + final int maxPosition = + _indexAppointments[index]! + .reduce( + (AppointmentView currentAppView, AppointmentView nextAppView) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; if (maxPosition <= maximumDisplayCount) { continue; } @@ -714,8 +717,8 @@ class _AppointmentLayoutState extends State { final int timeInterval = CalendarViewHelper.getTimeInterval( widget.calendar.timeSlotViewSettings, ); - final int viewStartHour = widget.calendar.timeSlotViewSettings.startHour - .toInt(); + final int viewStartHour = + widget.calendar.timeSlotViewSettings.startHour.toInt(); final double viewStartMinutes = (widget.calendar.timeSlotViewSettings.startHour - viewStartHour) * 60; @@ -908,9 +911,8 @@ class _AppointmentLayoutState extends State { widget.calendar.cellEndPadding, widget.isMobilePlatform, ); - final double slotHeight = isResourceEnabled - ? widget.resourceItemHeight! - : widget.height; + final double slotHeight = + isResourceEnabled ? widget.resourceItemHeight! : widget.height; final double timelineAppointmentHeight = _getTimelineAppointmentHeight( widget.calendar.timeSlotViewSettings, widget.view, @@ -1078,17 +1080,18 @@ class _AppointmentLayoutState extends State { widget.calendar.cellEndPadding, widget.isMobilePlatform, ); - final int viewStartHour = widget.calendar.timeSlotViewSettings.startHour - .toInt(); + final int viewStartHour = + widget.calendar.timeSlotViewSettings.startHour.toInt(); final double viewStartMinutes = (widget.calendar.timeSlotViewSettings.startHour - viewStartHour) * 60; final double timelineAppointmentHeight = _getTimelineAppointmentHeight( widget.calendar.timeSlotViewSettings, widget.view, ); - final double slotHeight = isResourceEnabled - ? widget.resourceItemHeight! - cellEndPadding - : widget.height - cellEndPadding; + final double slotHeight = + isResourceEnabled + ? widget.resourceItemHeight! - cellEndPadding + : widget.height - cellEndPadding; for (int i = 0; i < _appointmentCollection.length; i++) { final AppointmentView appointmentView = _appointmentCollection[i]; if (appointmentView.canReuse || appointmentView.appointment == null) { @@ -2060,8 +2063,8 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { final double iconSize = iconTextSize + (2 * iconPadding); final double recurrenceIconSize = isRecurrenceAppointment || appointment.recurrenceId != null - ? iconSize - : 0; + ? iconSize + : 0; double forwardSpanIconSize = 0; double backwardSpanIconSize = 0; @@ -2121,9 +2124,10 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { radius = 3; } } - double startXPosition = isRTL - ? moreRegionRect.right - startPadding - : moreRegionRect.left + startPadding; + double startXPosition = + isRTL + ? moreRegionRect.right - startPadding + : moreRegionRect.left + startPadding; paint.color = Colors.grey[600]!; for (int j = 0; j < 3; j++) { canvas.drawCircle( @@ -2161,19 +2165,19 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { recurrenceIconSize + forwardSpanIconSize + backwardSpanIconSize; final double textWidth = appointmentRect.width - totalIconsWidth; _textPainter.layout( - maxWidth: textWidth - (2 * textPadding) > 0 - ? textWidth - (2 * textPadding) - : 0, + maxWidth: + textWidth - (2 * textPadding) > 0 ? textWidth - (2 * textPadding) : 0, ); final double yPosition = appointmentRect.top + ((appointmentRect.height - _textPainter.height) / 2); - final double xPosition = isRTL - ? appointmentRect.right - - _textPainter.width - - backwardSpanIconSize - - textPadding - : appointmentRect.left + backwardSpanIconSize + textPadding; + final double xPosition = + isRTL + ? appointmentRect.right - + _textPainter.width - + backwardSpanIconSize - + textPadding + : appointmentRect.left + backwardSpanIconSize + textPadding; _textPainter.paint(canvas, Offset(xPosition, yPosition)); @@ -2312,9 +2316,10 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { _textPainter.layout(maxWidth: rect.width > 0 ? rect.width : 0); final double yPosition = rect.top + ((rect.height - _textPainter.height) / 2); - final double recurrenceStartPosition = isRTL - ? rect.left + forwardSpanIconSize - : rect.right - iconSize - forwardSpanIconSize; + final double recurrenceStartPosition = + isRTL + ? rect.left + forwardSpanIconSize + : rect.right - iconSize - forwardSpanIconSize; canvas.drawRRect( RRect.fromRectAndRadius( Rect.fromLTRB( @@ -2344,15 +2349,15 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { double cellHeight, Paint paint, ) { - double xPosition = isRTL - ? size.width - cellWidth - weekNumberPanelWidth - : weekNumberPanelWidth; + double xPosition = + isRTL + ? size.width - cellWidth - weekNumberPanelWidth + : weekNumberPanelWidth; double yPosition = 0; const double radius = 2.5; const double diameter = radius * 2; - final double bottomPadding = cellHeight * 0.2 < radius - ? radius - : cellHeight * 0.2; + final double bottomPadding = + cellHeight * 0.2 < radius ? radius : cellHeight * 0.2; final int visibleDatesCount = visibleDates.length; final int currentMonth = visibleDates[visibleDatesCount ~/ 2].month; final bool showTrailingLeadingDates = @@ -2393,9 +2398,9 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { ); final int count = appointmentLists.length <= - calendar.monthViewSettings.appointmentDisplayCount - ? appointmentLists.length - : calendar.monthViewSettings.appointmentDisplayCount; + calendar.monthViewSettings.appointmentDisplayCount + ? appointmentLists.length + : calendar.monthViewSettings.appointmentDisplayCount; const double indicatorPadding = 2; final double indicatorWidth = count * diameter + (count - 1) * indicatorPadding; @@ -2883,12 +2888,13 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { continue; } - final double xPosition = isRTL - ? appointmentRect.right - - backwardSpanIconSize - - _textPainter.width - - textStartPadding - : appointmentRect.left + backwardSpanIconSize + textStartPadding; + final double xPosition = + isRTL + ? appointmentRect.right - + backwardSpanIconSize - + _textPainter.width - + textStartPadding + : appointmentRect.left + backwardSpanIconSize + textStartPadding; final int maxLines = (appointmentRect.height / _textPainter.preferredLineHeight).floor(); final bool isRecurrenceAppointment = @@ -3029,9 +3035,10 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { _textScaleFactor, ); _textPainter.layout(maxWidth: maxWidth); - final double xPosition = isRTL - ? rect.left + xPadding - : rect.right - _textPainter.width - xPadding; + final double xPosition = + isRTL + ? rect.left + xPadding + : rect.right - _textPainter.width - xPadding; final double yPosition = _getYPositionForSpanIconInTimeline( icon, @@ -3078,9 +3085,10 @@ class _AppointmentRenderObject extends CustomCalendarRenderObject { _textScaleFactor, ); _textPainter.layout(maxWidth: maxWidth); - final double xPosition = isRTL - ? rect.right - _textPainter.width - xPadding - : rect.left + xPadding; + final double xPosition = + isRTL + ? rect.right - _textPainter.width - xPadding + : rect.left + xPadding; final double yPosition = _getYPositionForSpanIconInTimeline( icon, diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart index 220a0b667..759ad3968 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart @@ -280,12 +280,12 @@ class CalendarViewHelper { ) { return monthViewSettings != null ? (monthViewSettings.agendaItemHeight == -1 - ? 50 - : monthViewSettings.agendaItemHeight) + ? 50 + : monthViewSettings.agendaItemHeight) : (scheduleViewSettings == null || - scheduleViewSettings.appointmentItemHeight == -1 - ? 50 - : scheduleViewSettings.appointmentItemHeight); + scheduleViewSettings.appointmentItemHeight == -1 + ? 50 + : scheduleViewSettings.appointmentItemHeight); } /// Return schedule view all day appointment height and its value based on @@ -296,12 +296,12 @@ class CalendarViewHelper { ) { return monthViewSettings != null ? (monthViewSettings.agendaItemHeight == -1 - ? 25 - : monthViewSettings.agendaItemHeight) + ? 25 + : monthViewSettings.agendaItemHeight) : (scheduleViewSettings == null || - scheduleViewSettings.appointmentItemHeight == -1 - ? 25 - : scheduleViewSettings.appointmentItemHeight); + scheduleViewSettings.appointmentItemHeight == -1 + ? 25 + : scheduleViewSettings.appointmentItemHeight); } /// Returns the height for an resource item to render the resource within @@ -754,8 +754,8 @@ class CalendarViewHelper { ) { if (appointment.recurrenceRule != null && appointment.recurrenceRule!.isNotEmpty) { - final Appointment appointmentObject = appointment - .convertToCalendarAppointment(); + final Appointment appointmentObject = + appointment.convertToCalendarAppointment(); if (appointment.data is Appointment) { return appointmentObject; } else { diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/date_time_engine.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/date_time_engine.dart index f7c751370..f8df67538 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/date_time_engine.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/date_time_engine.dart @@ -69,8 +69,8 @@ class DateTimeHelper { return numberOfWeeksInView == 6 ? DateTimeHelper.getDateTimeValue(getNextMonthDate(date)) : DateTimeHelper.getDateTimeValue( - addDays(date, numberOfWeeksInView * DateTime.daysPerWeek), - ); + addDays(date, numberOfWeeksInView * DateTime.daysPerWeek), + ); } case CalendarView.timelineMonth: return DateTimeHelper.getDateTimeValue(getNextMonthDate(date)); @@ -82,9 +82,8 @@ class DateTimeHelper { case CalendarView.workWeek: case CalendarView.timelineWorkWeek: { - final int nonWorkingDaysCount = nonWorkingDays == null - ? 0 - : nonWorkingDays.length; + final int nonWorkingDaysCount = + nonWorkingDays == null ? 0 : nonWorkingDays.length; if (visibleDatesCount + nonWorkingDaysCount == 7) { return DateTimeHelper.getDateTimeValue( addDays(date, visibleDatesCount + nonWorkingDaysCount), @@ -126,8 +125,8 @@ class DateTimeHelper { return numberOfWeeksInView == 6 ? DateTimeHelper.getDateTimeValue(getPreviousMonthDate(date)) : DateTimeHelper.getDateTimeValue( - addDays(date, -numberOfWeeksInView * DateTime.daysPerWeek), - ); + addDays(date, -numberOfWeeksInView * DateTime.daysPerWeek), + ); } case CalendarView.timelineMonth: return DateTimeHelper.getDateTimeValue(getPreviousMonthDate(date)); @@ -139,9 +138,8 @@ class DateTimeHelper { case CalendarView.workWeek: case CalendarView.timelineWorkWeek: { - final int nonWorkingDaysCount = nonWorkingDays == null - ? 0 - : nonWorkingDays.length; + final int nonWorkingDaysCount = + nonWorkingDays == null ? 0 : nonWorkingDays.length; if (visibleDatesCount + nonWorkingDaysCount == 7) { return DateTimeHelper.getDateTimeValue( addDays(date, -visibleDatesCount - nonWorkingDaysCount), @@ -422,10 +420,8 @@ class DateTimeHelper { /// Returns week number for the given date. static int getWeekNumberOfYear(DateTime date) { final DateTime yearEndDate = DateTime(date.year - 1, 12, 31); - final int dayOfYear = AppointmentHelper.getDifference( - yearEndDate, - date, - ).inDays; + final int dayOfYear = + AppointmentHelper.getDifference(yearEndDate, date).inDays; int weekNumber = (dayOfYear - date.weekday + 10) ~/ 7; if (weekNumber < 1) { weekNumber = getWeeksInYear(date.year - 1); diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/resource_view/resource_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/resource_view/resource_view.dart index a44c43160..76aff4c11 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/resource_view/resource_view.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/resource_view/resource_view.dart @@ -461,11 +461,11 @@ class _ResourceViewRenderObject extends CustomCalendarRenderObject { child = childAfter(child); if (mouseHoverPosition != null) { - final Color resourceHoveringColor = - (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + final Color resourceHoveringColor = (themeData.brightness == + Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); _addHovering(context.canvas, size, yPosition, resourceHoveringColor); } @@ -488,16 +488,16 @@ class _ResourceViewRenderObject extends CustomCalendarRenderObject { final double actualItemHeight = resourceItemHeight * 0.80; double yPosition = 0; _circlePainter.isAntiAlias = true; - final double radius = actualItemHeight < actualItemWidth - ? actualItemHeight / 2 - : actualItemWidth / 2; + final double radius = + actualItemHeight < actualItemWidth + ? actualItemHeight / 2 + : actualItemWidth / 2; final Color resourceCellBorderColor = cellBorderColor ?? calendarTheme.cellBorderColor!; - final Color resourceHoveringColor = - (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + final Color resourceHoveringColor = (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); final TextStyle displayNameTextStyle = calendarTheme.displayNameTextStyle!; _circlePainter.color = resourceCellBorderColor; _circlePainter.strokeWidth = 0.5; @@ -661,12 +661,13 @@ class _ResourceViewRenderObject extends CustomCalendarRenderObject { _updateNamePainter(span); _namePainter.layout(maxWidth: size.width); final double startXPosition = (size.width - _namePainter.width) / 2; - final double startYPosition = resourceViewSettings.showAvatar - ? (yPosition + (actualItemHeight / 2)) + - _borderThickness + - radius + - (_borderThickness / 2) - : yPosition + ((resourceItemHeight - _namePainter.height) / 2); + final double startYPosition = + resourceViewSettings.showAvatar + ? (yPosition + (actualItemHeight / 2)) + + _borderThickness + + radius + + (_borderThickness / 2) + : yPosition + ((resourceItemHeight - _namePainter.height) / 2); _namePainter.paint(canvas, Offset(startXPosition, startYPosition)); } @@ -744,9 +745,10 @@ class _ResourceViewRenderObject extends CustomCalendarRenderObject { actualItemWidth - (_borderThickness * 2) - (padding * 2); final double innerCircleHeight = actualItemHeight - (_borderThickness * 2) - (padding * 2); - final double innerRadius = innerCircleWidth > innerCircleHeight - ? innerCircleHeight / 2 - : innerCircleWidth / 2; + final double innerRadius = + innerCircleWidth > innerCircleHeight + ? innerCircleHeight / 2 + : innerCircleWidth / 2; final double innerCircleXPosition = (size.width - actualItemWidth) / 2 + _borderThickness + padding; final double innerCircleYPosition = @@ -772,9 +774,10 @@ class _ResourceViewRenderObject extends CustomCalendarRenderObject { _circlePainter, ); final List splitName = resource.displayName.split(' '); - final String shortName = splitName.length > 1 - ? splitName[0].substring(0, 1) + splitName[1].substring(0, 1) - : splitName[0].substring(0, 1); + final String shortName = + splitName.length > 1 + ? splitName[0].substring(0, 1) + splitName[1].substring(0, 1) + : splitName[0].substring(0, 1); final TextSpan span = TextSpan( text: shortName, style: themeData.textTheme.bodyLarge!.copyWith( diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart index b3b844ff9..c93e49568 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart @@ -3067,8 +3067,8 @@ class _SfCalendarState extends State } _forwardWidgetHeights = {}; _backwardWidgetHeights = {}; - _agendaScrollController = ScrollController() - ..addListener(_handleScheduleViewScrolled); + _agendaScrollController = + ScrollController()..addListener(_handleScheduleViewScrolled); _scheduleMaxDate = null; _scheduleMinDate = null; _minDate = null; @@ -3190,12 +3190,14 @@ class _SfCalendarState extends State ); return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - _minWidth = constraints.maxWidth == double.infinity - ? _minWidth - : constraints.maxWidth; - _minHeight = constraints.maxHeight == double.infinity - ? _minHeight - : constraints.maxHeight; + _minWidth = + constraints.maxWidth == double.infinity + ? _minWidth + : constraints.maxWidth; + _minHeight = + constraints.maxHeight == double.infinity + ? _minHeight + : constraints.maxHeight; _isMobilePlatform = CalendarViewHelper.isMobileLayout( Theme.of(context).platform, @@ -3240,19 +3242,20 @@ class _SfCalendarState extends State height -= widget.headerHeight; final double agendaHeight = _view == CalendarView.month && widget.monthViewSettings.showAgenda - ? _getMonthAgendaHeight() - : 0; + ? _getMonthAgendaHeight() + : 0; return GestureDetector( child: Container( width: _minWidth, height: _minHeight, color: widget.backgroundColor ?? _calendarTheme.backgroundColor, - child: _view == CalendarView.schedule - ? widget.loadMoreWidgetBuilder == null - ? addAgenda(height, _isRTL) - : addAgendaWithLoadMore(height, _isRTL) - : _addChildren(agendaHeight, height, _minWidth, _isRTL), + child: + _view == CalendarView.schedule + ? widget.loadMoreWidgetBuilder == null + ? addAgenda(height, _isRTL) + : addAgendaWithLoadMore(height, _isRTL) + : _addChildren(agendaHeight, height, _minWidth, _isRTL), ), onTap: () { _removeDatePicker(); @@ -3304,16 +3307,16 @@ class _SfCalendarState extends State if (_selectedDate != null) { currentSelectedDate = isDateWithInDateRange( - widget.minDate, - widget.maxDate, - _selectedDate, - ) && - !CalendarViewHelper.isDateInDateCollection( - _blackoutDates, - _selectedDate!, - ) - ? _selectedDate - : null; + widget.minDate, + widget.maxDate, + _selectedDate, + ) && + !CalendarViewHelper.isDateInDateCollection( + _blackoutDates, + _selectedDate!, + ) + ? _selectedDate + : null; } if (currentSelectedDate == null) { @@ -3360,9 +3363,8 @@ class _SfCalendarState extends State widget.dataSource, _view, ); - final double resourceViewSize = isResourceEnabled - ? widget.resourceViewSettings.size - : 0; + final double resourceViewSize = + isResourceEnabled ? widget.resourceViewSettings.size : 0; if ((!_isRTL && updatedPosition.dx < resourceViewSize) || (_isRTL && updatedPosition.dx > _minWidth - resourceViewSize)) { final double viewHeaderHeight = @@ -3473,27 +3475,27 @@ class _SfCalendarState extends State } } - final DateTime startDate = yPosition >= 0 - ? _nextDates[index] - : _previousDates[index]; + final DateTime startDate = + yPosition >= 0 ? _nextDates[index] : _previousDates[index]; /// Set previous date form it date collection if index is first index of /// next dates collection then get the start date from previous dates. /// If the index as last index of previous dates collection then calculate /// by subtract the 7 days to get previous date. - final DateTime prevDate = yPosition >= 0 && index == 0 - ? _previousDates.isEmpty - ? DateTimeHelper.getDateTimeValue( + final DateTime prevDate = + yPosition >= 0 && index == 0 + ? _previousDates.isEmpty + ? DateTimeHelper.getDateTimeValue( addDays(startDate, -DateTime.daysPerWeek), ) - : _previousDates[0] - : (yPosition >= 0 && index > 0 - ? _nextDates[index - 1] - : index >= _previousDates.length - 1 - ? DateTimeHelper.getDateTimeValue( + : _previousDates[0] + : (yPosition >= 0 && index > 0 + ? _nextDates[index - 1] + : index >= _previousDates.length - 1 + ? DateTimeHelper.getDateTimeValue( addDays(startDate, -DateTime.daysPerWeek), ) - : _previousDates[index + 1]); + : _previousDates[index + 1]); final DateTime prevEndDate = DateTimeHelper.getDateTimeValue( addDays(prevDate, 6), ); @@ -3642,9 +3644,8 @@ class _SfCalendarState extends State /// assign the label maximum height as 60. double appointmentViewHeaderHeight = appointmentViewHeight + (2 * padding); if (_useMobilePlatformUI) { - appointmentViewHeaderHeight = appointmentViewHeaderHeight > 60 - ? 60 - : appointmentViewHeaderHeight; + appointmentViewHeaderHeight = + appointmentViewHeaderHeight > 60 ? 60 : appointmentViewHeaderHeight; } /// Check the week date needs month header at in between the appointment @@ -3658,16 +3659,18 @@ class _SfCalendarState extends State /// Check the end date month have appointments or not. bool isNextMonthHasNoAppointment = false; if (isNeedInBetweenMonthBuilder) { - final DateTime? lastAppointmentDate = dateAppointmentKeys.isNotEmpty - ? dateAppointmentKeys[dateAppointmentKeys.length - 1] - : null; - final DateTime? nextWeekDate = index == -1 - ? _nextDates[0] - : (index < 0 - ? _previousDates[-index - 2] - : index >= _nextDates.length - 1 - ? null - : _nextDates[index + 1]); + final DateTime? lastAppointmentDate = + dateAppointmentKeys.isNotEmpty + ? dateAppointmentKeys[dateAppointmentKeys.length - 1] + : null; + final DateTime? nextWeekDate = + index == -1 + ? _nextDates[0] + : (index < 0 + ? _previousDates[-index - 2] + : index >= _nextDates.length - 1 + ? null + : _nextDates[index + 1]); /// Check the following scenarios for rendering month label at last when /// the week holds different month dates @@ -3885,9 +3888,9 @@ class _SfCalendarState extends State widget.dataSource != null && !AppointmentHelper.isCalendarAppointment(widget.dataSource!) ? CalendarViewHelper.getCustomAppointments( - currentAppointments, - widget.dataSource, - ) + currentAppointments, + widget.dataSource, + ) : currentAppointments, DateTime(currentDate.year, currentDate.month, currentDate.day), CalendarElement.viewHeader, @@ -3916,9 +3919,9 @@ class _SfCalendarState extends State widget.dataSource!, ) ? CalendarViewHelper.getCustomAppointments( - selectedAppointment, - widget.dataSource, - ) + selectedAppointment, + widget.dataSource, + ) : selectedAppointment, DateTime(currentDate.year, currentDate.month, currentDate.day), CalendarElement.appointment, @@ -4119,11 +4122,12 @@ class _SfCalendarState extends State selectionBorderColor: calendarThemeData.selectionBorderColor ?? effectiveThemeData.selectionBorderColor, - blackoutDatesTextStyle: calendarThemeData.blackoutDatesTextStyle == null - ? widget.blackoutDatesTextStyle - : calendarThemeData.blackoutDatesTextStyle?.merge( - widget.blackoutDatesTextStyle, - ), + blackoutDatesTextStyle: + calendarThemeData.blackoutDatesTextStyle == null + ? widget.blackoutDatesTextStyle + : calendarThemeData.blackoutDatesTextStyle?.merge( + widget.blackoutDatesTextStyle, + ), trailingDatesTextStyle: themeData.textTheme.bodyMedium! .copyWith( color: colorScheme.onSurface.withValues(alpha: 0.54), @@ -4350,12 +4354,11 @@ class _SfCalendarState extends State for (int i = 0; i < _forwardWidgetHeights.length; i++) { final _ScheduleViewDetails? details = _forwardWidgetHeights.containsKey(i) - ? _forwardWidgetHeights[i] - : null; + ? _forwardWidgetHeights[i] + : null; final double widgetHeight = details == null ? 0 : details._height; - final double interSectionPoint = details == null - ? -1 - : details._intersectPoint; + final double interSectionPoint = + details == null ? -1 : details._intersectPoint; /// Check the scrolled position in between the view position if (scrolledPosition >= widgetPosition && @@ -4391,12 +4394,11 @@ class _SfCalendarState extends State for (int i = 0; i < _backwardWidgetHeights.length; i++) { final _ScheduleViewDetails? details = _backwardWidgetHeights.containsKey(i) - ? _backwardWidgetHeights[i] - : null; + ? _backwardWidgetHeights[i] + : null; final double widgetHeight = details == null ? 0 : details._height; - final double interSectionPoint = details == null - ? -1 - : details._intersectPoint; + final double interSectionPoint = + details == null ? -1 : details._intersectPoint; /// Check the scrolled position in between the view position if (-scrolledPosition > widgetPosition && @@ -4664,9 +4666,9 @@ class _SfCalendarState extends State void _updateCurrentVisibleDates() { final List? nonWorkingDays = (_view == CalendarView.workWeek || - _view == CalendarView.timelineWorkWeek) - ? widget.timeSlotViewSettings.nonWorkingDays - : null; + _view == CalendarView.timelineWorkWeek) + ? widget.timeSlotViewSettings.nonWorkingDays + : null; final int visibleDatesCount = DateTimeHelper.getViewDatesCount( _view, widget.monthViewSettings.numberOfWeeksInView, @@ -4674,12 +4676,13 @@ class _SfCalendarState extends State nonWorkingDays, ); - _currentViewVisibleDates = getVisibleDates( - _currentDate, - nonWorkingDays, - widget.firstDayOfWeek, - visibleDatesCount, - ).cast(); + _currentViewVisibleDates = + getVisibleDates( + _currentDate, + nonWorkingDays, + widget.firstDayOfWeek, + visibleDatesCount, + ).cast(); if (_view == CalendarView.timelineMonth) { _currentViewVisibleDates = DateTimeHelper.getCurrentMonthDates( @@ -4843,9 +4846,8 @@ class _SfCalendarState extends State /// Calculate and add newly appointments dates into previous or next dates /// collection when hideEmptyScheduleWeek enabled in mobileUI and web UI and /// hideEmptyScheduleWeek disabled in web UI with schedule view. - final DateTime startDate = _previousDates.isEmpty - ? _nextDates[0] - : _previousDates[0]; + final DateTime startDate = + _previousDates.isEmpty ? _nextDates[0] : _previousDates[0]; final DateTime endDate = addDuration( _nextDates[_nextDates.length - 1], @@ -5249,9 +5251,10 @@ class _SfCalendarState extends State ( AppointmentView currentAppView, AppointmentView nextAppView, - ) => currentAppView.position > nextAppView.position - ? currentAppView - : nextAppView, + ) => + currentAppView.position > nextAppView.position + ? currentAppView + : nextAppView, ) .position + 1; @@ -5390,14 +5393,15 @@ class _SfCalendarState extends State void _updateAllDayPanelHeight() { int maxPosition = 0; if (_allDayAppointmentViewCollection.isNotEmpty) { - maxPosition = _allDayAppointmentViewCollection - .reduce( - (AppointmentView currentAppView, AppointmentView nextAppView) => - currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + maxPosition = + _allDayAppointmentViewCollection + .reduce( + (AppointmentView currentAppView, AppointmentView nextAppView) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } if (maxPosition == -1) { @@ -5644,12 +5648,12 @@ class _SfCalendarState extends State /// web view enabled or [hideEmptyAgendaDays] property as enabled. for (int j = 0; j < appointments.length; j++) { final CalendarAppointment appointment = appointments[j]; - appointment.actualEndTime = - AppointmentHelper.convertTimeToAppointmentTimeZone( - appointment.endTime, - appointment.endTimeZone, - timeZone, - ); + appointment + .actualEndTime = AppointmentHelper.convertTimeToAppointmentTimeZone( + appointment.endTime, + appointment.endTimeZone, + timeZone, + ); if (appointment.recurrenceRule == null || appointment.recurrenceRule == '') { @@ -5771,12 +5775,12 @@ class _SfCalendarState extends State /// web view enabled or [hideEmptyAgendaDays] property as enabled. for (int j = 0; j < appointments.length; j++) { final CalendarAppointment appointment = appointments[j]; - appointment.actualStartTime = - AppointmentHelper.convertTimeToAppointmentTimeZone( - appointment.startTime, - appointment.startTimeZone, - timeZone, - ); + appointment + .actualStartTime = AppointmentHelper.convertTimeToAppointmentTimeZone( + appointment.startTime, + appointment.startTimeZone, + timeZone, + ); if (appointment.actualStartTime.isBefore(currentMinDate)) { currentMinDate = appointment.actualStartTime; @@ -5804,18 +5808,18 @@ class _SfCalendarState extends State for (int j = 0; j < appointments.length; j++) { final CalendarAppointment appointment = appointments[j]; - appointment.actualStartTime = - AppointmentHelper.convertTimeToAppointmentTimeZone( - appointment.startTime, - appointment.startTimeZone, - timeZone, - ); - appointment.actualEndTime = - AppointmentHelper.convertTimeToAppointmentTimeZone( - appointment.endTime, - appointment.endTimeZone, - timeZone, - ); + appointment + .actualStartTime = AppointmentHelper.convertTimeToAppointmentTimeZone( + appointment.startTime, + appointment.startTimeZone, + timeZone, + ); + appointment + .actualEndTime = AppointmentHelper.convertTimeToAppointmentTimeZone( + appointment.endTime, + appointment.endTimeZone, + timeZone, + ); if (appointment.recurrenceRule == null || appointment.recurrenceRule == '') { @@ -5992,9 +5996,10 @@ class _SfCalendarState extends State /// Assign minimum date value to schedule display date when the minimum /// date is after of schedule display date - _minDate = _minDate!.isAfter(scheduleDisplayDate) - ? scheduleDisplayDate - : _minDate; + _minDate = + _minDate!.isAfter(scheduleDisplayDate) + ? scheduleDisplayDate + : _minDate; _minDate = _minDate!.isBefore(widget.minDate) ? widget.minDate : _minDate; final DateTime viewMinDate = DateTimeHelper.getDateTimeValue( @@ -6016,9 +6021,10 @@ class _SfCalendarState extends State /// Assign maximum date value to schedule current date when the maximum /// date is before of schedule current date - _maxDate = _maxDate!.isBefore(scheduleCurrentDate) - ? scheduleCurrentDate - : _maxDate; + _maxDate = + _maxDate!.isBefore(scheduleCurrentDate) + ? scheduleCurrentDate + : _maxDate; _maxDate = _maxDate!.isAfter(widget.maxDate) ? widget.maxDate : _maxDate; final bool hideEmptyAgendaDays = @@ -6145,27 +6151,27 @@ class _SfCalendarState extends State return null; } - final DateTime startDate = index >= 0 - ? _nextDates[index] - : _previousDates[-index - 1]; + final DateTime startDate = + index >= 0 ? _nextDates[index] : _previousDates[-index - 1]; /// Set previous date form it date collection if index is first index of /// next dates collection then get the start date from previous dates. /// If the index as last index of previous dates collection then calculate /// by subtract the 7 days to get previous date. - final DateTime prevDate = index == 0 - ? _previousDates.isEmpty - ? DateTimeHelper.getDateTimeValue( + final DateTime prevDate = + index == 0 + ? _previousDates.isEmpty + ? DateTimeHelper.getDateTimeValue( addDays(startDate, -DateTime.daysPerWeek), ) - : _previousDates[0] - : (index > 0 - ? _nextDates[index - 1] - : -index > _previousDates.length - 1 - ? DateTimeHelper.getDateTimeValue( + : _previousDates[0] + : (index > 0 + ? _nextDates[index - 1] + : -index > _previousDates.length - 1 + ? DateTimeHelper.getDateTimeValue( addDays(startDate, -DateTime.daysPerWeek), ) - : _previousDates[-index]); + : _previousDates[-index]); final DateTime prevEndDate = DateTimeHelper.getDateTimeValue( addDays(prevDate, 6), ); @@ -6252,9 +6258,10 @@ class _SfCalendarState extends State /// calculate the total height using height variable /// web view does not have week label. - double height = _useMobilePlatformUI - ? widget.scheduleViewSettings.weekHeaderSettings.height - : 0; + double height = + _useMobilePlatformUI + ? widget.scheduleViewSettings.weekHeaderSettings.height + : 0; /// It is used to current view top position inside the collection of views. double topHeight = 0; @@ -6280,9 +6287,8 @@ class _SfCalendarState extends State /// 1. Check the start date month have display date view. /// 2. Check the start date month have today date view. /// 3. Check the start date month have appointment view. - final DateTime? firstAppointmentDate = dateAppointmentKeys.isNotEmpty - ? dateAppointmentKeys[0] - : null; + final DateTime? firstAppointmentDate = + dateAppointmentKeys.isNotEmpty ? dateAppointmentKeys[0] : null; if ((startDate.month != scheduleDisplayDate.month || startDate.year != scheduleDisplayDate.year) && (startDate.month != scheduleCurrentDate.month || @@ -6295,9 +6301,10 @@ class _SfCalendarState extends State } /// Web view does not have month label. - height += isNeedMonthBuilder - ? widget.scheduleViewSettings.monthHeaderSettings.height - : 0; + height += + isNeedMonthBuilder + ? widget.scheduleViewSettings.monthHeaderSettings.height + : 0; final double appointmentViewHeight = CalendarViewHelper.getScheduleAppointmentHeight( null, @@ -6333,9 +6340,10 @@ class _SfCalendarState extends State double panelHeight = ((eventsCount - allDayEventCount) * appointmentViewHeight) + (allDayEventCount * allDayAppointmentHeight); - panelHeight = panelHeight > appointmentViewHeight - ? panelHeight - : appointmentViewHeight; + panelHeight = + panelHeight > appointmentViewHeight + ? panelHeight + : appointmentViewHeight; appointmentHeight += panelHeight + dividerHeight; numberOfEvents += eventsCount; } @@ -6361,13 +6369,15 @@ class _SfCalendarState extends State /// Get the previous view end position used to find the next view end /// position. if (currentIndex >= 0) { - previousHeight = currentIndex == 0 - ? 0 - : _forwardWidgetHeights[currentIndex - 1]!._height; + previousHeight = + currentIndex == 0 + ? 0 + : _forwardWidgetHeights[currentIndex - 1]!._height; } else { - previousHeight = currentIndex == -1 - ? 0 - : _backwardWidgetHeights[-currentIndex - 2]!._height; + previousHeight = + currentIndex == -1 + ? 0 + : _backwardWidgetHeights[-currentIndex - 2]!._height; } final List widgets = []; @@ -6403,9 +6413,8 @@ class _SfCalendarState extends State /// assign the label maximum height as 60. double appointmentViewHeaderHeight = appointmentViewHeight + (2 * padding); if (_useMobilePlatformUI) { - appointmentViewHeaderHeight = appointmentViewHeaderHeight > 60 - ? 60 - : appointmentViewHeaderHeight; + appointmentViewHeaderHeight = + appointmentViewHeaderHeight > 60 ? 60 : appointmentViewHeaderHeight; } double interSectPoint = topHeight; @@ -6420,16 +6429,18 @@ class _SfCalendarState extends State /// Check the end date month have appointments or not. bool isNextMonthHasNoAppointment = false; if (isNeedInBetweenMonthBuilder) { - final DateTime? lastAppointmentDate = dateAppointmentKeys.isNotEmpty - ? dateAppointmentKeys[dateAppointmentKeys.length - 1] - : null; - final DateTime? nextWeekDate = index == -1 - ? _nextDates[0] - : (index < 0 - ? _previousDates[-index - 2] - : index >= _nextDates.length - 1 - ? null - : _nextDates[index + 1]); + final DateTime? lastAppointmentDate = + dateAppointmentKeys.isNotEmpty + ? dateAppointmentKeys[dateAppointmentKeys.length - 1] + : null; + final DateTime? nextWeekDate = + index == -1 + ? _nextDates[0] + : (index < 0 + ? _previousDates[-index - 2] + : index >= _nextDates.length - 1 + ? null + : _nextDates[index + 1]); /// Check the following scenarios for rendering month label at last when /// the week holds different month dates @@ -6470,16 +6481,18 @@ class _SfCalendarState extends State /// Add appointment height to height when the view have display date view. if (isNeedDisplayDateHighlight) { - height += _useMobilePlatformUI - ? appointmentViewHeaderHeight - : appointmentViewHeaderHeight + dividerHeight; + height += + _useMobilePlatformUI + ? appointmentViewHeaderHeight + : appointmentViewHeaderHeight + dividerHeight; } /// Add appointment height to height when the view have current date view. if (isNeedCurrentDateHighlight) { - height += _useMobilePlatformUI - ? appointmentViewHeaderHeight - : appointmentViewHeaderHeight + dividerHeight; + height += + _useMobilePlatformUI + ? appointmentViewHeaderHeight + : appointmentViewHeaderHeight + dividerHeight; } /// display date highlight added boolean variable used to identify the @@ -6505,9 +6518,10 @@ class _SfCalendarState extends State void addMonthHeaderView() { /// Assign the intersection point based on previous view end position. - scheduleViewDetails._intersectPoint = currentIndex >= 0 - ? previousHeight + interSectPoint + viewTopPadding - : previousHeight + height - interSectPoint - viewTopPadding; + scheduleViewDetails._intersectPoint = + currentIndex >= 0 + ? previousHeight + interSectPoint + viewTopPadding + : previousHeight + height - interSectPoint - viewTopPadding; /// Web view does not have month label; if (_useMobilePlatformUI) { @@ -6527,9 +6541,10 @@ class _SfCalendarState extends State } void addDisplayOrCurrentDateView({bool isDisplayDate = true}) { - final double highlightViewStartPosition = currentIndex >= 0 - ? previousHeight + interSectPoint - : -(previousHeight + height - interSectPoint); + final double highlightViewStartPosition = + currentIndex >= 0 + ? previousHeight + interSectPoint + : -(previousHeight + height - interSectPoint); widgets.add( _getDisplayDateView( isRTL, @@ -6622,9 +6637,10 @@ class _SfCalendarState extends State appointmentViewTopPadding = appointmentViewPadding / 2; } - final double viewStartPosition = currentIndex >= 0 - ? previousHeight + interSectPoint - : -(previousHeight + height - interSectPoint); + final double viewStartPosition = + currentIndex >= 0 + ? previousHeight + interSectPoint + : -(previousHeight + height - interSectPoint); interSectPoint += appointmentViewPadding; currentAppointments.sort( @@ -6791,9 +6807,10 @@ class _SfCalendarState extends State /// end date month value. if (!isDisplayDateHighlightAdded && endDate.month != scheduleDisplayDate.month) { - final double highlightViewStartPosition = currentIndex >= 0 - ? previousHeight + topHeight + appointmentHeight - : previousHeight + height - topHeight - appointmentHeight; + final double highlightViewStartPosition = + currentIndex >= 0 + ? previousHeight + topHeight + appointmentHeight + : previousHeight + height - topHeight - appointmentHeight; widgets.add( _getDisplayDateView( isRTL, @@ -6823,9 +6840,10 @@ class _SfCalendarState extends State /// end date month value. if (!isCurrentDateHighlightAdded && endDate.month != scheduleCurrentDate.month) { - final double highlightViewStartPosition = currentIndex >= 0 - ? previousHeight + topHeight + appointmentHeight - : previousHeight + height - topHeight - appointmentHeight; + final double highlightViewStartPosition = + currentIndex >= 0 + ? previousHeight + topHeight + appointmentHeight + : previousHeight + height - topHeight - appointmentHeight; widgets.add( _getDisplayDateView( isRTL, @@ -6863,13 +6881,14 @@ class _SfCalendarState extends State /// view holds next month label. if scrolling reaches this position /// then we update the header date so add the location to intersecting /// point. - scheduleViewDetails._intersectPoint = currentIndex >= 0 - ? previousHeight + topHeight + appointmentHeight + viewTopPadding - : previousHeight + - height - - topHeight - - appointmentHeight - - viewTopPadding; + scheduleViewDetails._intersectPoint = + currentIndex >= 0 + ? previousHeight + topHeight + appointmentHeight + viewTopPadding + : previousHeight + + height - + topHeight - + appointmentHeight - + viewTopPadding; topHeight += widget.scheduleViewSettings.monthHeaderSettings.height + viewTopPadding; @@ -6887,9 +6906,10 @@ class _SfCalendarState extends State /// Add the display date view at end of week view when /// it does not added to widget. if (!isDisplayDateHighlightAdded) { - final double highlightViewStartPosition = currentIndex >= 0 - ? previousHeight + topHeight + appointmentHeight - : previousHeight + height - topHeight - appointmentHeight; + final double highlightViewStartPosition = + currentIndex >= 0 + ? previousHeight + topHeight + appointmentHeight + : previousHeight + height - topHeight - appointmentHeight; widgets.add( _getDisplayDateView( isRTL, @@ -6913,9 +6933,10 @@ class _SfCalendarState extends State /// Add the current date view at end of week view /// when it does not added to widget. if (!isCurrentDateHighlightAdded) { - final double highlightViewStartPosition = currentIndex >= 0 - ? previousHeight + topHeight + appointmentHeight - : previousHeight + height - topHeight - appointmentHeight; + final double highlightViewStartPosition = + currentIndex >= 0 + ? previousHeight + topHeight + appointmentHeight + : previousHeight + height - topHeight - appointmentHeight; widgets.add( _getDisplayDateView( isRTL, @@ -6945,10 +6966,7 @@ class _SfCalendarState extends State _backwardWidgetHeights[-currentIndex - 1] = scheduleViewDetails; } - return SizedBox( - height: height, - child: Column(children: widgets), - ); + return SizedBox(height: height, child: Column(children: widgets)); } Widget _getMonthOrWeekHeader( @@ -6977,50 +6995,56 @@ class _SfCalendarState extends State return GestureDetector( child: Container( - padding: isMonthLabel - ? EdgeInsets.fromLTRB(0, isNeedTopPadding ? padding : 0, 0, 0) - : EdgeInsets.fromLTRB( - isRTL ? 0 : viewPadding, - isNeedTopPadding ? padding : 0, - isRTL ? viewPadding : 0, - 0, - ), + padding: + isMonthLabel + ? EdgeInsets.fromLTRB(0, isNeedTopPadding ? padding : 0, 0, 0) + : EdgeInsets.fromLTRB( + isRTL ? 0 : viewPadding, + isNeedTopPadding ? padding : 0, + isRTL ? viewPadding : 0, + 0, + ), child: RepaintBoundary( - child: headerWidget != null - ? SizedBox( - width: _minWidth, - height: - widget.scheduleViewSettings.monthHeaderSettings.height, - child: headerWidget, - ) - : CustomPaint( - painter: _ScheduleLabelPainter( - startDate, - endDate, - widget.scheduleViewSettings, - isMonthLabel, - isRTL, - _locale, - _useMobilePlatformUI, - _agendaViewNotifier, - _calendarTheme, - _themeData, - _localizations, - _textScaleFactor, + child: + headerWidget != null + ? SizedBox( + width: _minWidth, + height: + widget.scheduleViewSettings.monthHeaderSettings.height, + child: headerWidget, + ) + : CustomPaint( + painter: _ScheduleLabelPainter( + startDate, + endDate, + widget.scheduleViewSettings, + isMonthLabel, + isRTL, + _locale, + _useMobilePlatformUI, + _agendaViewNotifier, + _calendarTheme, + _themeData, + _localizations, + _textScaleFactor, + ), + size: + isMonthLabel + ? Size( + _minWidth, + widget + .scheduleViewSettings + .monthHeaderSettings + .height, + ) + : Size( + _minWidth - viewPadding - (2 * padding), + widget + .scheduleViewSettings + .weekHeaderSettings + .height, + ), ), - size: isMonthLabel - ? Size( - _minWidth, - widget - .scheduleViewSettings - .monthHeaderSettings - .height, - ) - : Size( - _minWidth - viewPadding - (2 * padding), - widget.scheduleViewSettings.weekHeaderSettings.height, - ), - ), ), ), onTapUp: (TapUpDetails details) { @@ -7218,9 +7242,9 @@ class _SfCalendarState extends State widget.dataSource != null && !AppointmentHelper.isCalendarAppointment(widget.dataSource!) ? CalendarViewHelper.getCustomAppointments( - currentAppointments, - widget.dataSource, - ) + currentAppointments, + widget.dataSource, + ) : currentAppointments, CalendarElement.viewHeader, null, @@ -7232,9 +7256,9 @@ class _SfCalendarState extends State widget.dataSource != null && !AppointmentHelper.isCalendarAppointment(widget.dataSource!) ? CalendarViewHelper.getCustomAppointments( - currentAppointments, - widget.dataSource, - ) + currentAppointments, + widget.dataSource, + ) : currentAppointments, CalendarElement.viewHeader, null, @@ -7294,9 +7318,9 @@ class _SfCalendarState extends State widget.dataSource!, ) ? CalendarViewHelper.getCustomAppointments( - selectedAppointment, - widget.dataSource, - ) + selectedAppointment, + widget.dataSource, + ) : selectedAppointment, CalendarElement.appointment, null, @@ -7310,9 +7334,9 @@ class _SfCalendarState extends State widget.dataSource!, ) ? CalendarViewHelper.getCustomAppointments( - selectedAppointment, - widget.dataSource, - ) + selectedAppointment, + widget.dataSource, + ) : selectedAppointment, CalendarElement.appointment, null, @@ -7343,12 +7367,12 @@ class _SfCalendarState extends State final DateTime scheduleCurrentDate = DateTime.now(); final DateTime currentMaxDate = scheduleDisplayDate.isAfter(scheduleCurrentDate) - ? scheduleDisplayDate - : scheduleCurrentDate; + ? scheduleDisplayDate + : scheduleCurrentDate; final DateTime currentMinDate = scheduleDisplayDate.isBefore(scheduleCurrentDate) - ? scheduleDisplayDate - : scheduleCurrentDate; + ? scheduleDisplayDate + : scheduleCurrentDate; /// Get the minimum date of schedule view when it value as null /// It return min date user assigned when the [hideEmptyAgendaDays] @@ -7414,11 +7438,12 @@ class _SfCalendarState extends State if (_previousDates.isEmpty) { /// Calculate the start date from display date if next view dates /// collection as empty. - DateTime date = _nextDates.isNotEmpty - ? _nextDates[0] - : DateTimeHelper.getDateTimeValue( - addDays(scheduleDisplayDate, value), - ); + DateTime date = + _nextDates.isNotEmpty + ? _nextDates[0] + : DateTimeHelper.getDateTimeValue( + addDays(scheduleDisplayDate, value), + ); int count = 0; /// Using while for calculate dates because if [hideEmptyAgendaDays] as @@ -7737,11 +7762,12 @@ class _SfCalendarState extends State ); final DateTime appStartDate = isSameOrAfterDate(_minDate, visibleStartDate) - ? visibleStartDate - : _minDate!; - DateTime appEndDate = isSameOrBeforeDate(_maxDate, viewEndDate) - ? viewEndDate - : _maxDate!; + ? visibleStartDate + : _minDate!; + DateTime appEndDate = + isSameOrBeforeDate(_maxDate, viewEndDate) + ? viewEndDate + : _maxDate!; if (appEndDate.isAfter(scheduleDisplayDate) || isSameDate(appEndDate, scheduleDisplayDate)) { appEndDate = DateTimeHelper.getDateTimeValue( @@ -7936,9 +7962,10 @@ class _SfCalendarState extends State double panelHeight = ((eventsCount - allDayEventCount) * appointmentViewHeight) + (allDayEventCount * allDayAppointmentHeight); - panelHeight = panelHeight > appointmentViewHeight - ? panelHeight - : appointmentViewHeight; + panelHeight = + panelHeight > appointmentViewHeight + ? panelHeight + : appointmentViewHeight; /// event count + 1 denotes the appointment padding and end padding. totalAppointmentHeight += panelHeight + ((eventsCount + 1) * padding); @@ -7963,9 +7990,9 @@ class _SfCalendarState extends State viewStartDate.day != 1 ? 0 : (!_useMobilePlatformUI - ? 0 - : widget.scheduleViewSettings.monthHeaderSettings.height + - padding)); + ? 0 + : widget.scheduleViewSettings.monthHeaderSettings.height + + padding)); } else if ((viewStartDate.month != _scheduleDisplayDate.month && _useMobilePlatformUI) || todayNewEventHeight != 0) { @@ -7973,7 +8000,7 @@ class _SfCalendarState extends State (!_useMobilePlatformUI ? 0 : widget.scheduleViewSettings.weekHeaderSettings.height + - padding) + + padding) + todayNewEventHeight; } @@ -8034,11 +8061,12 @@ class _SfCalendarState extends State !isSameDate(_previousDates[_previousDates.length - 1], viewMinDate)) { /// Calculate the start date from display date if next view dates /// collection as empty. - DateTime date = _previousDates.isNotEmpty - ? _previousDates[_previousDates.length - 1] - : (_nextDates.isNotEmpty - ? _nextDates[0] - : DateTimeHelper.getDateTimeValue( + DateTime date = + _previousDates.isNotEmpty + ? _previousDates[_previousDates.length - 1] + : (_nextDates.isNotEmpty + ? _nextDates[0] + : DateTimeHelper.getDateTimeValue( addDays(scheduleDisplayDate, value), )); int count = 0; @@ -8121,11 +8149,17 @@ class _SfCalendarState extends State if (_nextDates.isEmpty || !isSameDate(_nextDates[_nextDates.length - 1], viewMaxDate)) { /// Calculate the start date from display date - DateTime date = _nextDates.isEmpty - ? DateTimeHelper.getDateTimeValue(addDays(scheduleDisplayDate, value)) - : DateTimeHelper.getDateTimeValue( - addDays(_nextDates[_nextDates.length - 1], DateTime.daysPerWeek), - ); + DateTime date = + _nextDates.isEmpty + ? DateTimeHelper.getDateTimeValue( + addDays(scheduleDisplayDate, value), + ) + : DateTimeHelper.getDateTimeValue( + addDays( + _nextDates[_nextDates.length - 1], + DateTime.daysPerWeek, + ), + ); int count = 0; /// Using while for calculate dates because if [hideEmptyAgendaDays] as @@ -8389,18 +8423,18 @@ class _SfCalendarState extends State double appointmentViewHeaderHeight = appointmentViewHeight + (2 * padding); if (_useMobilePlatformUI) { - appointmentViewHeaderHeight = appointmentViewHeaderHeight > 60 - ? 60 - : appointmentViewHeaderHeight; + appointmentViewHeaderHeight = + appointmentViewHeaderHeight > 60 ? 60 : appointmentViewHeaderHeight; } /// Calculate the divider height and color when it is web view. final double dividerHeight = _useMobilePlatformUI ? 0 : 1; /// Holds the height of 'No Events' label view. - final double displayEventHeight = _useMobilePlatformUI - ? appointmentViewHeaderHeight - : appointmentViewHeaderHeight + dividerHeight; + final double displayEventHeight = + _useMobilePlatformUI + ? appointmentViewHeaderHeight + : appointmentViewHeaderHeight + dividerHeight; /// Holds the heights of each weeks in month on initial loading. /// Eg., holds Feb 1, 2021 to Feb 28, 2021 month weeks height. @@ -8416,32 +8450,32 @@ class _SfCalendarState extends State final DateTime viewEndDate = DateTimeHelper.getDateTimeValue( addDays(viewStartDate, DateTime.daysPerWeek - 1), ); - final DateTime appStartDate = isSameOrAfterDate(_minDate, viewStartDate) - ? viewStartDate - : _minDate!; - final DateTime appEndDate = isSameOrBeforeDate(_maxDate, viewEndDate) - ? viewEndDate - : _maxDate!; + final DateTime appStartDate = + isSameOrAfterDate(_minDate, viewStartDate) + ? viewStartDate + : _minDate!; + final DateTime appEndDate = + isSameOrBeforeDate(_maxDate, viewEndDate) ? viewEndDate : _maxDate!; /// Today date view height. double todayNewEventHeight = isDateWithInDateRange( - viewStartDate, - viewEndDate, - scheduleCurrentDate, - ) - ? displayEventHeight - : 0; + viewStartDate, + viewEndDate, + scheduleCurrentDate, + ) + ? displayEventHeight + : 0; /// Display date view height. double displayNewEventHeight = isDateWithInDateRange( - viewStartDate, - viewEndDate, - scheduleDisplayDate, - ) - ? displayEventHeight - : 0; + viewStartDate, + viewEndDate, + scheduleDisplayDate, + ) + ? displayEventHeight + : 0; /// Current week appointments heights. final List appointmentCollection = @@ -8462,15 +8496,17 @@ class _SfCalendarState extends State viewStartDate.day == 1); /// Web view does not have month label. - double currentWeekHeight = isNeedMonthBuilder - ? widget.scheduleViewSettings.monthHeaderSettings.height - : 0; + double currentWeekHeight = + isNeedMonthBuilder + ? widget.scheduleViewSettings.monthHeaderSettings.height + : 0; /// Add the week header height to the current view height. /// web view does not have week label. - currentWeekHeight += _useMobilePlatformUI - ? widget.scheduleViewSettings.weekHeaderSettings.height - : 0; + currentWeekHeight += + _useMobilePlatformUI + ? widget.scheduleViewSettings.weekHeaderSettings.height + : 0; if (appointmentCollection.isNotEmpty) { /// Get the collection of appointment collection listed by date. @@ -8480,8 +8516,8 @@ class _SfCalendarState extends State appStartDate, appEndDate, ); - final List dateAppointmentKeys = dateAppointments.keys - .toList(); + final List dateAppointmentKeys = + dateAppointments.keys.toList(); int numberOfEvents = 0; @@ -8518,9 +8554,10 @@ class _SfCalendarState extends State double panelHeight = ((eventsCount - allDayEventCount) * appointmentViewHeight) + (allDayEventCount * allDayAppointmentHeight); - panelHeight = panelHeight > appointmentViewHeight - ? panelHeight - : appointmentViewHeight; + panelHeight = + panelHeight > appointmentViewHeight + ? panelHeight + : appointmentViewHeight; appointmentHeight += panelHeight + dividerHeight; numberOfEvents += eventsCount; } @@ -8582,12 +8619,12 @@ class _SfCalendarState extends State final DateTime viewEndDate = DateTimeHelper.getDateTimeValue( addDays(viewStartDate, 6), ); - final DateTime appStartDate = isSameOrAfterDate(_minDate, viewStartDate) - ? viewStartDate - : _minDate!; - DateTime appEndDate = isSameOrBeforeDate(_maxDate, viewEndDate) - ? viewEndDate - : _maxDate!; + final DateTime appStartDate = + isSameOrAfterDate(_minDate, viewStartDate) + ? viewStartDate + : _minDate!; + DateTime appEndDate = + isSameOrBeforeDate(_maxDate, viewEndDate) ? viewEndDate : _maxDate!; if (appEndDate.isAfter(scheduleDisplayDate) || isSameDate(appEndDate, scheduleDisplayDate)) { appEndDate = DateTimeHelper.getDateTimeValue( @@ -8598,13 +8635,13 @@ class _SfCalendarState extends State /// Today date view height. double todayNewEventHeight = !isSameDate(scheduleCurrentDate, scheduleDisplayDate) && - isDateWithInDateRange( - appStartDate, - appEndDate, - scheduleCurrentDate, - ) - ? displayEventHeight - : 0; + isDateWithInDateRange( + appStartDate, + appEndDate, + scheduleCurrentDate, + ) + ? displayEventHeight + : 0; final List appointmentCollection = AppointmentHelper.getVisibleAppointments( appStartDate, @@ -8630,19 +8667,22 @@ class _SfCalendarState extends State appStartDate, appEndDate, ); - final List dateAppointmentKeys = dateAppointments.keys - .toList(); + final List dateAppointmentKeys = + dateAppointments.keys.toList(); /// calculate the scroll position by adding week header height. /// web view does not have week label. - initialScrolledPosition += _useMobilePlatformUI - ? widget.scheduleViewSettings.weekHeaderSettings.height - : 0; + initialScrolledPosition += + _useMobilePlatformUI + ? widget.scheduleViewSettings.weekHeaderSettings.height + : 0; /// Web view does not have month label. - initialScrolledPosition += isNeedMonthBuilder - ? widget.scheduleViewSettings.monthHeaderSettings.height + padding - : 0; + initialScrolledPosition += + isNeedMonthBuilder + ? widget.scheduleViewSettings.monthHeaderSettings.height + + padding + : 0; int numberOfEvents = 0; @@ -8668,9 +8708,10 @@ class _SfCalendarState extends State double panelHeight = ((eventsCount - allDayEventCount) * appointmentViewHeight) + (allDayEventCount * allDayAppointmentHeight); - panelHeight = panelHeight > appointmentViewHeight - ? panelHeight - : appointmentViewHeight; + panelHeight = + panelHeight > appointmentViewHeight + ? panelHeight + : appointmentViewHeight; appointmentHeight += panelHeight + dividerHeight; numberOfEvents += eventsCount; } @@ -8693,7 +8734,7 @@ class _SfCalendarState extends State (!_useMobilePlatformUI ? 0 : widget.scheduleViewSettings.weekHeaderSettings.height + - padding) + + padding) + todayNewEventHeight; } @@ -8709,9 +8750,8 @@ class _SfCalendarState extends State /// than view port height then reduce the scroll position. if (belowSpace < height) { initialScrolledPosition -= height - belowSpace; - initialScrolledPosition = initialScrolledPosition > 0 - ? initialScrolledPosition - : 0; + initialScrolledPosition = + initialScrolledPosition > 0 ? initialScrolledPosition : 0; } _agendaScrollController?.removeListener(_handleScheduleViewScrolled); @@ -8895,17 +8935,19 @@ class _SfCalendarState extends State widget.loadMoreWidgetBuilder != null) { final Alignment loadMoreAlignment = _agendaScrollController!.hasClients && - _agendaScrollController!.position.pixels <= - _agendaScrollController!.position.minScrollExtent && - _isScheduleStartLoadMore - ? Alignment.topCenter - : Alignment.bottomCenter; - final DateTime visibleStartDate = _isNeedLoadMore - ? AppointmentHelper.getMonthStartDate(_scheduleMaxDate!) - : _scheduleMinDate!; - final DateTime visibleEndDate = _isNeedLoadMore - ? _scheduleMaxDate! - : AppointmentHelper.getMonthEndDate(_scheduleMinDate!); + _agendaScrollController!.position.pixels <= + _agendaScrollController!.position.minScrollExtent && + _isScheduleStartLoadMore + ? Alignment.topCenter + : Alignment.bottomCenter; + final DateTime visibleStartDate = + _isNeedLoadMore + ? AppointmentHelper.getMonthStartDate(_scheduleMaxDate!) + : _scheduleMinDate!; + final DateTime visibleEndDate = + _isNeedLoadMore + ? _scheduleMaxDate! + : AppointmentHelper.getMonthEndDate(_scheduleMinDate!); children.add( Positioned( top: widget.headerHeight, @@ -8993,22 +9035,22 @@ class _SfCalendarState extends State _localizations, ); - final Alignment alignment = _isRTL - ? Alignment.centerRight - : Alignment.centerLeft; + final Alignment alignment = + _isRTL ? Alignment.centerRight : Alignment.centerLeft; final int allowedViewLength = widget.allowedViews!.length; /// Generate the calendar view pop up content views. for (int i = 0; i < allowedViewLength; i++) { final CalendarView view = widget.allowedViews![i]; final String text = calendarViews[view]!; - final double textWidth = _getTextWidgetWidth( - text, - calendarViewTextHeight, - _minWidth, - context, - style: style, - ).width; + final double textWidth = + _getTextWidgetWidth( + text, + calendarViewTextHeight, + _minWidth, + context, + style: style, + ).width; width = width < textWidth ? textWidth : width; final bool isSelected = view == _view; if (isSelected) { @@ -9064,32 +9106,34 @@ class _SfCalendarState extends State widget.headerStyle.textAlign == TextAlign.justify); /// Calculate the calendar view button width that placed on header view - final double calendarViewWidth = _useMobilePlatformUI - ? iconWidth - : _getTextWidgetWidth( - calendarViews[_view]!, - widget.headerHeight, - _minWidth - totalArrowWidth, - context, - style: style, - ).width + - padding + - headerIconTextWidth; - double dividerWidth = 0; - double todayWidth = 0; - - /// Today button shown only the date picker enabled. - if (widget.showTodayButton) { - todayWidth = _useMobilePlatformUI - ? iconWidth - : _getTextWidgetWidth( - _localizations.todayLabel, + final double calendarViewWidth = + _useMobilePlatformUI + ? iconWidth + : _getTextWidgetWidth( + calendarViews[_view]!, widget.headerHeight, _minWidth - totalArrowWidth, context, style: style, ).width + - padding; + padding + + headerIconTextWidth; + double dividerWidth = 0; + double todayWidth = 0; + + /// Today button shown only the date picker enabled. + if (widget.showTodayButton) { + todayWidth = + _useMobilePlatformUI + ? iconWidth + : _getTextWidgetWidth( + _localizations.todayLabel, + widget.headerHeight, + _minWidth - totalArrowWidth, + context, + style: style, + ).width + + padding; /// Divider shown when the view holds calendar views and today button. dividerWidth = _useMobilePlatformUI ? 0 : 5; @@ -9112,34 +9156,39 @@ class _SfCalendarState extends State Alignment popupAlignment; if (_isMobilePlatform) { /// icon width specifies the today button width and calendar view width. - left = _isRTL - ? totalArrowWidth - : headerWidth + todayWidth + iconWidth - width; + left = + _isRTL + ? totalArrowWidth + : headerWidth + todayWidth + iconWidth - width; popupAlignment = _isRTL ? Alignment.topLeft : Alignment.topRight; if (widget.headerStyle.textAlign == TextAlign.right || widget.headerStyle.textAlign == TextAlign.end) { popupAlignment = _isRTL ? Alignment.topRight : Alignment.topLeft; - left = _isRTL - ? headerWidth + iconWidth + todayWidth - width - : totalArrowWidth; + left = + _isRTL + ? headerWidth + iconWidth + todayWidth - width + : totalArrowWidth; } else if (widget.headerStyle.textAlign == TextAlign.center || widget.headerStyle.textAlign == TextAlign.justify) { popupAlignment = _isRTL ? Alignment.topLeft : Alignment.topRight; - left = _isRTL - ? arrowWidth - : headerWidth + arrowWidth + todayWidth + iconWidth - width; + left = + _isRTL + ? arrowWidth + : headerWidth + arrowWidth + todayWidth + iconWidth - width; } } else { - left = _isRTL - ? calendarViewWidth - width - : headerWidth + totalArrowWidth + todayWidth + dividerWidth - 1; + left = + _isRTL + ? calendarViewWidth - width + : headerWidth + totalArrowWidth + todayWidth + dividerWidth - 1; popupAlignment = _isRTL ? Alignment.topLeft : Alignment.topRight; if (widget.headerStyle.textAlign == TextAlign.right || widget.headerStyle.textAlign == TextAlign.end) { popupAlignment = _isRTL ? Alignment.topRight : Alignment.topLeft; - left = _isRTL - ? headerWidth + totalArrowWidth + todayWidth + dividerWidth - 1 - : calendarViewWidth - width; + left = + _isRTL + ? headerWidth + totalArrowWidth + todayWidth + dividerWidth - 1 + : calendarViewWidth - width; } else if (widget.headerStyle.textAlign == TextAlign.center || widget.headerStyle.textAlign == TextAlign.justify) { popupAlignment = _isRTL ? Alignment.topRight : Alignment.topLeft; @@ -9155,13 +9204,14 @@ class _SfCalendarState extends State todayWidth - headerWidth) / 2; - left = _isRTL - ? leftStartPosition + calendarViewWidth - width - : leftStartPosition + - totalArrowWidth + - headerWidth + - todayWidth + - dividerWidth; + left = + _isRTL + ? leftStartPosition + calendarViewWidth - width + : leftStartPosition + + totalArrowWidth + + headerWidth + + todayWidth + + dividerWidth; } } @@ -9176,9 +9226,10 @@ class _SfCalendarState extends State scrollPosition = selectedIndex * calendarViewTextHeight; final double maxScrollPosition = allowedViewLength * calendarViewTextHeight; - scrollPosition = (maxScrollPosition - scrollPosition) > height - ? scrollPosition - : maxScrollPosition - height; + scrollPosition = + (maxScrollPosition - scrollPosition) > height + ? scrollPosition + : maxScrollPosition - height; } final bool showScrollbar = totalHeight > height; @@ -9195,9 +9246,10 @@ class _SfCalendarState extends State child: Container( padding: EdgeInsets.zero, decoration: BoxDecoration( - color: _themeData.brightness == Brightness.dark - ? Colors.grey[850] - : Colors.white, + color: + _themeData.brightness == Brightness.dark + ? Colors.grey[850] + : Colors.white, boxShadow: kElevationToShadow[6], borderRadius: BorderRadius.circular(2.0), ), @@ -9269,12 +9321,14 @@ class _SfCalendarState extends State Positioned( left: _isRTL ? 0.5 : resourceViewSize - 0.5, width: 0.5, - top: _controller.view == CalendarView.timelineMonth - ? widget.headerHeight - : widget.headerHeight + viewHeaderHeight, - height: _controller.view == CalendarView.timelineMonth - ? viewHeaderHeight - : timeLabelSize, + top: + _controller.view == CalendarView.timelineMonth + ? widget.headerHeight + : widget.headerHeight + viewHeaderHeight, + height: + _controller.view == CalendarView.timelineMonth + ? viewHeaderHeight + : timeLabelSize, child: verticalDivider, ), Positioned( @@ -9497,9 +9551,8 @@ class _SfCalendarState extends State widget.dataSource, _view, ); - final double resourceViewSize = isResourceEnabled - ? widget.resourceViewSettings.size - : 0; + final double resourceViewSize = + isResourceEnabled ? widget.resourceViewSettings.size : 0; final DateTime currentViewDate = _currentViewVisibleDates[(_currentViewVisibleDates.length / 2) .truncate()]; @@ -9655,12 +9708,14 @@ class _SfCalendarState extends State final double totalArrowWidth = 2 * arrowWidth; final double totalWidth = _minWidth - totalArrowWidth; final double totalHeight = _minHeight - widget.headerHeight; - maxHeight = maxHeight < 250 - ? (totalHeight < 250 ? totalHeight - 10 : 250) - : maxHeight; - maxWidth = maxWidth < 250 - ? (totalWidth < 250 ? totalWidth - 10 : 250) - : maxWidth; + maxHeight = + maxHeight < 250 + ? (totalHeight < 250 ? totalHeight - 10 : 250) + : maxHeight; + maxWidth = + maxWidth < 250 + ? (totalWidth < 250 ? totalWidth - 10 : 250) + : maxWidth; double containerSize = maxHeight > maxWidth ? maxWidth : maxHeight; if (containerSize > 300) { containerSize = 300; @@ -9668,9 +9723,8 @@ class _SfCalendarState extends State pickerWidth = containerSize; pickerHeight = containerSize; - left = isRTL - ? _minWidth - containerSize - totalArrowWidth - : totalArrowWidth; + left = + isRTL ? _minWidth - containerSize - totalArrowWidth : totalArrowWidth; if (widget.headerStyle.textAlign == TextAlign.right || widget.headerStyle.textAlign == TextAlign.end) { left = isRTL ? padding : _minWidth - containerSize - totalArrowWidth; @@ -9692,13 +9746,14 @@ class _SfCalendarState extends State 2; double headerPadding = (headerViewWidth - containerSize) / 2; headerPadding = headerPadding > 0 ? headerPadding : 0; - left = _isRTL - ? leftPadding + - arrowWidth + - calendarViewWidth + - headerViewWidth - - containerSize - : leftPadding + arrowWidth + headerPadding; + left = + _isRTL + ? leftPadding + + arrowWidth + + calendarViewWidth + + headerViewWidth - + containerSize + : leftPadding + arrowWidth + headerPadding; } } } @@ -9712,26 +9767,29 @@ class _SfCalendarState extends State child: Container( margin: EdgeInsets.zero, padding: const EdgeInsets.all(5), - decoration: _isMobilePlatform - ? BoxDecoration( - color: _themeData.brightness == Brightness.dark - ? Colors.grey[850] - : Colors.white, - boxShadow: const [ - BoxShadow( - offset: Offset(0.0, 3.0), - blurRadius: 2.0, - color: Color(0x24000000), - ), - ], - ) - : BoxDecoration( - color: _themeData.brightness == Brightness.dark - ? Colors.grey[850] - : Colors.white, - boxShadow: kElevationToShadow[6], - borderRadius: BorderRadius.circular(2.0), - ), + decoration: + _isMobilePlatform + ? BoxDecoration( + color: + _themeData.brightness == Brightness.dark + ? Colors.grey[850] + : Colors.white, + boxShadow: const [ + BoxShadow( + offset: Offset(0.0, 3.0), + blurRadius: 2.0, + color: Color(0x24000000), + ), + ], + ) + : BoxDecoration( + color: + _themeData.brightness == Brightness.dark + ? Colors.grey[850] + : Colors.white, + boxShadow: kElevationToShadow[6], + borderRadius: BorderRadius.circular(2.0), + ), child: SfDateRangePicker( showNavigationArrow: true, initialSelectedDate: _currentDate, @@ -9743,21 +9801,21 @@ class _SfCalendarState extends State //// For disabling the picker dates based on the calendar non working days. selectableDayPredicate: _view != CalendarView.workWeek && - _view != CalendarView.timelineWorkWeek - ? null - : (DateTime dateTime) { - for ( - int i = 0; - i < widget.timeSlotViewSettings.nonWorkingDays.length; - i++ - ) { - if (dateTime.weekday == - widget.timeSlotViewSettings.nonWorkingDays[i]) { - return false; + _view != CalendarView.timelineWorkWeek + ? null + : (DateTime dateTime) { + for ( + int i = 0; + i < widget.timeSlotViewSettings.nonWorkingDays.length; + i++ + ) { + if (dateTime.weekday == + widget.timeSlotViewSettings.nonWorkingDays[i]) { + return false; + } } - } - return true; - }, + return true; + }, headerStyle: DateRangePickerHeaderStyle( textAlign: _isMobilePlatform ? TextAlign.center : TextAlign.left, ), @@ -9776,9 +9834,9 @@ class _SfCalendarState extends State ), view: _view == CalendarView.month || - _view == CalendarView.timelineMonth - ? DateRangePickerView.year - : DateRangePickerView.month, + _view == CalendarView.timelineMonth + ? DateRangePickerView.year + : DateRangePickerView.month, onViewChanged: (DateRangePickerViewChangedArgs details) { if ((_view != CalendarView.month && _view != CalendarView.timelineMonth) || @@ -10066,9 +10124,10 @@ class _SfCalendarState extends State ); for (int i = 0; i < agendaAppointments.length; i++) { final CalendarAppointment appointment = agendaAppointments[i]; - final double appointmentHeight = _isAllDayAppointmentView(appointment) - ? allDayAppointmentHeight - : actualAppointmentHeight; + final double appointmentHeight = + _isAllDayAppointmentView(appointment) + ? allDayAppointmentHeight + : actualAppointmentHeight; if (tappedYPosition >= xPosition && tappedYPosition < xPosition + appointmentHeight + padding) { index = i; @@ -10119,16 +10178,16 @@ class _SfCalendarState extends State if (_selectedDate != null) { currentSelectedDate = isDateWithInDateRange( - widget.minDate, - widget.maxDate, - _selectedDate, - ) && - !CalendarViewHelper.isDateInDateCollection( - _blackoutDates, - _selectedDate!, - ) - ? _selectedDate - : null; + widget.minDate, + widget.maxDate, + _selectedDate, + ) && + !CalendarViewHelper.isDateInDateCollection( + _blackoutDates, + _selectedDate!, + ) + ? _selectedDate + : null; } if (currentSelectedDate == null) { @@ -10645,9 +10704,10 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { headerTextSize.width + padding + (widget.showDatePickerButton ? headerIconTextWidth : 0); - maxHeaderHeight = maxHeaderHeight > headerTextSize.height - ? maxHeaderHeight - : headerTextSize.height; + maxHeaderHeight = + maxHeaderHeight > headerTextSize.height + ? maxHeaderHeight + : headerTextSize.height; } if (weekNumberEnabled) { @@ -10674,8 +10734,8 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { if (useMobilePlatformUI) { maxHeaderHeight = maxHeaderHeight != 0 && maxHeaderHeight <= widget.height - ? maxHeaderHeight - : widget.height; + ? maxHeaderHeight + : widget.height; /// Render allowed views icon on mobile view. calendarViewIcon = _getCalendarViewWidget( @@ -10727,8 +10787,8 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { calendarViewSize.width + allowedViewsPadding; maxCalendarViewHeight = maxCalendarViewHeight > calendarViewSize.height - ? maxCalendarViewHeight - : calendarViewSize.height + allowedViewsPadding; + ? maxCalendarViewHeight + : calendarViewSize.height + allowedViewsPadding; calendarViewsWidth[currentView] = currentViewTextWidth; allowedViewsWidth += currentViewTextWidth; } @@ -10737,12 +10797,12 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { /// render the allowed views as children. if (allowedViewsWidth < totalWidth) { calendarViewWidth = allowedViewsWidth; - maxHeaderHeight = maxCalendarViewHeight > maxHeaderHeight - ? maxCalendarViewHeight - : maxHeaderHeight; - maxHeaderHeight = maxHeaderHeight > widget.height - ? widget.height - : maxHeaderHeight; + maxHeaderHeight = + maxCalendarViewHeight > maxHeaderHeight + ? maxCalendarViewHeight + : maxHeaderHeight; + maxHeaderHeight = + maxHeaderHeight > widget.height ? widget.height : maxHeaderHeight; for (int i = 0; i < allowedViewsLength; i++) { final CalendarView currentView = widget.allowedViews![i]; children.add( @@ -10773,12 +10833,12 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { style: const TextStyle(fontSize: defaultCalendarViewTextSize), ); maxCalendarViewHeight = calendarViewSize.height + allowedViewsPadding; - maxHeaderHeight = maxCalendarViewHeight > maxHeaderHeight - ? maxCalendarViewHeight - : maxHeaderHeight; - maxHeaderHeight = maxHeaderHeight > widget.height - ? widget.height - : maxHeaderHeight; + maxHeaderHeight = + maxCalendarViewHeight > maxHeaderHeight + ? maxCalendarViewHeight + : maxHeaderHeight; + maxHeaderHeight = + maxHeaderHeight > widget.height ? widget.height : maxHeaderHeight; calendarViewWidth = calendarViewSize.width + allowedViewsPadding + @@ -10806,8 +10866,8 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { final double headerHeight = maxHeaderHeight != 0 && maxHeaderHeight <= widget.height - ? maxHeaderHeight - : widget.height; + ? maxHeaderHeight + : widget.height; if (weekNumberEnabled) { /// Header will render based on its text width while week number enabled. @@ -10880,9 +10940,8 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { return MainAxisAlignment.center; } - double arrowSize = headerHeight == widget.height - ? headerHeight * 0.6 - : headerHeight * 0.8; + double arrowSize = + headerHeight == widget.height ? headerHeight * 0.6 : headerHeight * 0.8; arrowSize = arrowSize > 25 ? 25 : arrowSize; arrowSize = arrowSize * widget.textScaleFactor; final bool isCenterAlignment = @@ -10905,403 +10964,419 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { final Color? splashColor = !widget.showDatePickerButton || !widget.enableInteraction - ? Colors.transparent - : null; + ? Colors.transparent + : null; final TextStyle headerTextStyle = widget.calendarTheme.headerTextStyle!; - final Widget headerText = widget.isMobilePlatform - ? Container( - alignment: Alignment.center, - color: headerBackgroundColor, - width: isCenterAlignment && headerWidth > 200 ? 200 : headerWidth, - height: headerHeight, - padding: const EdgeInsets.all(2), - child: Material( + final Widget headerText = + widget.isMobilePlatform + ? Container( + alignment: Alignment.center, color: headerBackgroundColor, - child: InkWell( - //// set splash color as transparent when header does not have - // date piker. - splashColor: splashColor, - highlightColor: splashColor, - hoverColor: splashColor, - splashFactory: _CustomSplashFactory(), - onTap: () { - if (!widget.enableInteraction) { - return; - } - widget.headerTapCallback( - calendarViewWidth + dividerWidth + todayIconWidth, - ); - }, - onLongPress: () { - if (!widget.enableInteraction) { - return; - } - widget.headerLongPressCallback( - calendarViewWidth + dividerWidth + todayIconWidth, - ); - }, - child: Container( - clipBehavior: Clip.antiAlias, - decoration: const BoxDecoration(color: Colors.transparent), - width: isCenterAlignment && headerWidth > 200 - ? 200 - : headerWidth, - height: headerHeight, - alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric(horizontal: 5), - child: Row( - mainAxisAlignment: getAlignmentFromTextAlign(), - children: widget.showDatePickerButton - ? [ - Flexible( - child: Text( - headerString, - style: headerTextStyle, - maxLines: 1, - semanticsLabel: - // ignore: lines_longer_than_80_chars - '$headerString ${widget.isPickerShown ? 'hide date picker' : 'show date picker'}', - overflow: TextOverflow.clip, - softWrap: false, - textDirection: - CalendarViewHelper.getTextDirectionBasedOnLocale( - widget.locale, - ), - ), - ), - Icon( - widget.isPickerShown - ? Icons.arrow_drop_up - : Icons.arrow_drop_down, - color: arrowColor, - size: headerTextStyle.fontSize ?? 14, - ), - ] - : [ - Flexible( - child: Text( - headerString, - style: headerTextStyle, - maxLines: 1, - overflow: TextOverflow.clip, - softWrap: false, - textDirection: - CalendarViewHelper.getTextDirectionBasedOnLocale( - widget.locale, - ), - ), - ), - ], + width: isCenterAlignment && headerWidth > 200 ? 200 : headerWidth, + height: headerHeight, + padding: const EdgeInsets.all(2), + child: Material( + color: headerBackgroundColor, + child: InkWell( + //// set splash color as transparent when header does not have + // date piker. + splashColor: splashColor, + highlightColor: splashColor, + hoverColor: splashColor, + splashFactory: _CustomSplashFactory(), + onTap: () { + if (!widget.enableInteraction) { + return; + } + widget.headerTapCallback( + calendarViewWidth + dividerWidth + todayIconWidth, + ); + }, + onLongPress: () { + if (!widget.enableInteraction) { + return; + } + widget.headerLongPressCallback( + calendarViewWidth + dividerWidth + todayIconWidth, + ); + }, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration(color: Colors.transparent), + width: + isCenterAlignment && headerWidth > 200 + ? 200 + : headerWidth, + height: headerHeight, + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 5), + child: Row( + mainAxisAlignment: getAlignmentFromTextAlign(), + children: + widget.showDatePickerButton + ? [ + Flexible( + child: Text( + headerString, + style: headerTextStyle, + maxLines: 1, + semanticsLabel: + // ignore: lines_longer_than_80_chars + '$headerString ${widget.isPickerShown ? 'hide date picker' : 'show date picker'}', + overflow: TextOverflow.clip, + softWrap: false, + textDirection: + CalendarViewHelper.getTextDirectionBasedOnLocale( + widget.locale, + ), + ), + ), + Icon( + widget.isPickerShown + ? Icons.arrow_drop_up + : Icons.arrow_drop_down, + color: arrowColor, + size: headerTextStyle.fontSize ?? 14, + ), + ] + : [ + Flexible( + child: Text( + headerString, + style: headerTextStyle, + maxLines: 1, + overflow: TextOverflow.clip, + softWrap: false, + textDirection: + CalendarViewHelper.getTextDirectionBasedOnLocale( + widget.locale, + ), + ), + ), + ], + ), ), ), ), - ), - ) - : Container( - alignment: getHeaderAlignment(), - color: headerBackgroundColor, - width: isCenterAlignment && headerWidth > 200 ? 200 : headerWidth, - height: headerHeight, - padding: const EdgeInsets.all(2), - child: Material( + ) + : Container( + alignment: getHeaderAlignment(), color: headerBackgroundColor, - child: InkWell( - //// set splash color as transparent when header does not have - // date piker. - splashColor: splashColor, - highlightColor: splashColor, - splashFactory: _CustomSplashFactory(), - onTap: () { - if (!widget.enableInteraction) { - return; - } - widget.headerTapCallback( - calendarViewWidth + dividerWidth + todayIconWidth, - ); - }, - onLongPress: () { - if (!widget.enableInteraction) { - return; - } - widget.headerLongPressCallback( - calendarViewWidth + dividerWidth + todayIconWidth, - ); - }, - child: Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - color: widget.showDatePickerButton && widget.isPickerShown - ? Colors.grey.withValues(alpha: 0.3) - : headerBackgroundColor, - ), + width: isCenterAlignment && headerWidth > 200 ? 200 : headerWidth, + height: headerHeight, + padding: const EdgeInsets.all(2), + child: Material( + color: headerBackgroundColor, + child: InkWell( + //// set splash color as transparent when header does not have + // date piker. + splashColor: splashColor, + highlightColor: splashColor, + splashFactory: _CustomSplashFactory(), + onTap: () { + if (!widget.enableInteraction) { + return; + } + widget.headerTapCallback( + calendarViewWidth + dividerWidth + todayIconWidth, + ); + }, + onLongPress: () { + if (!widget.enableInteraction) { + return; + } + widget.headerLongPressCallback( + calendarViewWidth + dividerWidth + todayIconWidth, + ); + }, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: + widget.showDatePickerButton && widget.isPickerShown + ? Colors.grey.withValues(alpha: 0.3) + : headerBackgroundColor, + ), - /// Padding value is from parent container padding - /// value const EdgeInsets.all(2). - width: - (isCenterAlignment && headerTextWidth > 200 - ? 200 - : headerTextWidth) - - padding, - height: headerHeight, - alignment: Alignment.center, - padding: const EdgeInsets.symmetric(horizontal: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: widget.showDatePickerButton - ? [ - Flexible( - child: Text( - headerString, - style: headerTextStyle, - maxLines: 1, - semanticsLabel: - // ignore: lines_longer_than_80_chars - '$headerString ${widget.isPickerShown ? 'hide date picker' : 'show date picker'}', - overflow: TextOverflow.clip, - softWrap: false, - textDirection: - CalendarViewHelper.getTextDirectionBasedOnLocale( - widget.locale, - ), - ), - ), - Icon( - widget.isPickerShown - ? Icons.arrow_drop_up - : Icons.arrow_drop_down, - color: arrowColor, - size: headerTextStyle.fontSize ?? 14, - ), - ] - : [ - Flexible( - child: Text( - headerString, - style: headerTextStyle, - maxLines: 1, - overflow: TextOverflow.clip, - softWrap: false, - textDirection: - CalendarViewHelper.getTextDirectionBasedOnLocale( - widget.locale, - ), - ), - ), - ], + /// Padding value is from parent container padding + /// value const EdgeInsets.all(2). + width: + (isCenterAlignment && headerTextWidth > 200 + ? 200 + : headerTextWidth) - + padding, + height: headerHeight, + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: + widget.showDatePickerButton + ? [ + Flexible( + child: Text( + headerString, + style: headerTextStyle, + maxLines: 1, + semanticsLabel: + // ignore: lines_longer_than_80_chars + '$headerString ${widget.isPickerShown ? 'hide date picker' : 'show date picker'}', + overflow: TextOverflow.clip, + softWrap: false, + textDirection: + CalendarViewHelper.getTextDirectionBasedOnLocale( + widget.locale, + ), + ), + ), + Icon( + widget.isPickerShown + ? Icons.arrow_drop_up + : Icons.arrow_drop_down, + color: arrowColor, + size: headerTextStyle.fontSize ?? 14, + ), + ] + : [ + Flexible( + child: Text( + headerString, + style: headerTextStyle, + maxLines: 1, + overflow: TextOverflow.clip, + softWrap: false, + textDirection: + CalendarViewHelper.getTextDirectionBasedOnLocale( + widget.locale, + ), + ), + ), + ], + ), ), ), ), - ), - ); + ); - final Widget weekNumberWidget = weekNumberEnabled - ? Container( - width: isCenterAlignment - ? weekNumberTextWidth - : weekNumberPanelWidth, - height: weekNumberPanelHeight, - alignment: getHeaderAlignment(), - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(padding)), - color: weekNumberBackgroundColor, - ), - alignment: Alignment.center, - width: weekNumberTextWidth, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: Text( - widget.localizations.weeknumberLabel, - textAlign: TextAlign.center, - textScaler: TextScaler.linear(widget.textScaleFactor), - style: weekNumberTextStyle, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), + final Widget weekNumberWidget = + weekNumberEnabled + ? Container( + width: + isCenterAlignment + ? weekNumberTextWidth + : weekNumberPanelWidth, + height: weekNumberPanelHeight, + alignment: getHeaderAlignment(), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(padding), ), - Flexible( - child: Text( - ' $weekNumberString', - textAlign: TextAlign.center, - style: weekNumberTextStyle, - textScaler: TextScaler.linear(widget.textScaleFactor), - maxLines: 1, + color: weekNumberBackgroundColor, + ), + alignment: Alignment.center, + width: weekNumberTextWidth, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: Text( + widget.localizations.weeknumberLabel, + textAlign: TextAlign.center, + textScaler: TextScaler.linear(widget.textScaleFactor), + style: weekNumberTextStyle, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), - ), - ], + Flexible( + child: Text( + ' $weekNumberString', + textAlign: TextAlign.center, + style: weekNumberTextStyle, + textScaler: TextScaler.linear(widget.textScaleFactor), + maxLines: 1, + ), + ), + ], + ), ), - ), - ) - : Container(); + ) + : Container(); final Color? leftArrowSplashColor = prevArrowColor != arrowColor || !widget.enableInteraction - ? Colors.transparent - : null; - final Container leftArrow = navigationArrowEnabled - ? Container( - alignment: Alignment.center, - color: headerBackgroundColor, - width: arrowWidth, - height: headerHeight, - padding: const EdgeInsets.all(2), - child: Material( + ? Colors.transparent + : null; + final Container leftArrow = + navigationArrowEnabled + ? Container( + alignment: Alignment.center, color: headerBackgroundColor, - child: InkWell( - //// set splash color as transparent when arrow reaches min date(disabled) - splashColor: leftArrowSplashColor, - highlightColor: leftArrowSplashColor, - hoverColor: leftArrowSplashColor, - splashFactory: _CustomSplashFactory(), - onTap: _backward, - child: Semantics( - label: 'Backward', - child: Container( - width: arrowWidth, - height: headerHeight, - alignment: Alignment.center, - clipBehavior: Clip.antiAlias, - decoration: const BoxDecoration(color: Colors.transparent), - child: Icon( - widget.navigationDirection == - MonthNavigationDirection.horizontal - ? Icons.chevron_left - : Icons.keyboard_arrow_up, - color: prevArrowColor, - size: arrowSize, + width: arrowWidth, + height: headerHeight, + padding: const EdgeInsets.all(2), + child: Material( + color: headerBackgroundColor, + child: InkWell( + //// set splash color as transparent when arrow reaches min date(disabled) + splashColor: leftArrowSplashColor, + highlightColor: leftArrowSplashColor, + hoverColor: leftArrowSplashColor, + splashFactory: _CustomSplashFactory(), + onTap: _backward, + child: Semantics( + label: 'Backward', + child: Container( + width: arrowWidth, + height: headerHeight, + alignment: Alignment.center, + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration( + color: Colors.transparent, + ), + child: Icon( + widget.navigationDirection == + MonthNavigationDirection.horizontal + ? Icons.chevron_left + : Icons.keyboard_arrow_up, + color: prevArrowColor, + size: arrowSize, + ), ), ), ), ), - ), - ) - : Container(); + ) + : Container(); final Color? rightArrowSplashColor = nextArrowColor != arrowColor || !widget.enableInteraction - ? Colors.transparent - : null; - final Container rightArrow = navigationArrowEnabled - ? Container( - alignment: Alignment.center, - color: headerBackgroundColor, - width: arrowWidth, - height: headerHeight, - padding: const EdgeInsets.all(2), - child: Material( + ? Colors.transparent + : null; + final Container rightArrow = + navigationArrowEnabled + ? Container( + alignment: Alignment.center, color: headerBackgroundColor, - child: InkWell( - //// set splash color as transparent when arrow reaches max date(disabled) - splashColor: rightArrowSplashColor, - highlightColor: rightArrowSplashColor, - hoverColor: rightArrowSplashColor, - splashFactory: _CustomSplashFactory(), - onTap: _forward, - child: Semantics( - label: 'Forward', - child: Container( - width: arrowWidth, - height: headerHeight, - alignment: Alignment.center, - clipBehavior: Clip.antiAlias, - decoration: const BoxDecoration(color: Colors.transparent), - child: Icon( - widget.navigationDirection == - MonthNavigationDirection.horizontal - ? Icons.chevron_right - : Icons.keyboard_arrow_down, - color: nextArrowColor, - size: arrowSize, + width: arrowWidth, + height: headerHeight, + padding: const EdgeInsets.all(2), + child: Material( + color: headerBackgroundColor, + child: InkWell( + //// set splash color as transparent when arrow reaches max date(disabled) + splashColor: rightArrowSplashColor, + highlightColor: rightArrowSplashColor, + hoverColor: rightArrowSplashColor, + splashFactory: _CustomSplashFactory(), + onTap: _forward, + child: Semantics( + label: 'Forward', + child: Container( + width: arrowWidth, + height: headerHeight, + alignment: Alignment.center, + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration( + color: Colors.transparent, + ), + child: Icon( + widget.navigationDirection == + MonthNavigationDirection.horizontal + ? Icons.chevron_right + : Icons.keyboard_arrow_down, + color: nextArrowColor, + size: arrowSize, + ), ), ), ), ), - ), - ) - : Container(); - - final Color? todaySplashColor = !widget.enableInteraction - ? Colors.transparent - : null; - final Widget todayIcon = widget.showTodayButton - ? Container( - alignment: Alignment.center, - color: headerBackgroundColor, - width: todayIconWidth, - height: headerHeight, - padding: EdgeInsets.all(useMobilePlatformUI ? 2 : 4), - child: Material( + ) + : Container(); + + final Color? todaySplashColor = + !widget.enableInteraction ? Colors.transparent : null; + final Widget todayIcon = + widget.showTodayButton + ? Container( + alignment: Alignment.center, color: headerBackgroundColor, - child: InkWell( - splashColor: todaySplashColor, - highlightColor: todaySplashColor, - hoverColor: todaySplashColor, - splashFactory: _CustomSplashFactory(), - onTap: () { - if (!widget.enableInteraction) { - return; - } - - widget.removePicker(); - widget.controller.displayDate = DateTime.now(); - }, - child: Semantics( - label: todayText, - child: useMobilePlatformUI - ? Container( - decoration: const BoxDecoration( - color: Colors.transparent, - ), - clipBehavior: Clip.antiAlias, - width: todayIconWidth, - height: headerHeight, - alignment: Alignment.center, - child: Icon( - Icons.today, - color: style.color, - size: style.fontSize, - ), - ) - : Container( - decoration: BoxDecoration( - border: Border.all( - color: - widget.cellBorderColor ?? - widget.calendarTheme.cellBorderColor!, - ), - borderRadius: BorderRadius.circular(5.0), - ), - width: todayIconWidth, - alignment: Alignment.center, - child: Text( - todayText, - style: TextStyle( - color: headerTextColor, - fontSize: defaultCalendarViewTextSize, + width: todayIconWidth, + height: headerHeight, + padding: EdgeInsets.all(useMobilePlatformUI ? 2 : 4), + child: Material( + color: headerBackgroundColor, + child: InkWell( + splashColor: todaySplashColor, + highlightColor: todaySplashColor, + hoverColor: todaySplashColor, + splashFactory: _CustomSplashFactory(), + onTap: () { + if (!widget.enableInteraction) { + return; + } + + widget.removePicker(); + widget.controller.displayDate = DateTime.now(); + }, + child: Semantics( + label: todayText, + child: + useMobilePlatformUI + ? Container( + decoration: const BoxDecoration( + color: Colors.transparent, + ), + clipBehavior: Clip.antiAlias, + width: todayIconWidth, + height: headerHeight, + alignment: Alignment.center, + child: Icon( + Icons.today, + color: style.color, + size: style.fontSize, + ), + ) + : Container( + decoration: BoxDecoration( + border: Border.all( + color: + widget.cellBorderColor ?? + widget.calendarTheme.cellBorderColor!, + ), + borderRadius: BorderRadius.circular(5.0), + ), + width: todayIconWidth, + alignment: Alignment.center, + child: Text( + todayText, + style: TextStyle( + color: headerTextColor, + fontSize: defaultCalendarViewTextSize, + ), + maxLines: 1, + textDirection: TextDirection.ltr, + ), ), - maxLines: 1, - textDirection: TextDirection.ltr, - ), - ), + ), ), ), - ), - ) - : Container(); + ) + : Container(); final Widget dividerWidget = widget.showTodayButton && isNeedViewSwitchOption && !useMobilePlatformUI - ? Container( - alignment: Alignment.center, - color: headerBackgroundColor, - width: dividerWidth, - height: headerHeight, - padding: const EdgeInsets.symmetric(vertical: 5), - child: const VerticalDivider(color: Colors.grey, thickness: 0.5), - ) - : const SizedBox(width: 0, height: 0); + ? Container( + alignment: Alignment.center, + color: headerBackgroundColor, + width: dividerWidth, + height: headerHeight, + padding: const EdgeInsets.symmetric(vertical: 5), + child: const VerticalDivider(color: Colors.grey, thickness: 0.5), + ) + : const SizedBox(width: 0, height: 0); List rowChildren = []; @@ -11451,12 +11526,12 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { }) { final String text = _calendarViews[view]!; - final Color? calendarViewSplashColor = !widget.enableInteraction - ? Colors.transparent - : null; - final Color? allowedViewsColor = isHighlighted - ? highlightColor - : widget.cellBorderColor ?? widget.calendarTheme.cellBorderColor; + final Color? calendarViewSplashColor = + !widget.enableInteraction ? Colors.transparent : null; + final Color? allowedViewsColor = + isHighlighted + ? highlightColor + : widget.cellBorderColor ?? widget.calendarTheme.cellBorderColor; return Container( alignment: Alignment.center, color: headerBackgroundColor, @@ -11464,9 +11539,10 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { height: height, padding: EdgeInsets.all(useMobilePlatformUI ? 2 : 4), child: Material( - color: isHighlighted && (isNeedIcon || useMobilePlatformUI) - ? Colors.grey.withValues(alpha: 0.3) - : headerBackgroundColor, + color: + isHighlighted && (isNeedIcon || useMobilePlatformUI) + ? Colors.grey.withValues(alpha: 0.3) + : headerBackgroundColor, child: InkWell( splashColor: calendarViewSplashColor, highlightColor: calendarViewSplashColor, @@ -11485,21 +11561,24 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { }, child: Semantics( label: semanticLabel ?? text, - child: useMobilePlatformUI - ? Container( - width: width, - height: height, - alignment: Alignment.center, - clipBehavior: Clip.antiAlias, - decoration: const BoxDecoration(color: Colors.transparent), - child: Icon( - Icons.more_vert, - color: style.color, - size: style.fontSize, - ), - ) - : (isNeedIcon - ? Container( + child: + useMobilePlatformUI + ? Container( + width: width, + height: height, + alignment: Alignment.center, + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration( + color: Colors.transparent, + ), + child: Icon( + Icons.more_vert, + color: style.color, + size: style.fontSize, + ), + ) + : (isNeedIcon + ? Container( width: width, height: height, alignment: Alignment.center, @@ -11535,7 +11614,7 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { ], ), ) - : Container( + : Container( decoration: BoxDecoration( border: Border.all(color: allowedViewsColor!), borderRadius: BorderRadius.circular(5.0), @@ -11547,9 +11626,10 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { text, textAlign: TextAlign.center, style: TextStyle( - color: isHighlighted - ? highlightColor - : headerTextColor, + color: + isHighlighted + ? highlightColor + : headerTextColor, fontSize: defaultCalendarViewTextSize, ), maxLines: 1, @@ -11613,11 +11693,12 @@ class _CalendarHeaderViewState extends State<_CalendarHeaderView> { String monthFormat = 'MMMM'; final String? headerDateFormat = widget.headerDateFormat != null && widget.headerDateFormat!.isNotEmpty - ? widget.headerDateFormat - : null; - final List headerFormatString = headerDateFormat == null - ? [] - : CalendarViewHelper.getListFromString(headerDateFormat); + ? widget.headerDateFormat + : null; + final List headerFormatString = + headerDateFormat == null + ? [] + : CalendarViewHelper.getListFromString(headerDateFormat); final int visibleDatesCount = DateTimeHelper.getViewDatesCount( widget.view, widget.numberOfDaysInView, @@ -12139,9 +12220,8 @@ class _AppointmentViewHeaderRenderObject extends RenderStack { final double headerSize = headerView.size.height; /// Current view position on scroll view. - final double viewPosition = _stackViewPort - .getOffsetToReveal(this, 0) - .offset; + final double viewPosition = + _stackViewPort.getOffsetToReveal(this, 0).offset; /// Calculate the current view offset by view position on scroll view, /// scrolled position and scroll view view port. @@ -12189,9 +12269,8 @@ class _AppointmentViewHeaderRenderObject extends RenderStack { /// Check current header offset exits content size, if exist then place the /// header at content size. double _getCurrentOffset(double currentOffset, double contentSize) { - final double currentHeaderPosition = -currentOffset > contentSize - ? contentSize - : -currentOffset; + final double currentHeaderPosition = + -currentOffset > contentSize ? contentSize : -currentOffset; return currentHeaderPosition > 0 ? currentHeaderPosition : 0; } @@ -12342,9 +12421,10 @@ class _CustomSplash extends InteractiveInkFeature { /// Calculate the ripple animation duration from its radius value and start /// the animation. Duration duration = Duration(milliseconds: (_targetRadius * 10).floor()); - duration = duration > _kUnconfirmedRippleSplashDuration - ? _kUnconfirmedRippleSplashDuration - : duration; + duration = + duration > _kUnconfirmedRippleSplashDuration + ? _kUnconfirmedRippleSplashDuration + : duration; _radiusController ..duration = duration ..forward(); @@ -12527,18 +12607,20 @@ class _AgendaDateTimePainter extends CustomPainter { todayTextStyle, calendarTheme, ); - dayTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: dayTextStyle.fontSize, - color: todayTextColor, - ) - : dayTextStyle.copyWith(color: todayTextColor); - dateTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: dateTextStyle.fontSize, - color: todayTextStyleColor, - ) - : dateTextStyle.copyWith(color: todayTextStyleColor); + dayTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: dayTextStyle.fontSize, + color: todayTextColor, + ) + : dayTextStyle.copyWith(color: todayTextColor); + dateTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: dateTextStyle.fontSize, + color: todayTextStyleColor, + ) + : dateTextStyle.copyWith(color: todayTextStyleColor); } /// Draw day label other than web schedule view. @@ -12583,14 +12665,13 @@ class _AgendaDateTimePainter extends CustomPainter { bool isMobile, ) { //// Draw Weekday - final String dayTextFormat = scheduleViewSettings != null - ? scheduleViewSettings!.dayHeaderSettings.dayFormat - : 'EEE'; + final String dayTextFormat = + scheduleViewSettings != null + ? scheduleViewSettings!.dayHeaderSettings.dayFormat + : 'EEE'; TextSpan span = TextSpan( - text: DateFormat( - dayTextFormat, - locale, - ).format(selectedDate!).toUpperCase(), + text: + DateFormat(dayTextFormat, locale).format(selectedDate!).toUpperCase(), style: dayTextStyle, ); _updateTextPainter(span); @@ -12635,12 +12716,13 @@ class _AgendaDateTimePainter extends CustomPainter { yPosition < agendaDateNotifier.value!.hoveringOffset.dy && yPosition + _textPainter.height > agendaDateNotifier.value!.hoveringOffset.dy) { - _linePainter.color = isToday - ? Colors.black.withValues(alpha: 0.1) - : (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + _linePainter.color = + isToday + ? Colors.black.withValues(alpha: 0.1) + : (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); _drawTodayCircle(canvas, xPosition, yPosition, padding); } } @@ -12661,12 +12743,13 @@ class _AgendaDateTimePainter extends CustomPainter { /// Calculate the date text maximum width value. const String maxWidthDateText = '30'; - final String dayText = DateFormat( - isRTL - ? '${scheduleViewSettings!.dayHeaderSettings.dayFormat}, MMM' - : 'MMM, ${scheduleViewSettings!.dayHeaderSettings.dayFormat}', - locale, - ).format(selectedDate!).toUpperCase(); + final String dayText = + DateFormat( + isRTL + ? '${scheduleViewSettings!.dayHeaderSettings.dayFormat}, MMM' + : 'MMM, ${scheduleViewSettings!.dayHeaderSettings.dayFormat}', + locale, + ).format(selectedDate!).toUpperCase(); //// Draw Weekday TextSpan span = TextSpan(text: maxWidthDateText, style: dateTextStyle); @@ -12706,12 +12789,13 @@ class _AgendaDateTimePainter extends CustomPainter { yPosition < agendaDateNotifier.value!.hoveringOffset.dy && (yPosition + _textPainter.height) > agendaDateNotifier.value!.hoveringOffset.dy) { - _linePainter.color = isToday - ? Colors.black.withValues(alpha: 0.1) - : (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + _linePainter.color = + isToday + ? Colors.black.withValues(alpha: 0.1) + : (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); _drawTodayCircle(canvas, dateTextStartPosition, yPosition, padding); } } @@ -12824,9 +12908,8 @@ double _getTargetRadius( return Material.defaultSplashRadius; } - final Size size = rectCallback != null - ? rectCallback().size - : referenceBox.size; + final Size size = + rectCallback != null ? rectCallback().size : referenceBox.size; final double d1 = (position - size.topLeft(Offset.zero)).distance; final double d2 = (position - size.topRight(Offset.zero)).distance; final double d3 = (position - size.bottomLeft(Offset.zero)).distance; diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/theme.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/theme.dart index 081a018bb..92928fbdb 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/theme.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/theme.dart @@ -22,11 +22,12 @@ class SfCalendarThemeColors extends SfCalendarThemeData { Color? get backgroundColor => Colors.transparent; @override - Color? get headerBackgroundColor => Theme.of(context).useMaterial3 - ? (Theme.of(context).brightness == Brightness.light - ? const Color.fromRGBO(247, 242, 251, 1) - : const Color.fromRGBO(37, 35, 42, 1)) - : Colors.transparent; + Color? get headerBackgroundColor => + Theme.of(context).useMaterial3 + ? (Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(247, 242, 251, 1) + : const Color.fromRGBO(37, 35, 42, 1)) + : Colors.transparent; @override Color? get agendaBackgroundColor => Colors.transparent; diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart index 718f19132..78eccbe1b 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart @@ -276,12 +276,14 @@ class _CustomCalendarScrollViewState extends State _dragDetails = ValueNotifier<_DragPaintDetails>( _DragPaintDetails(position: ValueNotifier(null)), ); - widget.controller.forward = widget.isRTL - ? _moveToPreviousViewWithAnimation - : _moveToNextViewWithAnimation; - widget.controller.backward = widget.isRTL - ? _moveToNextViewWithAnimation - : _moveToPreviousViewWithAnimation; + widget.controller.forward = + widget.isRTL + ? _moveToPreviousViewWithAnimation + : _moveToNextViewWithAnimation; + widget.controller.backward = + widget.isRTL + ? _moveToNextViewWithAnimation + : _moveToPreviousViewWithAnimation; _currentChildIndex = 1; _updateVisibleDates(); @@ -301,12 +303,14 @@ class _CustomCalendarScrollViewState extends State @override void didUpdateWidget(CustomCalendarScrollView oldWidget) { if (oldWidget.controller != widget.controller) { - widget.controller.forward = widget.isRTL - ? _moveToPreviousViewWithAnimation - : _moveToNextViewWithAnimation; - widget.controller.backward = widget.isRTL - ? _moveToNextViewWithAnimation - : _moveToPreviousViewWithAnimation; + widget.controller.forward = + widget.isRTL + ? _moveToPreviousViewWithAnimation + : _moveToNextViewWithAnimation; + widget.controller.backward = + widget.isRTL + ? _moveToNextViewWithAnimation + : _moveToPreviousViewWithAnimation; if (!CalendarViewHelper.isSameTimeSlot( oldWidget.controller.selectedDate, @@ -550,12 +554,13 @@ class _CustomCalendarScrollViewState extends State (!widget.isMobilePlatform || (widget.view != CalendarView.month && widget.view != CalendarView.timelineMonth)); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); final double timeLabelWidth = CalendarViewHelper.getTimeLabelWidth( widget.calendar.timeSlotViewSettings.timeRulerSize, widget.view, @@ -564,17 +569,17 @@ class _CustomCalendarScrollViewState extends State widget.calendar.dataSource, widget.view, ); - final double resourceItemHeight = isResourceEnabled - ? CalendarViewHelper.getResourceItemHeight( - widget.calendar.resourceViewSettings.size, - widget.height - viewHeaderHeight - timeLabelWidth, - widget.calendar.resourceViewSettings, - widget.calendar.dataSource!.resources!.length, - ) - : 0; - final double resourceViewSize = isResourceEnabled - ? widget.calendar.resourceViewSettings.size - : 0; + final double resourceItemHeight = + isResourceEnabled + ? CalendarViewHelper.getResourceItemHeight( + widget.calendar.resourceViewSettings.size, + widget.height - viewHeaderHeight - timeLabelWidth, + widget.calendar.resourceViewSettings, + widget.calendar.dataSource!.resources!.length, + ) + : 0; + final double resourceViewSize = + isResourceEnabled ? widget.calendar.resourceViewSettings.size : 0; final bool isMonthView = widget.view == CalendarView.month || widget.view == CalendarView.timelineMonth; @@ -591,88 +596,94 @@ class _CustomCalendarScrollViewState extends State _focusNode.requestFocus(); } }, - onHorizontalDragStart: isTimelineView - ? null - : (DragStartDetails dragStartDetails) { - _onHorizontalStart( - dragStartDetails, - isResourceEnabled, - isTimelineView, - viewHeaderHeight, - timeLabelWidth, - isNeedDragAndDrop, - ); - }, - onHorizontalDragUpdate: isTimelineView - ? null - : (DragUpdateDetails dragUpdateDetails) { - _onHorizontalUpdate( - dragUpdateDetails, - isResourceEnabled, - isMonthView, - isTimelineView, - viewHeaderHeight, - timeLabelWidth, - resourceItemHeight, - weekNumberPanelWidth, - isNeedDragAndDrop, - ); - }, - onHorizontalDragEnd: isTimelineView - ? null - : (DragEndDetails dragEndDetails) { - _onHorizontalEnd( - dragEndDetails, - isResourceEnabled, - isTimelineView, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - weekNumberPanelWidth, - isNeedDragAndDrop, - ); - }, - onVerticalDragStart: isHorizontalNavigation - ? null - : (DragStartDetails dragStartDetails) { - _onVerticalStart( - dragStartDetails, - isResourceEnabled, - isTimelineView, - viewHeaderHeight, - timeLabelWidth, - isNeedDragAndDrop, - ); - }, - onVerticalDragUpdate: isHorizontalNavigation - ? null - : (DragUpdateDetails dragUpdateDetails) { - _onVerticalUpdate( - dragUpdateDetails, - isResourceEnabled, - isMonthView, - isTimelineView, - viewHeaderHeight, - timeLabelWidth, - resourceItemHeight, - weekNumberPanelWidth, - isNeedDragAndDrop, - ); - }, - onVerticalDragEnd: isHorizontalNavigation - ? null - : (DragEndDetails dragEndDetails) { - _onVerticalEnd( - dragEndDetails, - isResourceEnabled, - isTimelineView, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - weekNumberPanelWidth, - isNeedDragAndDrop, - ); - }, + onHorizontalDragStart: + isTimelineView + ? null + : (DragStartDetails dragStartDetails) { + _onHorizontalStart( + dragStartDetails, + isResourceEnabled, + isTimelineView, + viewHeaderHeight, + timeLabelWidth, + isNeedDragAndDrop, + ); + }, + onHorizontalDragUpdate: + isTimelineView + ? null + : (DragUpdateDetails dragUpdateDetails) { + _onHorizontalUpdate( + dragUpdateDetails, + isResourceEnabled, + isMonthView, + isTimelineView, + viewHeaderHeight, + timeLabelWidth, + resourceItemHeight, + weekNumberPanelWidth, + isNeedDragAndDrop, + ); + }, + onHorizontalDragEnd: + isTimelineView + ? null + : (DragEndDetails dragEndDetails) { + _onHorizontalEnd( + dragEndDetails, + isResourceEnabled, + isTimelineView, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + weekNumberPanelWidth, + isNeedDragAndDrop, + ); + }, + onVerticalDragStart: + isHorizontalNavigation + ? null + : (DragStartDetails dragStartDetails) { + _onVerticalStart( + dragStartDetails, + isResourceEnabled, + isTimelineView, + viewHeaderHeight, + timeLabelWidth, + isNeedDragAndDrop, + ); + }, + onVerticalDragUpdate: + isHorizontalNavigation + ? null + : (DragUpdateDetails dragUpdateDetails) { + _onVerticalUpdate( + dragUpdateDetails, + isResourceEnabled, + isMonthView, + isTimelineView, + viewHeaderHeight, + timeLabelWidth, + resourceItemHeight, + weekNumberPanelWidth, + isNeedDragAndDrop, + ); + }, + onVerticalDragEnd: + isHorizontalNavigation + ? null + : (DragEndDetails dragEndDetails) { + _onVerticalEnd( + dragEndDetails, + isResourceEnabled, + isTimelineView, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + weekNumberPanelWidth, + isNeedDragAndDrop, + ); + }, child: CustomScrollViewerLayout( _addViews(), isHorizontalNavigation @@ -694,33 +705,35 @@ class _CustomCalendarScrollViewState extends State timeLabelWidth, ); }, - onLongPressMoveUpdate: isNeedDragAndDrop - ? (LongPressMoveUpdateDetails details) { - _handleLongPressMove( - details.localPosition, - isTimelineView, - isResourceEnabled, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - resourceItemHeight, - weekNumberPanelWidth, - ); - } - : null, - onLongPressEnd: isNeedDragAndDrop - ? (LongPressEndDetails details) { - _handleLongPressEnd( - details.localPosition, - isTimelineView, - isResourceEnabled, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - weekNumberPanelWidth, - ); - } - : null, + onLongPressMoveUpdate: + isNeedDragAndDrop + ? (LongPressMoveUpdateDetails details) { + _handleLongPressMove( + details.localPosition, + isTimelineView, + isResourceEnabled, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + resourceItemHeight, + weekNumberPanelWidth, + ); + } + : null, + onLongPressEnd: + isNeedDragAndDrop + ? (LongPressEndDetails details) { + _handleLongPressEnd( + details.localPosition, + isTimelineView, + isResourceEnabled, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + weekNumberPanelWidth, + ); + } + : null, child: Stack( children: [ Positioned( @@ -731,63 +744,67 @@ class _CustomCalendarScrollViewState extends State child: FocusScope( node: _focusNode, onKeyEvent: _onKeyDown, - child: isTimelineView - ? Listener( - onPointerSignal: _handlePointerSignal, - child: RawGestureDetector( - gestures: { - HorizontalDragGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - HorizontalDragGestureRecognizer - >(() => HorizontalDragGestureRecognizer(), ( - HorizontalDragGestureRecognizer instance, - ) { - instance.onUpdate = - (DragUpdateDetails details) { - _handleDragUpdate( - details, - isTimelineView, - isResourceEnabled, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - resourceItemHeight, - weekNumberPanelWidth, - isNeedDragAndDrop, - resourceViewSize, - ); - }; - instance.onStart = (DragStartDetails details) { - _handleDragStart( - details, - isNeedDragAndDrop, - isTimelineView, - isResourceEnabled, - viewHeaderHeight, - timeLabelWidth, - resourceViewSize, - ); - }; - instance.onEnd = (DragEndDetails details) { - _handleDragEnd( - details, - isTimelineView, - isResourceEnabled, - isMonthView, - viewHeaderHeight, - timeLabelWidth, - weekNumberPanelWidth, - isNeedDragAndDrop, - ); - }; - instance.onCancel = _handleDragCancel; - }), - }, - behavior: HitTestBehavior.opaque, - child: customScrollWidget, - ), - ) - : customScrollWidget, + child: + isTimelineView + ? Listener( + onPointerSignal: _handlePointerSignal, + child: RawGestureDetector( + gestures: { + HorizontalDragGestureRecognizer: + GestureRecognizerFactoryWithHandlers< + HorizontalDragGestureRecognizer + >(() => HorizontalDragGestureRecognizer(), ( + HorizontalDragGestureRecognizer instance, + ) { + instance.onUpdate = ( + DragUpdateDetails details, + ) { + _handleDragUpdate( + details, + isTimelineView, + isResourceEnabled, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + resourceItemHeight, + weekNumberPanelWidth, + isNeedDragAndDrop, + resourceViewSize, + ); + }; + instance.onStart = ( + DragStartDetails details, + ) { + _handleDragStart( + details, + isNeedDragAndDrop, + isTimelineView, + isResourceEnabled, + viewHeaderHeight, + timeLabelWidth, + resourceViewSize, + ); + }; + instance.onEnd = (DragEndDetails details) { + _handleDragEnd( + details, + isTimelineView, + isResourceEnabled, + isMonthView, + viewHeaderHeight, + timeLabelWidth, + weekNumberPanelWidth, + isNeedDragAndDrop, + ); + }; + instance.onCancel = _handleDragCancel; + }), + }, + behavior: HitTestBehavior.opaque, + child: customScrollWidget, + ), + ) + : customScrollWidget, ), ), Positioned( @@ -893,9 +910,10 @@ class _CustomCalendarScrollViewState extends State yPosition = yPosition - details.dy; _dragDifferenceOffset = Offset(xPosition, yPosition); } else { - final double allDayHeight = currentState._isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : currentState._allDayHeight; + final double allDayHeight = + currentState._isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : currentState._allDayHeight; xPosition = appointmentPosition.dx - details.dx; yPosition = appointmentPosition.dy + @@ -927,8 +945,8 @@ class _CustomCalendarScrollViewState extends State _dragDetails.value.position.value = details + _dragDifferenceOffset!; _dragDetails.value.draggingTime = yPosition <= 0 && widget.view != CalendarView.month && !isTimelineView - ? null - : _dragDetails.value.appointmentView!.appointment!.actualStartTime; + ? null + : _dragDetails.value.appointmentView!.appointment!.actualStartTime; final dynamic dragStartAppointment = _getCalendarAppointmentToObject( appointmentView.appointment, widget.calendar, @@ -999,9 +1017,10 @@ class _CustomCalendarScrollViewState extends State final Offset appointmentPosition = details + _dragDifferenceOffset!; final _CalendarViewState currentState = _getCurrentViewByVisibleDates()!; - final double allDayHeight = currentState._isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : currentState._allDayHeight; + final double allDayHeight = + currentState._isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : currentState._allDayHeight; final double timeIntervalHeight = currentState._getTimeIntervalHeight( widget.calendar, @@ -1735,10 +1754,11 @@ class _CustomCalendarScrollViewState extends State ._timelineViewVerticalScrollController! .position .maxScrollExtent) { - scrollPosition = currentState - ._timelineViewVerticalScrollController! - .position - .maxScrollExtent; + scrollPosition = + currentState + ._timelineViewVerticalScrollController! + .position + .maxScrollExtent; } await currentState._timelineViewVerticalScrollController!.position @@ -1969,15 +1989,17 @@ class _CustomCalendarScrollViewState extends State xPosition = widget.width - 1; } - final double overAllWidth = isTimelineView - ? currentState._timeIntervalHeight * - (currentState._horizontalLinesCount! * - currentState.widget.visibleDates.length) - : widget.width; - final double overAllHeight = isTimelineView || isMonthView - ? widget.height - : currentState._timeIntervalHeight * - currentState._horizontalLinesCount!; + final double overAllWidth = + isTimelineView + ? currentState._timeIntervalHeight * + (currentState._horizontalLinesCount! * + currentState.widget.visibleDates.length) + : widget.width; + final double overAllHeight = + isTimelineView || isMonthView + ? widget.height + : currentState._timeIntervalHeight * + currentState._horizontalLinesCount!; if (isTimelineView && overAllWidth < widget.width && @@ -1997,21 +2019,23 @@ class _CustomCalendarScrollViewState extends State _dragDetails.value.appointmentView!.appointmentRect!.height; } - draggingTime = currentState._getDateFromPosition( - xPosition, - yPosition, - timeLabelWidth, - )!; - if (!isMonthView) { - if (isTimelineView) { - final DateTime time = _timeFromPosition( - draggingTime, - widget.calendar.timeSlotViewSettings, + draggingTime = + currentState._getDateFromPosition( xPosition, - currentState, - timeIntervalHeight, - isTimelineView, + yPosition, + timeLabelWidth, )!; + if (!isMonthView) { + if (isTimelineView) { + final DateTime time = + _timeFromPosition( + draggingTime, + widget.calendar.timeSlotViewSettings, + xPosition, + currentState, + timeIntervalHeight, + isTimelineView, + )!; draggingTime = DateTime( draggingTime.year, @@ -2028,14 +2052,15 @@ class _CustomCalendarScrollViewState extends State draggingTime.day, ); } else { - draggingTime = _timeFromPosition( - draggingTime, - widget.calendar.timeSlotViewSettings, - yPosition, - currentState, - timeIntervalHeight, - isTimelineView, - )!; + draggingTime = + _timeFromPosition( + draggingTime, + widget.calendar.timeSlotViewSettings, + yPosition, + currentState, + timeIntervalHeight, + isTimelineView, + )!; } } } @@ -2046,8 +2071,8 @@ class _CustomCalendarScrollViewState extends State ); _dragDetails.value.draggingTime = yPosition <= 0 && widget.view != CalendarView.month && !isTimelineView - ? null - : draggingTime; + ? null + : draggingTime; _dragDetails.value.position.value = Offset( _dragDetails.value.position.value!.dx, _dragDetails.value.position.value!.dy + 0.1, @@ -2083,10 +2108,11 @@ class _CustomCalendarScrollViewState extends State widget.calendar.dataSource!.resources![sourceSelectedResourceIndex]; } - final int currentMonth = currentState - .widget - .visibleDates[currentState.widget.visibleDates.length ~/ 2] - .month; + final int currentMonth = + currentState + .widget + .visibleDates[currentState.widget.visibleDates.length ~/ 2] + .month; final int timeInterval = CalendarViewHelper.getTimeInterval( widget.calendar.timeSlotViewSettings, @@ -2096,12 +2122,13 @@ class _CustomCalendarScrollViewState extends State final Duration appointmentDuration = _dragDetails.value.appointmentView!.appointment!.isAllDay && - widget.view != CalendarView.month && - !isTimelineView - ? const Duration(hours: 1) - : _dragDetails.value.appointmentView!.appointment!.endTime.difference( - _dragDetails.value.appointmentView!.appointment!.startTime, - ); + widget.view != CalendarView.month && + !isTimelineView + ? const Duration(hours: 1) + : _dragDetails.value.appointmentView!.appointment!.endTime + .difference( + _dragDetails.value.appointmentView!.appointment!.startTime, + ); final DateTime updatedEndTime = updateStartTime.add(appointmentDuration); if (CalendarViewHelper.isDraggingAppointmentHasDisabledCell( @@ -2166,9 +2193,10 @@ class _CustomCalendarScrollViewState extends State final Offset appointmentPosition = details + _dragDifferenceOffset!; final _CalendarViewState currentState = _getCurrentViewByVisibleDates()!; - final double allDayHeight = currentState._isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : currentState._allDayHeight; + final double allDayHeight = + currentState._isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : currentState._allDayHeight; final double timeIntervalHeight = currentState._getTimeIntervalHeight( widget.calendar, widget.view, @@ -2215,15 +2243,17 @@ class _CustomCalendarScrollViewState extends State xPosition = widget.width - 1; } - final double overAllWidth = isTimelineView - ? currentState._timeIntervalHeight * - (currentState._horizontalLinesCount! * - currentState.widget.visibleDates.length) - : widget.width; - final double overAllHeight = isTimelineView || isMonthView - ? widget.height - : currentState._timeIntervalHeight * - currentState._horizontalLinesCount!; + final double overAllWidth = + isTimelineView + ? currentState._timeIntervalHeight * + (currentState._horizontalLinesCount! * + currentState.widget.visibleDates.length) + : widget.width; + final double overAllHeight = + isTimelineView || isMonthView + ? widget.height + : currentState._timeIntervalHeight * + currentState._horizontalLinesCount!; if (isTimelineView && overAllWidth < widget.width && @@ -2252,14 +2282,15 @@ class _CustomCalendarScrollViewState extends State ); if (!isMonthView) { if (isTimelineView) { - final DateTime time = _timeFromPosition( - dropTime!, - widget.calendar.timeSlotViewSettings, - xPosition, - currentState, - timeIntervalHeight, - isTimelineView, - )!; + final DateTime time = + _timeFromPosition( + dropTime!, + widget.calendar.timeSlotViewSettings, + xPosition, + currentState, + timeIntervalHeight, + isTimelineView, + )!; dropTime = DateTime( dropTime.year, dropTime.month, @@ -2304,10 +2335,11 @@ class _CustomCalendarScrollViewState extends State widget.calendar.dataSource!.resources![sourceSelectedResourceIndex]; } - final int currentMonth = currentState - .widget - .visibleDates[currentState.widget.visibleDates.length ~/ 2] - .month; + final int currentMonth = + currentState + .widget + .visibleDates[currentState.widget.visibleDates.length ~/ 2] + .month; bool isAllDay = appointment!.isAllDay; if (!isTimelineView && widget.view != CalendarView.month) { @@ -2320,19 +2352,19 @@ class _CustomCalendarScrollViewState extends State isAllDay = appointment.isAllDay; } - DateTime updateStartTime = isAllDay - ? DateTime(dropTime!.year, dropTime.month, dropTime.day) - : dropTime!; + DateTime updateStartTime = + isAllDay + ? DateTime(dropTime!.year, dropTime.month, dropTime.day) + : dropTime!; final Duration appointmentDuration = appointment.isAllDay && - widget.view != CalendarView.month && - !isTimelineView - ? const Duration(hours: 1) - : appointment.endTime.difference(appointment.startTime); - DateTime updatedEndTime = isAllDay - ? updateStartTime - : updateStartTime.add(appointmentDuration); + widget.view != CalendarView.month && + !isTimelineView + ? const Duration(hours: 1) + : appointment.endTime.difference(appointment.startTime); + DateTime updatedEndTime = + isAllDay ? updateStartTime : updateStartTime.add(appointmentDuration); final int timeInterval = CalendarViewHelper.getTimeInterval( widget.calendar.timeSlotViewSettings, @@ -2410,9 +2442,10 @@ class _CustomCalendarScrollViewState extends State parentAppointment.exactEndTime, ), specificStartDate: currentState.widget.visibleDates[0], - specificEndDate: currentState - .widget - .visibleDates[currentState.widget.visibleDates.length - 1], + specificEndDate: + currentState + .widget + .visibleDates[currentState.widget.visibleDates.length - 1], ); for ( @@ -2524,12 +2557,11 @@ class _CustomCalendarScrollViewState extends State parentAppointment.recurrenceExceptionDates != null ? parentAppointment.recurrenceExceptionDates!.add(exceptionDate) : parentAppointment.recurrenceExceptionDates = [ - exceptionDate, - ]; + exceptionDate, + ]; - appointment.id = appointment.recurrenceId != null - ? appointment.id - : null; + appointment.id = + appointment.recurrenceId != null ? appointment.id : null; appointment.recurrenceId = appointment.recurrenceId ?? parentAppointment.id; appointment.recurrenceRule = null; @@ -2850,9 +2882,8 @@ class _CustomCalendarScrollViewState extends State void _handlePointerSignal(PointerSignalEvent event) { final _CalendarViewState? viewKey = _getCurrentViewByVisibleDates(); if (event is PointerScrollEvent && viewKey != null) { - double scrolledPosition = widget.isRTL - ? -event.scrollDelta.dx - : event.scrollDelta.dx; + double scrolledPosition = + widget.isRTL ? -event.scrollDelta.dx : event.scrollDelta.dx; /// Check the scrolling is vertical and timeline view does not have /// vertical scroll view then scroll the vertical movement on @@ -2864,9 +2895,8 @@ class _CustomCalendarScrollViewState extends State .position .maxScrollExtent == 0) { - scrolledPosition = widget.isRTL - ? -event.scrollDelta.dy - : event.scrollDelta.dy; + scrolledPosition = + widget.isRTL ? -event.scrollDelta.dy : event.scrollDelta.dy; } final double targetScrollOffset = math.min( @@ -2886,9 +2916,9 @@ class _CustomCalendarScrollViewState extends State widget.getCalendarState(_updateCalendarStateDetails); final List? nonWorkingDays = (widget.view == CalendarView.workWeek || - widget.view == CalendarView.timelineWorkWeek) - ? widget.calendar.timeSlotViewSettings.nonWorkingDays - : null; + widget.view == CalendarView.timelineWorkWeek) + ? widget.calendar.timeSlotViewSettings.nonWorkingDays + : null; final int visibleDatesCount = DateTimeHelper.getViewDatesCount( widget.view, widget.calendar.monthViewSettings.numberOfWeeksInView, @@ -2916,24 +2946,27 @@ class _CustomCalendarScrollViewState extends State nonWorkingDays, ); - _visibleDates = getVisibleDates( - currentDate, - nonWorkingDays, - widget.calendar.firstDayOfWeek, - visibleDatesCount, - ).cast(); - _previousViewVisibleDates = getVisibleDates( - widget.isRTL ? nextDate : prevDate, - nonWorkingDays, - widget.calendar.firstDayOfWeek, - visibleDatesCount, - ).cast(); - _nextViewVisibleDates = getVisibleDates( - widget.isRTL ? prevDate : nextDate, - nonWorkingDays, - widget.calendar.firstDayOfWeek, - visibleDatesCount, - ).cast(); + _visibleDates = + getVisibleDates( + currentDate, + nonWorkingDays, + widget.calendar.firstDayOfWeek, + visibleDatesCount, + ).cast(); + _previousViewVisibleDates = + getVisibleDates( + widget.isRTL ? nextDate : prevDate, + nonWorkingDays, + widget.calendar.firstDayOfWeek, + visibleDatesCount, + ).cast(); + _nextViewVisibleDates = + getVisibleDates( + widget.isRTL ? prevDate : nextDate, + nonWorkingDays, + widget.calendar.firstDayOfWeek, + visibleDatesCount, + ).cast(); if (widget.view == CalendarView.timelineMonth) { _visibleDates = DateTimeHelper.getCurrentMonthDates(_visibleDates); _previousViewVisibleDates = DateTimeHelper.getCurrentMonthDates( @@ -2966,9 +2999,9 @@ class _CustomCalendarScrollViewState extends State DateTime currentViewDate = _currentViewVisibleDates[0]; final List? nonWorkingDays = (widget.view == CalendarView.workWeek || - widget.view == CalendarView.timelineWorkWeek) - ? widget.calendar.timeSlotViewSettings.nonWorkingDays - : null; + widget.view == CalendarView.timelineWorkWeek) + ? widget.calendar.timeSlotViewSettings.nonWorkingDays + : null; final int visibleDatesCount = DateTimeHelper.getViewDatesCount( widget.view, widget.calendar.monthViewSettings.numberOfWeeksInView, @@ -3001,12 +3034,13 @@ class _CustomCalendarScrollViewState extends State ); } - List dates = getVisibleDates( - currentViewDate, - nonWorkingDays, - widget.calendar.firstDayOfWeek, - visibleDatesCount, - ).cast(); + List dates = + getVisibleDates( + currentViewDate, + nonWorkingDays, + widget.calendar.firstDayOfWeek, + visibleDatesCount, + ).cast(); if (widget.view == CalendarView.timelineMonth) { dates = DateTimeHelper.getCurrentMonthDates(dates); @@ -3025,9 +3059,9 @@ class _CustomCalendarScrollViewState extends State DateTime currentViewDate = _currentViewVisibleDates[0]; final List? nonWorkingDays = (widget.view == CalendarView.workWeek || - widget.view == CalendarView.timelineWorkWeek) - ? widget.calendar.timeSlotViewSettings.nonWorkingDays - : null; + widget.view == CalendarView.timelineWorkWeek) + ? widget.calendar.timeSlotViewSettings.nonWorkingDays + : null; final int visibleDatesCount = DateTimeHelper.getViewDatesCount( widget.view, widget.calendar.monthViewSettings.numberOfWeeksInView, @@ -3060,12 +3094,13 @@ class _CustomCalendarScrollViewState extends State ); } - List dates = getVisibleDates( - currentViewDate, - nonWorkingDays, - widget.calendar.firstDayOfWeek, - visibleDatesCount, - ).cast(); + List dates = + getVisibleDates( + currentViewDate, + nonWorkingDays, + widget.calendar.firstDayOfWeek, + visibleDatesCount, + ).cast(); if (widget.view == CalendarView.timelineMonth) { dates = DateTimeHelper.getCurrentMonthDates(dates); @@ -3133,12 +3168,12 @@ class _CustomCalendarScrollViewState extends State final CalendarTimeRegion region = _getCalendarTimeRegionFromTimeRegion( timeRegion, ); - region.actualStartTime = - AppointmentHelper.convertTimeToAppointmentTimeZone( - region.startTime, - region.timeZone, - widget.calendar.timeZone, - ); + region + .actualStartTime = AppointmentHelper.convertTimeToAppointmentTimeZone( + region.startTime, + region.timeZone, + widget.calendar.timeZone, + ); region.actualEndTime = AppointmentHelper.convertTimeToAppointmentTimeZone( region.endTime, region.timeZone, @@ -3239,10 +3274,11 @@ class _CustomCalendarScrollViewState extends State DateTime recursiveDate, String? calendarTimeZone, ) { - final int minutes = AppointmentHelper.getDifference( - region.actualStartTime, - region.actualEndTime, - ).inMinutes; + final int minutes = + AppointmentHelper.getDifference( + region.actualStartTime, + region.actualEndTime, + ).inMinutes; final DateTime actualEndTime = DateTimeHelper.getDateTimeValue( addDuration(recursiveDate, Duration(minutes: minutes)), ); @@ -4298,13 +4334,14 @@ class _CustomCalendarScrollViewState extends State } } } else { - final double xPosition = widget.view == CalendarView.timelineMonth - ? 0 - : AppointmentHelper.timeToPosition( - widget.calendar, - selectedDate!, - currentViewState._timeIntervalHeight, - ); + final double xPosition = + widget.view == CalendarView.timelineMonth + ? 0 + : AppointmentHelper.timeToPosition( + widget.calendar, + selectedDate!, + currentViewState._timeIntervalHeight, + ); final int rowIndex = _getRowOfDate( currentView.visibleDates, selectedDate!, @@ -4440,13 +4477,14 @@ class _CustomCalendarScrollViewState extends State } } } else { - final double xPosition = widget.view == CalendarView.timelineMonth - ? 0 - : AppointmentHelper.timeToPosition( - widget.calendar, - selectedDate!, - currentViewState._timeIntervalHeight, - ); + final double xPosition = + widget.view == CalendarView.timelineMonth + ? 0 + : AppointmentHelper.timeToPosition( + widget.calendar, + selectedDate!, + currentViewState._timeIntervalHeight, + ); final int rowIndex = _getRowOfDate( currentView.visibleDates, selectedDate!, @@ -4753,15 +4791,15 @@ class _CustomCalendarScrollViewState extends State resourceItemHeight; scrollPosition = scrollPosition > - currentViewState + currentViewState + ._timelineViewVerticalScrollController! + .position + .maxScrollExtent + ? currentViewState ._timelineViewVerticalScrollController! .position .maxScrollExtent - ? currentViewState - ._timelineViewVerticalScrollController! - .position - .maxScrollExtent - : scrollPosition; + : scrollPosition; currentViewState._timelineViewVerticalScrollController!.jumpTo( scrollPosition, ); @@ -4995,9 +5033,10 @@ class _CustomCalendarScrollViewState extends State widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final ScrollController scrollController = isResourceEnabled - ? widget.resourcePanelScrollController! - : currentViewState._scrollController!; + final ScrollController scrollController = + isResourceEnabled + ? widget.resourcePanelScrollController! + : currentViewState._scrollController!; final TargetPlatform platform = Theme.of(context).platform; double difference = 0; @@ -5030,9 +5069,10 @@ class _CustomCalendarScrollViewState extends State allDayHeight = _kAllDayLayoutHeight; viewHeaderHeight = 0; } else { - allDayHeight = allDayHeight > _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : allDayHeight; + allDayHeight = + allDayHeight > _kAllDayLayoutHeight + ? _kAllDayLayoutHeight + : allDayHeight; } final double timeRulerSize = CalendarViewHelper.getTimeLabelWidth( @@ -5040,9 +5080,10 @@ class _CustomCalendarScrollViewState extends State widget.controller.view!, ); - final double viewPortHeight = isResourceEnabled - ? widget.height - viewHeaderHeight - timeRulerSize - : widget.height - allDayHeight - viewHeaderHeight; + final double viewPortHeight = + isResourceEnabled + ? widget.height - viewHeaderHeight - timeRulerSize + : widget.height - allDayHeight - viewHeaderHeight; final double viewPortEndPosition = scrollController.position.pixels + viewPortHeight; @@ -5076,14 +5117,13 @@ class _CustomCalendarScrollViewState extends State AppointmentView? selectedAppointment; bool isAllDay = currentAllDayAppointment != null; - final List appointmentCollection = currentVisibleViewState - ._appointmentLayout - .getAppointmentViewCollection(); + final List appointmentCollection = + currentVisibleViewState._appointmentLayout + .getAppointmentViewCollection(); final List allDayAppointmentCollection = _updateCalendarStateDetails.allDayAppointmentViewCollection; - final List tempAppColl = isAllDay - ? allDayAppointmentCollection - : appointmentCollection; + final List tempAppColl = + isAllDay ? allDayAppointmentCollection : appointmentCollection; if (HardwareKeyboard.instance.isShiftPressed) { if (event.logicalKey == LogicalKeyboardKey.tab) { if (currentAllDayAppointment != null || @@ -5093,18 +5133,21 @@ class _CustomCalendarScrollViewState extends State ); index -= 1; if (tempAppColl.length > index && !index.isNegative) { - selectedAppointment = tempAppColl[index].appointment != null - ? tempAppColl[index] - : null; + selectedAppointment = + tempAppColl[index].appointment != null + ? tempAppColl[index] + : null; } } if (currentSelectedAppointment != null && selectedAppointment == null) { isAllDay = allDayAppointmentCollection.isNotEmpty; - selectedAppointment = isAllDay - ? allDayAppointmentCollection[allDayAppointmentCollection.length - - 1] - : null; + selectedAppointment = + isAllDay + ? allDayAppointmentCollection[allDayAppointmentCollection + .length - + 1] + : null; } else if (currentSelectedAppointment == null && currentAllDayAppointment == null && selectedAppointment == null) { @@ -5124,9 +5167,10 @@ class _CustomCalendarScrollViewState extends State break; } } else { - selectedAppointment = appointmentCollection.isNotEmpty - ? appointmentCollection[appointmentCollection.length - 1] - : null; + selectedAppointment = + appointmentCollection.isNotEmpty + ? appointmentCollection[appointmentCollection.length - 1] + : null; } } @@ -5146,9 +5190,10 @@ class _CustomCalendarScrollViewState extends State ); index += 1; if (tempAppColl.length > index) { - selectedAppointment = tempAppColl[index].appointment != null - ? tempAppColl[index] - : null; + selectedAppointment = + tempAppColl[index].appointment != null + ? tempAppColl[index] + : null; } } @@ -5172,11 +5217,12 @@ class _CustomCalendarScrollViewState extends State } } else { isAllDay = allDayAppointmentCollection.isNotEmpty; - selectedAppointment = isAllDay - ? allDayAppointmentCollection[0] - : appointmentCollection.isNotEmpty - ? appointmentCollection[0] - : null; + selectedAppointment = + isAllDay + ? allDayAppointmentCollection[0] + : appointmentCollection.isNotEmpty + ? appointmentCollection[0] + : null; } } @@ -5253,9 +5299,8 @@ class _CustomCalendarScrollViewState extends State ._scrollController! .position .viewportDimension; - final double resourceViewSize = isResourceEnabled - ? widget.calendar.resourceViewSettings.size - : 0; + final double resourceViewSize = + isResourceEnabled ? widget.calendar.resourceViewSettings.size : 0; final bool isTimeline = CalendarViewHelper.isTimelineView( widget.controller.view!, ); @@ -5274,9 +5319,10 @@ class _CustomCalendarScrollViewState extends State allDayHeight = _kAllDayLayoutHeight; viewHeaderHeight = 0; } else { - allDayHeight = allDayHeight > _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : allDayHeight; + allDayHeight = + allDayHeight > _kAllDayLayoutHeight + ? _kAllDayLayoutHeight + : allDayHeight; } viewPortSize = widget.height - allDayHeight - viewHeaderHeight; offset = selectedAppointment.appointmentRect!.top; @@ -5447,19 +5493,19 @@ class _CustomCalendarScrollViewState extends State currentVisibleViewState._selectionPainter!.appointmentView; final List? selectedAppointments = widget.controller.view == CalendarView.month && - selectedAppointment == null - ? AppointmentHelper.getSelectedDateAppointments( - _updateCalendarStateDetails.appointments, - widget.calendar.timeZone, - _updateCalendarStateDetails.selectedDate, - ) - : selectedAppointment != null - ? [selectedAppointment.appointment!] - : null; + selectedAppointment == null + ? AppointmentHelper.getSelectedDateAppointments( + _updateCalendarStateDetails.appointments, + widget.calendar.timeZone, + _updateCalendarStateDetails.selectedDate, + ) + : selectedAppointment != null + ? [selectedAppointment.appointment!] + : null; final CalendarElement tappedElement = _updateCalendarStateDetails.selectedDate != null - ? CalendarElement.calendarCell - : CalendarElement.appointment; + ? CalendarElement.calendarCell + : CalendarElement.appointment; CalendarViewHelper.raiseCalendarTapCallback( widget.calendar, @@ -5473,14 +5519,15 @@ class _CustomCalendarScrollViewState extends State tappedElement, isResourcesEnabled ? widget.calendar.dataSource!.resources![currentVisibleViewState - ._selectedResourceIndex] + ._selectedResourceIndex] : null, ); } - final int previousResourceIndex = isResourcesEnabled - ? currentVisibleViewState._selectedResourceIndex - : -1; + final int previousResourceIndex = + isResourcesEnabled + ? currentVisibleViewState._selectedResourceIndex + : -1; if ((currentVisibleViewState._selectionPainter!.selectedDate != null && isDateWithInDateRange( @@ -5496,15 +5543,17 @@ class _CustomCalendarScrollViewState extends State )) || (currentSelectedAppointment != null || currentAllDayAppointment != null)) { - final int resourceIndex = isResourcesEnabled - ? currentVisibleViewState._selectedResourceIndex - : -1; + final int resourceIndex = + isResourcesEnabled + ? currentVisibleViewState._selectedResourceIndex + : -1; - final DateTime? selectedAppointmentDate = currentAllDayAppointment != null - ? AppointmentHelper.convertToStartTime( - currentAllDayAppointment.appointment!.actualStartTime, - ) - : currentSelectedAppointment?.appointment!.actualStartTime; + final DateTime? selectedAppointmentDate = + currentAllDayAppointment != null + ? AppointmentHelper.convertToStartTime( + currentAllDayAppointment.appointment!.actualStartTime, + ) + : currentSelectedAppointment?.appointment!.actualStartTime; final bool isAllDayAppointment = currentAllDayAppointment != null; @@ -5547,7 +5596,7 @@ class _CustomCalendarScrollViewState extends State selectedDate, isResourcesEnabled ? widget.resourceCollection![currentVisibleViewState - ._selectedResourceIndex] + ._selectedResourceIndex] : null, ); } @@ -6406,28 +6455,27 @@ class _CalendarViewState extends State<_CalendarView> duration: const Duration(milliseconds: 200), vsync: this, ); - _heightAnimation = - CurveTween(curve: Curves.easeIn).animate(_animationController!) - ..addListener(() { - setState(() { - /* Animates the all day panel height when + _heightAnimation = CurveTween( + curve: Curves.easeIn, + ).animate(_animationController!)..addListener(() { + setState(() { + /* Animates the all day panel height when expanding or collapsing */ - }); - }); + }); + }); _expanderAnimationController = AnimationController( duration: const Duration(milliseconds: 100), vsync: this, ); - _allDayExpanderAnimation = - CurveTween( - curve: Curves.easeIn, - ).animate(_expanderAnimationController!)..addListener(() { - setState(() { - /* Animates the all day panel height when + _allDayExpanderAnimation = CurveTween( + curve: Curves.easeIn, + ).animate(_expanderAnimationController!)..addListener(() { + setState(() { + /* Animates the all day panel height when expanding or collapsing */ - }); - }); + }); + }); } _timeIntervalHeight = _getTimeIntervalHeight( @@ -6445,8 +6493,8 @@ class _CalendarViewState extends State<_CalendarView> ); _scrollController = ScrollController()..addListener(_scrollListener); if (CalendarViewHelper.isTimelineView(widget.view)) { - _timelineRulerController = ScrollController() - ..addListener(_timeRulerListener); + _timelineRulerController = + ScrollController()..addListener(_timeRulerListener); _timelineViewHeaderScrollController = ScrollController(); _timelineViewAnimationController = AnimationController( duration: const Duration(milliseconds: 300), @@ -6455,8 +6503,8 @@ class _CalendarViewState extends State<_CalendarView> _timelineViewAnimation = _timelineViewTween.animate( _timelineViewAnimationController!, )..addListener(_scrollAnimationListener); - _timelineViewVerticalScrollController = ScrollController() - ..addListener(_updateResourceScroll); + _timelineViewVerticalScrollController = + ScrollController()..addListener(_updateResourceScroll); widget.resourcePanelScrollController?.addListener( _updateResourcePanelScroll, ); @@ -6660,28 +6708,28 @@ class _CalendarViewState extends State<_CalendarView> widget.view != CalendarView.month && widget.view != CalendarView.timelineMonth ? Timer.periodic(const Duration(seconds: 1), (Timer t) { - final DateTime today = DateTime.now(); - final DateTime viewEndDate = - widget.visibleDates[widget.visibleDates.length - 1]; - - /// Check the today date is in between visible date range and - /// today date hour and minute is 0(12 AM) because in day view - /// current time as Feb 16, 23.59 and changed to Feb 17 then view - /// will update both Feb 16 and 17 views. - if (!isDateWithInDateRange( - widget.visibleDates[0], - viewEndDate, - today, - ) && - !(today.hour == 0 && - today.minute == 0 && - isSameDate(addDays(today, -1), viewEndDate))) { - return; - } + final DateTime today = DateTime.now(); + final DateTime viewEndDate = + widget.visibleDates[widget.visibleDates.length - 1]; + + /// Check the today date is in between visible date range and + /// today date hour and minute is 0(12 AM) because in day view + /// current time as Feb 16, 23.59 and changed to Feb 17 then view + /// will update both Feb 16 and 17 views. + if (!isDateWithInDateRange( + widget.visibleDates[0], + viewEndDate, + today, + ) && + !(today.hour == 0 && + today.minute == 0 && + isSameDate(addDays(today, -1), viewEndDate))) { + return; + } - _currentTimeNotifier.value = - (today.day * 24 * 60) + (today.hour * 60) + today.minute; - }) + _currentTimeNotifier.value = + (today.day * 24 * 60) + (today.hour * 60) + today.minute; + }) : null; } @@ -6738,12 +6786,12 @@ class _CalendarViewState extends State<_CalendarView> Widget _getMonthView() { final SystemMouseCursor currentCursor = _mouseCursor == SystemMouseCursors.resizeUp || - _mouseCursor == SystemMouseCursors.resizeDown - ? SystemMouseCursors.resizeUpDown - : _mouseCursor == SystemMouseCursors.resizeRight || - _mouseCursor == SystemMouseCursors.resizeLeft - ? SystemMouseCursors.resizeLeftRight - : _mouseCursor; + _mouseCursor == SystemMouseCursors.resizeDown + ? SystemMouseCursors.resizeUpDown + : _mouseCursor == SystemMouseCursors.resizeRight || + _mouseCursor == SystemMouseCursors.resizeLeft + ? SystemMouseCursors.resizeLeftRight + : _mouseCursor; return MouseRegion( cursor: currentCursor, @@ -6803,12 +6851,12 @@ class _CalendarViewState extends State<_CalendarView> final SystemMouseCursor currentCursor = _mouseCursor == SystemMouseCursors.resizeUp || - _mouseCursor == SystemMouseCursors.resizeDown - ? SystemMouseCursors.resizeUpDown - : _mouseCursor == SystemMouseCursors.resizeRight || - _mouseCursor == SystemMouseCursors.resizeLeft - ? SystemMouseCursors.resizeLeftRight - : _mouseCursor; + _mouseCursor == SystemMouseCursors.resizeDown + ? SystemMouseCursors.resizeUpDown + : _mouseCursor == SystemMouseCursors.resizeRight || + _mouseCursor == SystemMouseCursors.resizeLeft + ? SystemMouseCursors.resizeLeftRight + : _mouseCursor; return MouseRegion( cursor: currentCursor, @@ -6861,12 +6909,13 @@ class _CalendarViewState extends State<_CalendarView> if (isCurrentView) { _allDayHeight = _kAllDayLayoutHeight > viewHeaderHeight && - _updateCalendarStateDetails.allDayPanelHeight > viewHeaderHeight - ? _updateCalendarStateDetails.allDayPanelHeight > - _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : _updateCalendarStateDetails.allDayPanelHeight - : viewHeaderHeight; + _updateCalendarStateDetails.allDayPanelHeight > + viewHeaderHeight + ? _updateCalendarStateDetails.allDayPanelHeight > + _kAllDayLayoutHeight + ? _kAllDayLayoutHeight + : _updateCalendarStateDetails.allDayPanelHeight + : viewHeaderHeight; if (_allDayHeight < _updateCalendarStateDetails.allDayPanelHeight) { _allDayHeight += kAllDayAppointmentHeight; } @@ -6876,8 +6925,8 @@ class _CalendarViewState extends State<_CalendarView> } else if (isCurrentView) { _allDayHeight = _updateCalendarStateDetails.allDayPanelHeight > _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : _updateCalendarStateDetails.allDayPanelHeight; + ? _kAllDayLayoutHeight + : _updateCalendarStateDetails.allDayPanelHeight; _allDayHeight = _allDayHeight * _heightAnimation!.value; } } @@ -6885,12 +6934,12 @@ class _CalendarViewState extends State<_CalendarView> Widget _getTimelineView() { final SystemMouseCursor currentCursor = _mouseCursor == SystemMouseCursors.resizeUp || - _mouseCursor == SystemMouseCursors.resizeDown - ? SystemMouseCursors.resizeUpDown - : _mouseCursor == SystemMouseCursors.resizeRight || - _mouseCursor == SystemMouseCursors.resizeLeft - ? SystemMouseCursors.resizeLeftRight - : _mouseCursor; + _mouseCursor == SystemMouseCursors.resizeDown + ? SystemMouseCursors.resizeUpDown + : _mouseCursor == SystemMouseCursors.resizeRight || + _mouseCursor == SystemMouseCursors.resizeLeft + ? SystemMouseCursors.resizeLeftRight + : _mouseCursor; return MouseRegion( cursor: currentCursor, onEnter: _pointerEnterEvent, @@ -7017,8 +7066,9 @@ class _CalendarViewState extends State<_CalendarView> final double singleViewWidth = _getSingleViewWidthForTimeLineView(this); /// Calculate the scrolled position date. - scrolledDate = widget - .visibleDates[_scrollController!.position.pixels ~/ singleViewWidth]; + scrolledDate = + widget.visibleDates[_scrollController!.position.pixels ~/ + singleViewWidth]; /// Calculate the scrolled hour position without visible date position. scrolledPosition = _scrollController!.position.pixels % singleViewWidth; @@ -7189,27 +7239,27 @@ class _CalendarViewState extends State<_CalendarView> duration: const Duration(milliseconds: 200), vsync: this, ); - _heightAnimation ??= - CurveTween(curve: Curves.easeIn).animate(_animationController!) - ..addListener(() { - setState(() { - /*Animates the all day panel when it's expanding or + _heightAnimation ??= CurveTween( + curve: Curves.easeIn, + ).animate(_animationController!)..addListener(() { + setState(() { + /*Animates the all day panel when it's expanding or collapsing*/ - }); - }); + }); + }); _expanderAnimationController ??= AnimationController( duration: const Duration(milliseconds: 100), vsync: this, ); - _allDayExpanderAnimation ??= - CurveTween(curve: Curves.easeIn).animate(_expanderAnimationController!) - ..addListener(() { - setState(() { - /*Animates the all day panel when it's expanding or + _allDayExpanderAnimation ??= CurveTween( + curve: Curves.easeIn, + ).animate(_expanderAnimationController!)..addListener(() { + setState(() { + /*Animates the all day panel when it's expanding or collapsing*/ - }); - }); + }); + }); if (!CalendarViewHelper.isDayView( widget.view, @@ -7256,8 +7306,8 @@ class _CalendarViewState extends State<_CalendarView> } void _updateTimelineViews(_CalendarView oldWidget) { - _timelineRulerController ??= ScrollController() - ..addListener(_timeRulerListener); + _timelineRulerController ??= + ScrollController()..addListener(_timeRulerListener); _timelineViewAnimationController ??= AnimationController( duration: const Duration(milliseconds: 300), @@ -7336,9 +7386,10 @@ class _CalendarViewState extends State<_CalendarView> topPosition = 0; } - double panelHeight = isCurrentView - ? _updateCalendarStateDetails.allDayPanelHeight - _allDayHeight - : 0; + double panelHeight = + isCurrentView + ? _updateCalendarStateDetails.allDayPanelHeight - _allDayHeight + : 0; if (panelHeight < 0) { panelHeight = 0; } @@ -7455,9 +7506,9 @@ class _CalendarViewState extends State<_CalendarView> ]) { final List? visibleAppointments = widget.visibleDates == - _updateCalendarStateDetails.currentViewVisibleDates - ? _updateCalendarStateDetails.visibleAppointments - : null; + _updateCalendarStateDetails.currentViewVisibleDates + ? _updateCalendarStateDetails.visibleAppointments + : null; _appointmentLayout = AppointmentLayout( widget.calendar, widget.view, @@ -7499,21 +7550,23 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); if (!CalendarViewHelper.isTimelineView(widget.view) && widget.view != CalendarView.month) { if (xPosition < timeLabelWidth) { return; } - final double allDayPanelHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double allDayPanelHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; yPosition = yPosition - @@ -7562,9 +7615,18 @@ class _CalendarViewState extends State<_CalendarView> ); } - _resizingDetails.value.resizingTime = isBackwardResize - ? _resizingDetails.value.appointmentView!.appointment!.actualStartTime - : _resizingDetails.value.appointmentView!.appointment!.actualEndTime; + _resizingDetails.value.resizingTime = + isBackwardResize + ? _resizingDetails + .value + .appointmentView! + .appointment! + .actualStartTime + : _resizingDetails + .value + .appointmentView! + .appointment! + .actualEndTime; _resizingDetails.value.scrollPosition = null; if (widget.calendar.appointmentBuilder == null) { _resizingDetails.value.appointmentColor = @@ -7595,18 +7657,20 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); double yPosition = details.localPosition.dy; final bool isForwardResize = _mouseCursor == SystemMouseCursors.resizeDown; final bool isBackwardResize = _mouseCursor == SystemMouseCursors.resizeUp; - final double allDayPanelHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double allDayPanelHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; if (!CalendarViewHelper.isTimelineView(widget.view) && widget.view != CalendarView.month) { _updateMaximumResizingPosition( @@ -7662,21 +7726,23 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); - final double allDayPanelHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double allDayPanelHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; final double currentYPosition = _resizingDetails.value.position.value!.dy > widget.height - 1 - ? widget.height - 1 - : _resizingDetails.value.position.value!.dy; + ? widget.height - 1 + : _resizingDetails.value.position.value!.dy; double yPosition = currentYPosition - viewHeaderHeight - @@ -7699,14 +7765,15 @@ class _CalendarViewState extends State<_CalendarView> yPosition = overAllHeight; } - final DateTime resizingTime = _timeFromPosition( - appointment.actualStartTime, - widget.calendar.timeSlotViewSettings, - yPosition, - null, - timeIntervalHeight, - false, - )!; + final DateTime resizingTime = + _timeFromPosition( + appointment.actualStartTime, + widget.calendar.timeSlotViewSettings, + yPosition, + null, + timeIntervalHeight, + false, + )!; final int timeInterval = CalendarViewHelper.getTimeInterval( widget.calendar.timeSlotViewSettings, @@ -7803,8 +7870,8 @@ class _CalendarViewState extends State<_CalendarView> parentAppointment.recurrenceExceptionDates != null ? parentAppointment.recurrenceExceptionDates!.add(exceptionDate) : parentAppointment.recurrenceExceptionDates = [ - exceptionDate, - ]; + exceptionDate, + ]; final dynamic newParentAppointment = _getCalendarAppointmentToObject( parentAppointment, @@ -7825,12 +7892,12 @@ class _CalendarViewState extends State<_CalendarView> appointment.startTime = updatedStartTime; appointment.endTime = updatedEndTime; - appointment.recurrenceId = parentAppointment != null - ? parentAppointment.id - : appointment.recurrenceId; - appointment.recurrenceRule = appointment.recurrenceId != null - ? null - : appointment.recurrenceRule; + appointment.recurrenceId = + parentAppointment != null + ? parentAppointment.id + : appointment.recurrenceId; + appointment.recurrenceRule = + appointment.recurrenceId != null ? null : appointment.recurrenceRule; appointment.id = parentAppointment != null ? null : appointment.id; final dynamic newAppointment = _getCalendarAppointmentToObject( appointment, @@ -7864,12 +7931,13 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); double xPosition = details.localPosition.dx; CalendarResource? resource; double yPosition = details.localPosition.dy; @@ -8018,13 +8086,31 @@ class _CalendarViewState extends State<_CalendarView> appointmentView.appointment!.color; } if (isTimelineView && _isRTL) { - _resizingDetails.value.resizingTime = isForwardResize - ? _resizingDetails.value.appointmentView!.appointment!.actualStartTime - : _resizingDetails.value.appointmentView!.appointment!.actualEndTime; + _resizingDetails.value.resizingTime = + isForwardResize + ? _resizingDetails + .value + .appointmentView! + .appointment! + .actualStartTime + : _resizingDetails + .value + .appointmentView! + .appointment! + .actualEndTime; } else { - _resizingDetails.value.resizingTime = isBackwardResize - ? _resizingDetails.value.appointmentView!.appointment!.actualStartTime - : _resizingDetails.value.appointmentView!.appointment!.actualEndTime; + _resizingDetails.value.resizingTime = + isBackwardResize + ? _resizingDetails + .value + .appointmentView! + .appointment! + .actualStartTime + : _resizingDetails + .value + .appointmentView! + .appointment! + .actualEndTime; } _resizingDetails.value.position.value = Offset( details.localPosition.dx, @@ -8161,15 +8247,13 @@ class _CalendarViewState extends State<_CalendarView> if (_isRTL) { final double currentXPosition = (DateTime.daysPerWeek - endColumnCount - 1) * cellWidth; - xPosition = xPosition > currentXPosition - ? xPosition - : currentXPosition; + xPosition = + xPosition > currentXPosition ? xPosition : currentXPosition; } else { final double currentXPosition = ((endColumnCount + 1) * cellWidth) + weekNumberPanelWidth - 1; - xPosition = xPosition > currentXPosition - ? currentXPosition - : xPosition; + xPosition = + xPosition > currentXPosition ? currentXPosition : xPosition; } } else if (resizingRowIndex <= startRowCount) { resizingRowIndex = startRowCount; @@ -8183,15 +8267,13 @@ class _CalendarViewState extends State<_CalendarView> currentXPosition -= 1; } - xPosition = xPosition < currentXPosition - ? xPosition - : currentXPosition; + xPosition = + xPosition < currentXPosition ? xPosition : currentXPosition; } else { final double currentXPosition = (startColumnCount * cellWidth) + weekNumberPanelWidth; - xPosition = xPosition < currentXPosition - ? currentXPosition - : xPosition; + xPosition = + xPosition < currentXPosition ? currentXPosition : xPosition; } } } @@ -8237,18 +8319,16 @@ class _CalendarViewState extends State<_CalendarView> } } - resizingTime = _getDateFromPosition( - xPosition, - resizingPosition, - timeLabelWidth, - )!; - final int rowDifference = isBackwardResize - ? _isRTL - ? (appointmentRowIndex - resizingRowIndex).abs() - : appointmentRowIndex - resizingRowIndex - : _isRTL - ? appointmentRowIndex - resizingRowIndex - : (appointmentRowIndex - resizingRowIndex).abs(); + resizingTime = + _getDateFromPosition(xPosition, resizingPosition, timeLabelWidth)!; + final int rowDifference = + isBackwardResize + ? _isRTL + ? (appointmentRowIndex - resizingRowIndex).abs() + : appointmentRowIndex - resizingRowIndex + : _isRTL + ? appointmentRowIndex - resizingRowIndex + : (appointmentRowIndex - resizingRowIndex).abs(); if (((!_isRTL && ((isBackwardResize && appointmentRowIndex > resizingRowIndex) || @@ -8322,11 +8402,8 @@ class _CalendarViewState extends State<_CalendarView> currentXPosition -= timeLabelWidth; } - resizingTime = _getDateFromPosition( - currentXPosition, - yPosition, - timeLabelWidth, - )!; + resizingTime = + _getDateFromPosition(currentXPosition, yPosition, timeLabelWidth)!; } if (_resizingDetails.value.isAllDayPanel || @@ -8388,12 +8465,13 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); final bool isTimelineView = CalendarViewHelper.isTimelineView(widget.view); @@ -8470,11 +8548,8 @@ class _CalendarViewState extends State<_CalendarView> } } - DateTime resizingTime = _getDateFromPosition( - xPosition, - yPosition, - timeLabelWidth, - )!; + DateTime resizingTime = + _getDateFromPosition(xPosition, yPosition, timeLabelWidth)!; if (_resizingDetails.value.isAllDayPanel || widget.view == CalendarView.month || widget.view == CalendarView.timelineMonth) { @@ -8484,14 +8559,15 @@ class _CalendarViewState extends State<_CalendarView> resizingTime.day, ); } else if (isTimelineView) { - final DateTime time = _timeFromPosition( - resizingTime, - widget.calendar.timeSlotViewSettings, - xPosition, - this, - timeIntervalHeight, - isTimelineView, - )!; + final DateTime time = + _timeFromPosition( + resizingTime, + widget.calendar.timeSlotViewSettings, + xPosition, + this, + timeIntervalHeight, + isTimelineView, + )!; resizingTime = DateTime( resizingTime.year, @@ -8664,13 +8740,14 @@ class _CalendarViewState extends State<_CalendarView> appointment.exactStartTime, ); if (currentRecurrenceIndex != -1) { - final DateTime? previousRecurrence = currentRecurrenceIndex <= 0 - ? null - : recurrenceDates[currentRecurrenceIndex - 1]; + final DateTime? previousRecurrence = + currentRecurrenceIndex <= 0 + ? null + : recurrenceDates[currentRecurrenceIndex - 1]; final DateTime? nextRecurrence = currentRecurrenceIndex >= recurrenceDates.length - 1 - ? null - : recurrenceDates[currentRecurrenceIndex + 1]; + ? null + : recurrenceDates[currentRecurrenceIndex + 1]; /// Check the resizing time is in between previous and next recurrence /// date. If previous recurrence is null(means resized appointment @@ -8726,8 +8803,8 @@ class _CalendarViewState extends State<_CalendarView> parentAppointment.recurrenceExceptionDates != null ? parentAppointment.recurrenceExceptionDates!.add(exceptionDate) : parentAppointment.recurrenceExceptionDates = [ - exceptionDate, - ]; + exceptionDate, + ]; final dynamic newParentAppointment = _getCalendarAppointmentToObject( parentAppointment, @@ -8749,12 +8826,12 @@ class _CalendarViewState extends State<_CalendarView> appointment.startTime = updatedStartTime; appointment.endTime = updatedEndTime; - appointment.recurrenceId = parentAppointment != null - ? parentAppointment.id - : appointment.recurrenceId; - appointment.recurrenceRule = appointment.recurrenceId != null - ? null - : appointment.recurrenceRule; + appointment.recurrenceId = + parentAppointment != null + ? parentAppointment.id + : appointment.recurrenceId; + appointment.recurrenceRule = + appointment.recurrenceId != null ? null : appointment.recurrenceRule; appointment.id = parentAppointment != null ? null : appointment.id; final dynamic newAppointment = _getCalendarAppointmentToObject( appointment, @@ -9371,12 +9448,13 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); selectedResourceIndex = _getSelectedResourceIndex( _resizingDetails.value.appointmentView!.appointmentRect!.top, viewHeaderHeight, @@ -9399,21 +9477,23 @@ class _CalendarViewState extends State<_CalendarView> updatedXPosition = overAllWidth; } - resizingTime = _getDateFromPosition( - updatedXPosition, - details.localPosition.dy, - timeLabelWidth!, - )!; - final DateTime time = _timeFromPosition( - resizingTime, - widget.calendar.timeSlotViewSettings, - xPosition! > widget.width - 1 - ? widget.width - 1 - : (xPosition < 0 ? 0 : xPosition), - this, - timeIntervalHeight, - true, - )!; + resizingTime = + _getDateFromPosition( + updatedXPosition, + details.localPosition.dy, + timeLabelWidth!, + )!; + final DateTime time = + _timeFromPosition( + resizingTime, + widget.calendar.timeSlotViewSettings, + xPosition! > widget.width - 1 + ? widget.width - 1 + : (xPosition < 0 ? 0 : xPosition), + this, + timeIntervalHeight, + true, + )!; if (widget.view == CalendarView.timelineMonth) { resizingTime = DateTime( @@ -9433,22 +9513,26 @@ class _CalendarViewState extends State<_CalendarView> } } else { final double overAllHeight = _timeIntervalHeight * _horizontalLinesCount!; - double updatedYPosition = yPosition > widget.height - 1 - ? widget.height - 1 - : yPosition; + double updatedYPosition = + yPosition > widget.height - 1 ? widget.height - 1 : yPosition; if (overAllHeight < widget.height && updatedYPosition > overAllHeight) { updatedYPosition = overAllHeight; } final double currentYPosition = updatedYPosition - viewHeaderHeight! - allDayPanelHeight!; - resizingTime = _timeFromPosition( - _resizingDetails.value.appointmentView!.appointment!.actualStartTime, - widget.calendar.timeSlotViewSettings, - currentYPosition > 0 ? currentYPosition : 0, - this, - timeIntervalHeight, - false, - )!; + resizingTime = + _timeFromPosition( + _resizingDetails + .value + .appointmentView! + .appointment! + .actualStartTime, + widget.calendar.timeSlotViewSettings, + currentYPosition > 0 ? currentYPosition : 0, + this, + timeIntervalHeight, + false, + )!; } _resizingDetails.value.resizingTime = resizingTime; @@ -9573,9 +9657,9 @@ class _CalendarViewState extends State<_CalendarView> Widget _getMonthWidget(bool isRTL, double height) { final List? visibleAppointments = widget.visibleDates == - _updateCalendarStateDetails.currentViewVisibleDates - ? _updateCalendarStateDetails.visibleAppointments - : null; + _updateCalendarStateDetails.currentViewVisibleDates + ? _updateCalendarStateDetails.visibleAppointments + : null; _monthView = MonthViewWidget( widget.visibleDates, widget.calendar.monthViewSettings.numberOfWeeksInView, @@ -9616,15 +9700,17 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.nonWorkingDays, widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); - final double allDayPanelHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); + final double allDayPanelHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; final bool isVerticalResize = _mouseCursor == SystemMouseCursors.resizeUp || _mouseCursor == SystemMouseCursors.resizeDown; @@ -9643,16 +9729,17 @@ class _CalendarViewState extends State<_CalendarView> widget.isMobilePlatform, ); - final double overAllWidth = isTimelineView - ? _timeIntervalHeight * - (_horizontalLinesCount! * widget.visibleDates.length) - : widget.width; + final double overAllWidth = + isTimelineView + ? _timeIntervalHeight * + (_horizontalLinesCount! * widget.visibleDates.length) + : widget.width; final double overAllHeight = isTimelineView || widget.view == CalendarView.month - ? widget.height - : viewHeaderHeight + - allDayPanelHeight + - (_timeIntervalHeight * _horizontalLinesCount!); + ? widget.height + : viewHeaderHeight + + allDayPanelHeight + + (_timeIntervalHeight * _horizontalLinesCount!); return Positioned( left: 0, @@ -9728,14 +9815,14 @@ class _CalendarViewState extends State<_CalendarView> ); if (isDayView) { viewHeaderWidth = timeLabelWidth < 50 ? 50 : timeLabelWidth; - viewHeaderHeight = _allDayHeight > viewHeaderHeight - ? _allDayHeight - : viewHeaderHeight; + viewHeaderHeight = + _allDayHeight > viewHeaderHeight ? _allDayHeight : viewHeaderHeight; } - double panelHeight = isCurrentView - ? _updateCalendarStateDetails.allDayPanelHeight - _allDayHeight - : 0; + double panelHeight = + isCurrentView + ? _updateCalendarStateDetails.allDayPanelHeight - _allDayHeight + : 0; if (panelHeight < 0) { panelHeight = 0; } @@ -9789,9 +9876,10 @@ class _CalendarViewState extends State<_CalendarView> ), ), Positioned( - top: isDayView - ? viewHeaderHeight + allDayExpanderHeight - : viewHeaderHeight + _allDayHeight + allDayExpanderHeight, + top: + isDayView + ? viewHeaderHeight + allDayExpanderHeight + : viewHeaderHeight + _allDayHeight + allDayExpanderHeight, left: 0, right: 0, bottom: 0, @@ -9983,9 +10071,10 @@ class _CalendarViewState extends State<_CalendarView> padding: EdgeInsets.zero, controller: _timelineRulerController, scrollDirection: Axis.horizontal, - physics: widget.isMobilePlatform - ? const _CustomNeverScrollableScrollPhysics() - : const ClampingScrollPhysics(), + physics: + widget.isMobilePlatform + ? const _CustomNeverScrollableScrollPhysics() + : const ClampingScrollPhysics(), children: [ RepaintBoundary( child: CustomPaint( @@ -10019,9 +10108,10 @@ class _CalendarViewState extends State<_CalendarView> padding: EdgeInsets.zero, controller: _scrollController, scrollDirection: Axis.horizontal, - physics: widget.isMobilePlatform - ? const _CustomNeverScrollableScrollPhysics() - : const ClampingScrollPhysics(), + physics: + widget.isMobilePlatform + ? const _CustomNeverScrollableScrollPhysics() + : const ClampingScrollPhysics(), children: [ SizedBox( width: width, @@ -10033,9 +10123,10 @@ class _CalendarViewState extends State<_CalendarView> child: ListView( padding: EdgeInsets.zero, controller: _timelineViewVerticalScrollController, - physics: isResourceEnabled - ? const ClampingScrollPhysics() - : const NeverScrollableScrollPhysics(), + physics: + isResourceEnabled + ? const ClampingScrollPhysics() + : const NeverScrollableScrollPhysics(), children: [ Stack( children: [ @@ -10201,18 +10292,19 @@ class _CalendarViewState extends State<_CalendarView> final List selectedAppointments = appointmentView == null || isMoreTapped - ? _getSelectedAppointments(getDate) - : [ - CalendarViewHelper.getAppointmentDetail( - appointmentView.appointment!, - widget.calendar.dataSource, - ), - ]; - final CalendarElement selectedElement = appointmentView == null - ? CalendarElement.calendarCell - : isMoreTapped - ? CalendarElement.moreAppointmentRegion - : CalendarElement.appointment; + ? _getSelectedAppointments(getDate) + : [ + CalendarViewHelper.getAppointmentDetail( + appointmentView.appointment!, + widget.calendar.dataSource, + ), + ]; + final CalendarElement selectedElement = + appointmentView == null + ? CalendarElement.calendarCell + : isMoreTapped + ? CalendarElement.moreAppointmentRegion + : CalendarElement.appointment; /// Return calendar details while the [getCalendarDetailsAtOffset] /// position placed on month cells in month view. @@ -10300,11 +10392,8 @@ class _CalendarViewState extends State<_CalendarView> } widget.updateCalendarState(_updateCalendarStateDetails); - final DateTime selectedDate = _getDateFromPosition( - xDetails, - yDetails - viewHeaderHeight, - 0, - )!; + final DateTime selectedDate = + _getDateFromPosition(xDetails, yDetails - viewHeaderHeight, 0)!; if (appointmentView == null) { if (!isDateWithInDateRange( widget.calendar.minDate, @@ -10353,18 +10442,19 @@ class _CalendarViewState extends State<_CalendarView> if (canRaiseLongPress || canRaiseTap || canRaiseSelectionChanged) { final List selectedAppointments = appointmentView == null || isMoreTapped - ? _getSelectedAppointments(selectedDate) - : [ - CalendarViewHelper.getAppointmentDetail( - appointmentView.appointment!, - widget.calendar.dataSource, - ), - ]; - final CalendarElement selectedElement = appointmentView == null - ? CalendarElement.calendarCell - : isMoreTapped - ? CalendarElement.moreAppointmentRegion - : CalendarElement.appointment; + ? _getSelectedAppointments(selectedDate) + : [ + CalendarViewHelper.getAppointmentDetail( + appointmentView.appointment!, + widget.calendar.dataSource, + ), + ]; + final CalendarElement selectedElement = + appointmentView == null + ? CalendarElement.calendarCell + : isMoreTapped + ? CalendarElement.moreAppointmentRegion + : CalendarElement.appointment; if (canRaiseTap) { CalendarViewHelper.raiseCalendarTapCallback( widget.calendar, @@ -10453,9 +10543,9 @@ class _CalendarViewState extends State<_CalendarView> ) { final int resourceCount = widget.calendar.dataSource != null && - widget.calendar.dataSource!.resources != null - ? widget.calendar.dataSource!.resources!.length - : 0; + widget.calendar.dataSource!.resources != null + ? widget.calendar.dataSource!.resources!.length + : 0; final double resourceItemHeight = CalendarViewHelper.getResourceItemHeight( widget.calendar.resourceViewSettings.size, widget.height - viewHeaderHeight - timeLabelSize, @@ -10531,11 +10621,8 @@ class _CalendarViewState extends State<_CalendarView> final AppointmentView? appointmentView = _appointmentLayout .getAppointmentViewOnPoint(xPosition, yPosition); - final DateTime getDate = _getDateFromPosition( - xDetails, - yDetails - viewHeaderHeight, - 0, - )!; + final DateTime getDate = + _getDateFromPosition(xDetails, yDetails - viewHeaderHeight, 0)!; if (appointmentView == null) { /// Return calendar details while the [getCalendarDetailsAtOffset] @@ -10813,15 +10900,17 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.monthViewSettings.numberOfWeeksInView, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); - final double allDayHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); + final double allDayHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; // time ruler position on time slot scroll view. if (!_isRTL && xDetails <= timeLabelWidth && @@ -10980,16 +11069,18 @@ class _CalendarViewState extends State<_CalendarView> int maxPosition = 0; if (selectedIndexAppointment.isNotEmpty) { - maxPosition = selectedIndexAppointment - .reduce( - ( - AppointmentView currentAppView, - AppointmentView nextAppView, - ) => currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + maxPosition = + selectedIndexAppointment + .reduce( + ( + AppointmentView currentAppView, + AppointmentView nextAppView, + ) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } final int endAppointmentPosition = allDayHeight ~/ kAllDayAppointmentHeight; @@ -11028,9 +11119,9 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.dataSource!, ) ? CalendarViewHelper.getCustomAppointments( - moreRegionAppointments, - widget.calendar.dataSource, - ) + moreRegionAppointments, + widget.calendar.dataSource, + ) : moreRegionAppointments, selectedDate, CalendarElement.moreAppointmentRegion, @@ -11134,15 +11225,17 @@ class _CalendarViewState extends State<_CalendarView> widget.view, ); - final double viewHeaderHeight = isDayView - ? 0 - : CalendarViewHelper.getViewHeaderHeight( - widget.calendar.viewHeaderHeight, - widget.view, - ); - final double allDayHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + final double viewHeaderHeight = + isDayView + ? 0 + : CalendarViewHelper.getViewHeaderHeight( + widget.calendar.viewHeaderHeight, + widget.view, + ); + final double allDayHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; if (!_isRTL && xDetails <= timeLabelWidth && yDetails > viewHeaderHeight + allDayHeight) { @@ -11268,16 +11361,18 @@ class _CalendarViewState extends State<_CalendarView> int maxPosition = 0; if (selectedIndexAppointment.isNotEmpty) { - maxPosition = selectedIndexAppointment - .reduce( - ( - AppointmentView currentAppView, - AppointmentView nextAppView, - ) => currentAppView.maxPositions > nextAppView.maxPositions - ? currentAppView - : nextAppView, - ) - .maxPositions; + maxPosition = + selectedIndexAppointment + .reduce( + ( + AppointmentView currentAppView, + AppointmentView nextAppView, + ) => + currentAppView.maxPositions > nextAppView.maxPositions + ? currentAppView + : nextAppView, + ) + .maxPositions; } final int endAppointmentPosition = allDayHeight ~/ kAllDayAppointmentHeight; @@ -11640,14 +11735,15 @@ class _CalendarViewState extends State<_CalendarView> calendar.timeSlotViewSettings.nonWorkingDays, calendar.monthViewSettings.numberOfWeeksInView, ); - double timeIntervalHeight = isTimelineView - ? _getTimeIntervalWidth( - calendar.timeSlotViewSettings.timeIntervalWidth, - view, - width, - isMobilePlatform, - ) - : calendar.timeSlotViewSettings.timeIntervalHeight; + double timeIntervalHeight = + isTimelineView + ? _getTimeIntervalWidth( + calendar.timeSlotViewSettings.timeIntervalWidth, + view, + width, + isMobilePlatform, + ) + : calendar.timeSlotViewSettings.timeIntervalHeight; if (!_isAutoTimeIntervalHeight(calendar, isTimelineView)) { return timeIntervalHeight; @@ -11667,12 +11763,13 @@ class _CalendarViewState extends State<_CalendarView> if (isCurrentView) { allDayViewHeight = _kAllDayLayoutHeight > viewHeaderHeight && - _updateCalendarStateDetails.allDayPanelHeight > viewHeaderHeight - ? _updateCalendarStateDetails.allDayPanelHeight > - _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : _updateCalendarStateDetails.allDayPanelHeight - : viewHeaderHeight; + _updateCalendarStateDetails.allDayPanelHeight > + viewHeaderHeight + ? _updateCalendarStateDetails.allDayPanelHeight > + _kAllDayLayoutHeight + ? _kAllDayLayoutHeight + : _updateCalendarStateDetails.allDayPanelHeight + : viewHeaderHeight; if (allDayViewHeight < _updateCalendarStateDetails.allDayPanelHeight) { allDayViewHeight += kAllDayAppointmentHeight; } @@ -11684,8 +11781,8 @@ class _CalendarViewState extends State<_CalendarView> } else if (isCurrentView) { allDayViewHeight = _updateCalendarStateDetails.allDayPanelHeight > _kAllDayLayoutHeight - ? _kAllDayLayoutHeight - : _updateCalendarStateDetails.allDayPanelHeight; + ? _kAllDayLayoutHeight + : _updateCalendarStateDetails.allDayPanelHeight; } switch (view) { @@ -11753,10 +11850,8 @@ class _CalendarViewState extends State<_CalendarView> //// Handles the on tap callback for view header void _handleOnTapForViewHeader(TapUpDetails details, double width) { - final DateTime tappedDate = _getTappedViewHeaderDate( - details.localPosition, - width, - )!; + final DateTime tappedDate = + _getTappedViewHeaderDate(details.localPosition, width)!; _handleViewHeaderTapNavigation(tappedDate); if (!CalendarViewHelper.shouldRaiseCalendarTapCallback( widget.calendar.onTap, @@ -11778,10 +11873,8 @@ class _CalendarViewState extends State<_CalendarView> LongPressStartDetails details, double width, ) { - final DateTime tappedDate = _getTappedViewHeaderDate( - details.localPosition, - width, - )!; + final DateTime tappedDate = + _getTappedViewHeaderDate(details.localPosition, width)!; _handleViewHeaderTapNavigation(tappedDate); if (!CalendarViewHelper.shouldRaiseCalendarLongPressCallback( widget.calendar.onLongPress, @@ -11880,7 +11973,7 @@ class _CalendarViewState extends State<_CalendarView> ((_scrollController!.offset + (_isRTL ? _scrollController!.position.viewportDimension - - localPosition.dx + localPosition.dx : localPosition.dx)) / _getSingleViewWidthForTimeLineView(this)) .truncate(); @@ -12192,27 +12285,28 @@ class _CalendarViewState extends State<_CalendarView> final DateTime appointmentStartTime = appointmentView.appointment!.isAllDay - ? AppointmentHelper.convertToStartTime( - appointmentView.appointment!.actualStartTime, - ) - : appointmentView.appointment!.actualStartTime; - final DateTime appointmentEndTime = appointmentView.appointment!.isAllDay - ? AppointmentHelper.convertToEndTime( - appointmentView.appointment!.actualEndTime, - ) - : appointmentView.appointment!.actualEndTime; + ? AppointmentHelper.convertToStartTime( + appointmentView.appointment!.actualStartTime, + ) + : appointmentView.appointment!.actualStartTime; + final DateTime appointmentEndTime = + appointmentView.appointment!.isAllDay + ? AppointmentHelper.convertToEndTime( + appointmentView.appointment!.actualEndTime, + ) + : appointmentView.appointment!.actualEndTime; final DateTime appointmentExactStartTime = appointmentView.appointment!.isAllDay - ? AppointmentHelper.convertToStartTime( - appointmentView.appointment!.exactStartTime, - ) - : appointmentView.appointment!.exactStartTime; + ? AppointmentHelper.convertToStartTime( + appointmentView.appointment!.exactStartTime, + ) + : appointmentView.appointment!.exactStartTime; final DateTime appointmentExactEndTime = appointmentView.appointment!.isAllDay - ? AppointmentHelper.convertToEndTime( - appointmentView.appointment!.exactEndTime, - ) - : appointmentView.appointment!.exactEndTime; + ? AppointmentHelper.convertToEndTime( + appointmentView.appointment!.exactEndTime, + ) + : appointmentView.appointment!.exactEndTime; if (xPosition >= appointmentView.appointmentRect!.left && xPosition <= appointmentView.appointmentRect!.left + padding && @@ -12307,9 +12401,10 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.timeSlotViewSettings.timeRulerSize, widget.view, ); - double allDayHeight = _isExpanded - ? _updateCalendarStateDetails.allDayPanelHeight - : _allDayHeight; + double allDayHeight = + _isExpanded + ? _updateCalendarStateDetails.allDayPanelHeight + : _allDayHeight; final bool isDayView = CalendarViewHelper.isDayView( widget.view, widget.calendar.timeSlotViewSettings.numberOfDaysInView, @@ -12384,9 +12479,10 @@ class _CalendarViewState extends State<_CalendarView> final double allDayExpanderHeight = panelHeight * _allDayExpanderAnimation!.value; - final double allDayBottom = isDayView - ? viewHeaderHeight - : viewHeaderHeight + _allDayHeight + allDayExpanderHeight; + final double allDayBottom = + isDayView + ? viewHeaderHeight + : viewHeaderHeight + _allDayHeight + allDayExpanderHeight; if (localPosition.dy > viewHeaderHeight && localPosition.dy < allDayBottom) { if ((_isRTL && localPosition.dx < widget.width - timeLabelWidth) || @@ -12779,18 +12875,18 @@ class _CalendarViewState extends State<_CalendarView> widget.calendar.dataSource!, )) ? CalendarViewHelper.getCustomAppointments( - AppointmentHelper.getSelectedDateAppointments( - _updateCalendarStateDetails.appointments, - widget.calendar.timeZone, - selectedDate, - ), - widget.calendar.dataSource, - ) - : (AppointmentHelper.getSelectedDateAppointments( + AppointmentHelper.getSelectedDateAppointments( _updateCalendarStateDetails.appointments, widget.calendar.timeZone, selectedDate, - )); + ), + widget.calendar.dataSource, + ) + : (AppointmentHelper.getSelectedDateAppointments( + _updateCalendarStateDetails.appointments, + widget.calendar.timeZone, + selectedDate, + )); } DateTime? _getDateFromPositionForMonth( @@ -12824,16 +12920,17 @@ class _CalendarViewState extends State<_CalendarView> double x, double y, ) { - final int columnIndex = ((_scrollController!.offset + y) / cellHeight) - .truncate(); - final double time = columnIndex == -1 - ? 0 - : ((CalendarViewHelper.getTimeInterval( - widget.calendar.timeSlotViewSettings, - ) / - 60) * - columnIndex) + - widget.calendar.timeSlotViewSettings.startHour; + final int columnIndex = + ((_scrollController!.offset + y) / cellHeight).truncate(); + final double time = + columnIndex == -1 + ? 0 + : ((CalendarViewHelper.getTimeInterval( + widget.calendar.timeSlotViewSettings, + ) / + 60) * + columnIndex) + + widget.calendar.timeSlotViewSettings.startHour; final int hour = time.toInt(); final int minute = ((time - hour) * 60).round(); int rowIndex = (x / cellWidth).truncate(); @@ -13176,9 +13273,10 @@ class _ViewHeaderViewPainter extends CustomPainter { size.width, isMobilePlatform, ); - double width = view == CalendarView.month - ? size.width - weekNumberPanelWidth - : size.width; + double width = + view == CalendarView.month + ? size.width - weekNumberPanelWidth + : size.width; width = _getViewHeaderWidth(width); /// Initializes the default text style for the texts in view header of @@ -13218,9 +13316,10 @@ class _ViewHeaderViewPainter extends CustomPainter { double weekNumberPanelWidth, ) { TextStyle dayTextStyle = viewHeaderDayStyle; - double xPosition = isRTL - ? size.width - width - weekNumberPanelWidth - : weekNumberPanelWidth; + double xPosition = + isRTL + ? size.width - width - weekNumberPanelWidth + : weekNumberPanelWidth; double yPosition = 0; final int visibleDatesLength = visibleDates.length; bool hasToday = @@ -13237,10 +13336,11 @@ class _ViewHeaderViewPainter extends CustomPainter { for (int i = 0; i < DateTime.daysPerWeek; i++) { final DateTime currentDate = visibleDates[i]; - String dayText = DateFormat( - monthViewSettings.dayFormat, - locale, - ).format(currentDate).toUpperCase(); + String dayText = + DateFormat( + monthViewSettings.dayFormat, + locale, + ).format(currentDate).toUpperCase(); dayText = _updateViewHeaderFormat(monthViewSettings.dayFormat, dayText); @@ -13252,12 +13352,13 @@ class _ViewHeaderViewPainter extends CustomPainter { calendarTheme, ); - dayTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: viewHeaderDayStyle.fontSize, - color: todayTextColor, - ) - : viewHeaderDayStyle.copyWith(color: todayTextColor); + dayTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: viewHeaderDayStyle.fontSize, + color: todayTextColor, + ) + : viewHeaderDayStyle.copyWith(color: todayTextColor); } else { dayTextStyle = viewHeaderDayStyle; } @@ -13330,9 +13431,8 @@ class _ViewHeaderViewPainter extends CustomPainter { timeSlotViewSettings.nonWorkingDays, monthViewSettings.numberOfWeeksInView, ); - final double labelWidth = isDayView && timeLabelWidth < 50 - ? 50 - : timeLabelWidth; + final double labelWidth = + isDayView && timeLabelWidth < 50 ? 50 : timeLabelWidth; TextStyle dayTextStyle = viewHeaderDayStyle; TextStyle dateTextStyle = viewHeaderDateStyle; const double topPadding = 5; @@ -13351,10 +13451,11 @@ class _ViewHeaderViewPainter extends CustomPainter { for (int i = 0; i < visibleDatesLength; i++) { final DateTime currentDate = visibleDates[i]; - String dayText = DateFormat( - timeSlotViewSettings.dayFormat, - locale, - ).format(currentDate).toUpperCase(); + String dayText = + DateFormat( + timeSlotViewSettings.dayFormat, + locale, + ).format(currentDate).toUpperCase(); dayText = _updateViewHeaderFormat( timeSlotViewSettings.dayFormat, @@ -13373,17 +13474,19 @@ class _ViewHeaderViewPainter extends CustomPainter { todayTextStyle, calendarTheme, ); - dayTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: viewHeaderDayStyle.fontSize, - color: todayTextColor, - ) - : viewHeaderDayStyle.copyWith(color: todayTextColor); - dateTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: viewHeaderDateStyle.fontSize, - ) - : viewHeaderDateStyle.copyWith(color: todayTextStyleColor); + dayTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: viewHeaderDayStyle.fontSize, + color: todayTextColor, + ) + : viewHeaderDayStyle.copyWith(color: todayTextColor); + dateTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: viewHeaderDateStyle.fontSize, + ) + : viewHeaderDateStyle.copyWith(color: todayTextStyleColor); } else { dayTextStyle = viewHeaderDayStyle; dateTextStyle = viewHeaderDateStyle; @@ -13391,18 +13494,20 @@ class _ViewHeaderViewPainter extends CustomPainter { if (!isDateWithInDateRange(minDate, maxDate, currentDate)) { dayTextStyle = dayTextStyle.copyWith( - color: dayTextStyle.color != null - ? dayTextStyle.color!.withValues(alpha: 0.38) - : themeData.brightness == Brightness.light - ? Colors.black26 - : Colors.white38, + color: + dayTextStyle.color != null + ? dayTextStyle.color!.withValues(alpha: 0.38) + : themeData.brightness == Brightness.light + ? Colors.black26 + : Colors.white38, ); dateTextStyle = dateTextStyle.copyWith( - color: dateTextStyle.color != null - ? dateTextStyle.color!.withValues(alpha: 0.38) - : themeData.brightness == Brightness.light - ? Colors.black26 - : Colors.white38, + color: + dateTextStyle.color != null + ? dateTextStyle.color!.withValues(alpha: 0.38) + : themeData.brightness == Brightness.light + ? Colors.black26 + : Colors.white38, ); } @@ -13478,9 +13583,8 @@ class _ViewHeaderViewPainter extends CustomPainter { DateTime.monday, ) && i == visibleDatesLength ~/ 2))) { - final String weekNumber = DateTimeHelper.getWeekNumberOfYear( - currentDate, - ).toString(); + final String weekNumber = + DateTimeHelper.getWeekNumberOfYear(currentDate).toString(); final TextStyle weekNumberTextStyle = calendarTheme.weekNumberTextStyle!; final TextSpan dayTextSpan = TextSpan( @@ -13493,10 +13597,11 @@ class _ViewHeaderViewPainter extends CustomPainter { _dateTextPainter.textWidthBasis = TextWidthBasis.longestLine; _dateTextPainter.textScaler = TextScaler.linear(textScaleFactor); _dateTextPainter.layout(maxWidth: timeLabelWidth); - final double weekNumberPosition = isRTL - ? (size.width - timeLabelWidth) + - ((timeLabelWidth - _dateTextPainter.width) / 2) - : (timeLabelWidth - _dateTextPainter.width) / 2; + final double weekNumberPosition = + isRTL + ? (size.width - timeLabelWidth) + + ((timeLabelWidth - _dateTextPainter.width) / 2) + : (timeLabelWidth - _dateTextPainter.width) / 2; final double weekNumberYPosition = size.height / 2 - (_dayTextPainter.height + @@ -13570,11 +13675,10 @@ class _ViewHeaderViewPainter extends CustomPainter { xPosition + (width / 2 - _dayTextPainter.width / 2), yPosition, _dayTextPainter, - hoveringColor: - (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04), + hoveringColor: (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04), ); } } @@ -13592,12 +13696,13 @@ class _ViewHeaderViewPainter extends CustomPainter { if (xPosition + dateXPosition <= viewHeaderNotifier.value!.dx && xPosition + dateXPosition + _dateTextPainter.width >= viewHeaderNotifier.value!.dx) { - final Color hoveringColor = isToday - ? Colors.black.withValues(alpha: 0.12) - : (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + final Color hoveringColor = + isToday + ? Colors.black.withValues(alpha: 0.12) + : (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); _drawTodayCircle( canvas, xPosition + dateXPosition, @@ -13719,9 +13824,8 @@ class _ViewHeaderViewPainter extends CustomPainter { const double circlePadding = 5; final double painterWidth = dateTextPainter.width / 2; final double painterHeight = dateTextPainter.height / 2; - final double radius = painterHeight > painterWidth - ? painterHeight - : painterWidth; + final double radius = + painterHeight > painterWidth ? painterHeight : painterWidth; canvas.drawCircle( Offset(x + painterWidth, y + painterHeight), radius + circlePadding, @@ -13793,13 +13897,15 @@ class _ViewHeaderViewPainter extends CustomPainter { timeSlotViewSettings.nonWorkingDays, monthViewSettings.numberOfWeeksInView, ); - final double cellWidth = isDayView - ? size.width - : (size.width - timeLabelWidth) / visibleDates.length; + final double cellWidth = + isDayView + ? size.width + : (size.width - timeLabelWidth) / visibleDates.length; if (isRTL) { - left = isDayView - ? size.width - timeLabelWidth - : (size.width - timeLabelWidth) - cellWidth; + left = + isDayView + ? size.width - timeLabelWidth + : (size.width - timeLabelWidth) - cellWidth; } else { left = isDayView ? 0 : timeLabelWidth; } @@ -14203,12 +14309,12 @@ class _SelectionPainter extends CustomPainter { for (int i = 0; i < visibleDates.length; i++) { if (isSameDate(visibleDates[i], selectedDate)) { _yPosition = _getTimelineYPosition(); - _xPosition = isRTL - ? size.width - ((i + 1) * _cellWidth) - : i * _cellWidth; - final double height = selectedResourceIndex == -1 - ? size.height - : _yPosition + resourceItemHeight!; + _xPosition = + isRTL ? size.width - ((i + 1) * _cellWidth) : i * _cellWidth; + final double height = + selectedResourceIndex == -1 + ? size.height + : _yPosition + resourceItemHeight!; _drawSlotSelection(width, height, canvas); break; } @@ -14236,9 +14342,10 @@ class _SelectionPainter extends CustomPainter { _xPosition = size.width - _xPosition - _cellWidth; } _yPosition = _getTimelineYPosition(); - final double height = selectedResourceIndex == -1 - ? size.height - : _yPosition + resourceItemHeight!; + final double height = + selectedResourceIndex == -1 + ? size.height + : _yPosition + resourceItemHeight!; _drawSlotSelection(width, height, canvas); break; } @@ -14473,9 +14580,8 @@ class _TimeRulerView extends CustomPainter { if (isTimelineView) { startYPosition = (size.height - _textPainter.height) / 2; - startXPosition = isRTL - ? startXPosition - padding - : startXPosition + padding; + startXPosition = + isRTL ? startXPosition - padding : startXPosition + padding; } _textPainter.paint(canvas, Offset(startXPosition, startYPosition)); @@ -14534,8 +14640,8 @@ class _CalendarMultiChildContainer extends Stack { @override RenderStack createRenderObject(BuildContext context) { - final Directionality? widget = context - .dependOnInheritedWidgetOfExactType(); + final Directionality? widget = + context.dependOnInheritedWidgetOfExactType(); return _MultiChildContainerRenderObject( width, height, @@ -14549,8 +14655,8 @@ class _CalendarMultiChildContainer extends Stack { void updateRenderObject(BuildContext context, RenderStack renderObject) { super.updateRenderObject(context, renderObject); if (renderObject is _MultiChildContainerRenderObject) { - final Directionality? widget = context - .dependOnInheritedWidgetOfExactType(); + final Directionality? widget = + context.dependOnInheritedWidgetOfExactType(); renderObject ..width = width ..height = height @@ -14717,9 +14823,10 @@ class _MultiChildContainerRenderObject extends RenderStack { final List semanticsNodes = []; for (int i = 0; i < semantics.length; i++) { final CustomPainterSemantics currentSemantics = semantics[i]; - final SemanticsNode newChild = _cacheNodes!.isNotEmpty - ? _cacheNodes!.removeAt(0) - : SemanticsNode(key: currentSemantics.key); + final SemanticsNode newChild = + _cacheNodes!.isNotEmpty + ? _cacheNodes!.removeAt(0) + : SemanticsNode(key: currentSemantics.key); final SemanticsProperties properties = currentSemantics.properties; final SemanticsConfiguration config = SemanticsConfiguration(); @@ -14872,11 +14979,12 @@ class _CurrentTimeIndicator extends CustomPainter { timeSlotViewSettings, minuteHeight, ); - final Paint painter = Paint() - ..color = todayHighlightColor! - ..strokeWidth = 1 - ..isAntiAlias = true - ..style = PaintingStyle.fill; + final Paint painter = + Paint() + ..color = todayHighlightColor! + ..strokeWidth = 1 + ..isAntiAlias = true + ..style = PaintingStyle.fill; if (isTimelineView) { final double viewSize = size.width / visibleDates.length; double startXPosition = (index * viewSize) + currentTimePosition; @@ -14930,9 +15038,8 @@ DateTime? _timeFromPosition( double timeIntervalHeight, bool isTimelineView, ) { - final double topPosition = currentState == null - ? 0 - : currentState._scrollController!.offset; + final double topPosition = + currentState == null ? 0 : currentState._scrollController!.offset; final double singleIntervalHeightForAnHour = (60 / CalendarViewHelper.getTimeInterval(timeSlotViewSettings)) * @@ -15068,8 +15175,8 @@ class _ResizingAppointmentPainter extends CustomPainter { final double scrollOffset = view == CalendarView.month || resizingDetails.value.isAllDayPanel - ? 0 - : resizingDetails.value.scrollPosition ?? scrollController!.offset; + ? 0 + : resizingDetails.value.scrollPosition ?? scrollController!.offset; final bool isForwardResize = mouseCursor == SystemMouseCursors.resizeDown || @@ -15526,9 +15633,10 @@ class _ResizingAppointmentPainter extends CustomPainter { final double yPosition = rect.top + ((rect.height - _textPainter.height) / 2); const double rightPadding = 0; - final double recurrenceStartPosition = isRTL - ? rect.left + rightPadding - : rect.right - _textPainter.width - rightPadding; + final double recurrenceStartPosition = + isRTL + ? rect.left + rightPadding + : rect.right - _textPainter.width - rightPadding; canvas.drawRRect( RRect.fromRectAndRadius( Rect.fromLTRB( @@ -15594,8 +15702,8 @@ dynamic _getCalendarAppointmentToObject( return null; } - final Appointment appointment = calendarAppointment - .convertToCalendarAppointment(); + final Appointment appointment = + calendarAppointment.convertToCalendarAppointment(); if (calendarAppointment.data is Appointment) { return appointment; @@ -16151,7 +16259,7 @@ class _DraggingAppointmentRenderObject extends RenderBox Offset( isRTL ? dragDetails.position.value!.dx - - dragDetails.appointmentView!.appointmentRect!.width + dragDetails.appointmentView!.appointmentRect!.width : dragDetails.position.value!.dx, dragDetails.position.value!.dy, ), @@ -16225,13 +16333,13 @@ class _DraggingAppointmentRenderObject extends RenderBox canvas, isTimelineView ? Offset( - xPosition + (isRTL ? 0 : textStartPadding), - yPosition + textStartPadding, - ) + xPosition + (isRTL ? 0 : textStartPadding), + yPosition + textStartPadding, + ) : Offset( - xPosition + (isRTL ? 0 : textStartPadding), - yPosition + textStartPadding, - ), + xPosition + (isRTL ? 0 : textStartPadding), + yPosition + textStartPadding, + ), ); if (dragAndDropSettings.showTimeIndicator && dragDetails.draggingTime != null) { @@ -16257,9 +16365,8 @@ class _DraggingAppointmentRenderObject extends RenderBox _textPainter.textAlign = isRTL ? TextAlign.right : TextAlign.left; _textPainter.textWidthBasis = TextWidthBasis.longestLine; _textPainter.textScaler = TextScaler.linear(textScaleFactor); - final double timeLabelSize = isTimelineView - ? dragDetails.timeIntervalHeight! - : timeLabelWidth; + final double timeLabelSize = + isTimelineView ? dragDetails.timeIntervalHeight! : timeLabelWidth; _textPainter.layout(maxWidth: timeLabelSize); double xPosition; double yPosition; diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/day_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/day_view.dart index b06aa0efc..8faa3739b 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/day_view.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/day_view.dart @@ -817,9 +817,8 @@ class _TimeSlotRenderObject extends CustomCalendarRenderObject { _linePainter.color = cellBorderColor ?? calendarTheme.cellBorderColor!; final double startXPosition = isRTL ? 0 : timeLabelWidth; - final double endXPosition = isRTL - ? size.width - timeLabelWidth - : size.width; + final double endXPosition = + isRTL ? size.width - timeLabelWidth : size.width; for (int i = 1; i <= horizontalLinesCount; i++) { canvas.drawLine( Offset(startXPosition, y), @@ -890,9 +889,10 @@ class _TimeSlotRenderObject extends CustomCalendarRenderObject { _linePainter.style = PaintingStyle.fill; final int count = specialRegionBounds.length; final TextStyle defaultTextStyle = TextStyle( - color: themeData.brightness == Brightness.dark - ? Colors.white54 - : Colors.black45, + color: + themeData.brightness == Brightness.dark + ? Colors.white54 + : Colors.black45, ); for (int i = 0; i < count; i++) { final TimeRegionView view = specialRegionBounds[i]; @@ -938,8 +938,8 @@ class _TimeSlotRenderObject extends CustomCalendarRenderObject { left = isRTL ? (size.width - timeLabelWidth) - cellWidth : timeLabelWidth; final double cellHeight = timeIntervalHeight; final int startHour = timeSlotViewSettings.startHour.toInt(); - final int hour = ((timeSlotViewSettings.startHour - startHour) * 60) - .toInt(); + final int hour = + ((timeSlotViewSettings.startHour - startHour) * 60).toInt(); final int timeInterval = CalendarViewHelper.getTimeInterval( timeSlotViewSettings, ); diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/month_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/month_view.dart index dd035f2c7..ac15ee51c 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/month_view.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/month_view.dart @@ -935,9 +935,8 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { double cellHeight, double yPosition, ) { - final String weekNumber = DateTimeHelper.getWeekNumberOfYear( - date, - ).toString(); + final String weekNumber = + DateTimeHelper.getWeekNumberOfYear(date).toString(); double xPosition = isRTL ? size.width - weekNumberPanelWidth : 0; final TextStyle weekNumberTextStyle = calendarTheme.weekNumberTextStyle!; final TextSpan textSpan = TextSpan( @@ -1002,21 +1001,24 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { final double cellWidth = (size.width - weekNumberPanelWidth) / DateTime.daysPerWeek; final double cellHeight = size.height / rowCount; - double xPosition = isRTL - ? size.width - cellWidth - weekNumberPanelWidth - : weekNumberPanelWidth; + double xPosition = + isRTL + ? size.width - cellWidth - weekNumberPanelWidth + : weekNumberPanelWidth; double yPosition = viewPadding; _textPainter.textDirection = TextDirection.ltr; _textPainter.textWidthBasis = TextWidthBasis.longestLine; _textPainter.textScaler = TextScaler.linear(textScaleFactor); final int visibleDatesCount = visibleDates.length; final DateTime currentMonthDate = visibleDates[visibleDatesCount ~/ 2]; - final int nextMonth = DateTimeHelper.getDateTimeValue( - getNextMonthDate(currentMonthDate), - ).month; - final int previousMonth = DateTimeHelper.getDateTimeValue( - getPreviousMonthDate(currentMonthDate), - ).month; + final int nextMonth = + DateTimeHelper.getDateTimeValue( + getNextMonthDate(currentMonthDate), + ).month; + final int previousMonth = + DateTimeHelper.getDateTimeValue( + getPreviousMonthDate(currentMonthDate), + ).month; final DateTime today = DateTime.now(); bool isCurrentDate; @@ -1024,15 +1026,16 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { final TextStyle todayStyle = calendarTheme.todayTextStyle!; final TextStyle currentMonthTextStyle = calendarTheme.activeDatesTextStyle!; final TextStyle previousMonthTextStyle = - calendarTheme.trailingDatesTextStyle!; - final TextStyle nextMonthTextStyle = calendarTheme.leadingDatesTextStyle!; + calendarTheme.leadingDatesTextStyle!; + final TextStyle nextMonthTextStyle = calendarTheme.trailingDatesTextStyle!; final TextStyle? blackoutDatesStyle = calendarTheme.blackoutDatesTextStyle; final TextStyle disabledTextStyle = currentMonthTextStyle.copyWith( - color: currentMonthTextStyle.color != null - ? currentMonthTextStyle.color!.withValues(alpha: 0.38) - : themeData.brightness == Brightness.light - ? Colors.black26 - : Colors.white38, + color: + currentMonthTextStyle.color != null + ? currentMonthTextStyle.color!.withValues(alpha: 0.38) + : themeData.brightness == Brightness.light + ? Colors.black26 + : Colors.white38, ); final bool showTrailingLeadingDates = @@ -1298,9 +1301,8 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { _linePainter.strokeWidth = linePadding; _linePainter.color = cellBorderColor ?? calendarTheme.cellBorderColor!; xPosition = isRTL ? 0 : weekNumberPanelWidth; - final double finalXPosition = isRTL - ? size.width - weekNumberPanelWidth - : size.width; + final double finalXPosition = + isRTL ? size.width - weekNumberPanelWidth : size.width; canvas.drawLine( Offset(xPosition, linePadding), Offset(finalXPosition, linePadding), @@ -1311,16 +1313,16 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { Offset( isMobilePlatform ? isRTL - ? 0 - : weekNumberPanelWidth + ? 0 + : weekNumberPanelWidth : 0, yPosition, ), Offset( isMobilePlatform ? isRTL - ? size.width - weekNumberPanelWidth - : size.width + ? size.width - weekNumberPanelWidth + : size.width : size.width, yPosition, ), @@ -1334,9 +1336,8 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { Offset(size.width, size.height - linePadding), _linePainter, ); - xPosition = weekNumberPanelWidth != 0 && !isRTL - ? weekNumberPanelWidth - : cellWidth; + xPosition = + weekNumberPanelWidth != 0 && !isRTL ? weekNumberPanelWidth : cellWidth; canvas.drawLine( const Offset(linePadding, 0), Offset(linePadding, size.height), @@ -1379,9 +1380,10 @@ class _MonthViewRenderObject extends CustomCalendarRenderObject { final double cellWidth = (size.width - weekNumberPanelWidth) / DateTime.daysPerWeek; - double left = isRTL - ? size.width - cellWidth - weekNumberPanelWidth - : weekNumberPanelWidth, + double left = + isRTL + ? size.width - cellWidth - weekNumberPanelWidth + : weekNumberPanelWidth, top = 0; final double cellHeight = size.height / rowCount; final bool showTrailingLeadingDates = diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/timeline_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/timeline_view.dart index 874439d87..c6b6084aa 100644 --- a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/timeline_view.dart +++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/timeline_view.dart @@ -934,13 +934,14 @@ class _TimelineRenderObject extends CustomCalendarRenderObject { double leftPosition = 0; const double topPosition = 0; - final double xPosition = isTimelineMonth - ? 0 - : CalendarViewHelper.getTimeToPosition( - Duration(hours: disabledDate.hour, minutes: disabledDate.minute), - timeSlotViewSettings, - minuteHeight, - ); + final double xPosition = + isTimelineMonth + ? 0 + : CalendarViewHelper.getTimeToPosition( + Duration(hours: disabledDate.hour, minutes: disabledDate.minute), + timeSlotViewSettings, + minuteHeight, + ); double rightPosition = (dateIndex * viewWidth) + xPosition; if (isMaxDate == true) { leftPosition = @@ -1047,18 +1048,19 @@ class _TimelineRenderObject extends CustomCalendarRenderObject { double top = 0; double height = size.height; if (isResourceEnabled) { - final int index = (calendarCellNotifier.value!.dy / resourceItemHeight) - .truncate(); + final int index = + (calendarCellNotifier.value!.dy / resourceItemHeight).truncate(); top = index * resourceItemHeight; height = resourceItemHeight; } const double padding = 0.5; top = top == 0 ? padding : top; - height = height == size.height - ? top == padding - ? height - (padding * 2) - : height - padding - : height; + height = + height == size.height + ? top == padding + ? height - (padding * 2) + : height - padding + : height; double width = timeIntervalWidth; double difference = 0; if (isRTL && @@ -1107,9 +1109,10 @@ class _TimelineRenderObject extends CustomCalendarRenderObject { _linePainter.style = PaintingStyle.fill; final int count = specialRegionBounds.length; final TextStyle defaultTextStyle = TextStyle( - color: themeData.brightness == Brightness.dark - ? Colors.white54 - : Colors.black45, + color: + themeData.brightness == Brightness.dark + ? Colors.white54 + : Colors.black45, ); for (int i = 0; i < count; i++) { final TimeRegionView view = specialRegionBounds[i]; @@ -1327,14 +1330,16 @@ class TimelineViewHeaderView extends CustomPainter { final bool isTimelineMonth = visibleDatesLength > DateTime.daysPerWeek; final DateTime today = DateTime.now(); final double childWidth = size.width / visibleDatesLength; - final int index = isTimelineMonth - ? 0 - : timelineViewHeaderScrollController.offset ~/ childWidth; - _xPosition = !isTimelineMonth - ? timelineViewHeaderScrollController.offset - : isRTL - ? size.width - childWidth - : 0; + final int index = + isTimelineMonth + ? 0 + : timelineViewHeaderScrollController.offset ~/ childWidth; + _xPosition = + !isTimelineMonth + ? timelineViewHeaderScrollController.offset + : isRTL + ? size.width - childWidth + : 0; final TextStyle defaultThemeViewHeaderDayTextStyle = themeData .textTheme @@ -1394,8 +1399,8 @@ class TimelineViewHeaderView extends CustomPainter { String dayFormat = 'EE'; dayFormat = dayFormat == timeSlotViewSettings.dayFormat && !isTimelineMonth - ? 'EEEE' - : timeSlotViewSettings.dayFormat; + ? 'EEEE' + : timeSlotViewSettings.dayFormat; final String dayText = DateFormat(dayFormat, locale).format(currentDate); final String dateText = DateFormat( @@ -1408,18 +1413,20 @@ class TimelineViewHeaderView extends CustomPainter { ); if (isSameDate(currentDate, today)) { - dayTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: viewHeaderDayStyle.fontSize, - color: todayTextColor, - ) - : viewHeaderDayStyle.copyWith(color: todayTextColor); - dateTextStyle = todayTextStyle != null - ? calendarTheme.todayTextStyle!.copyWith( - fontSize: viewHeaderDateStyle.fontSize, - color: todayTextColor, - ) - : viewHeaderDateStyle.copyWith(color: todayTextColor); + dayTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: viewHeaderDayStyle.fontSize, + color: todayTextColor, + ) + : viewHeaderDayStyle.copyWith(color: todayTextColor); + dateTextStyle = + todayTextStyle != null + ? calendarTheme.todayTextStyle!.copyWith( + fontSize: viewHeaderDateStyle.fontSize, + color: todayTextColor, + ) + : viewHeaderDateStyle.copyWith(color: todayTextColor); } else { dateTextStyle = viewHeaderDateStyle; dayTextStyle = viewHeaderDayStyle; @@ -1441,18 +1448,20 @@ class TimelineViewHeaderView extends CustomPainter { if (!isDateWithInDateRange(minDate, maxDate, currentDate)) { dayTextStyle = dayTextStyle.copyWith( - color: dayTextStyle.color != null - ? dayTextStyle.color!.withValues(alpha: 0.38) - : themeData.brightness == Brightness.light - ? Colors.black26 - : Colors.white38, + color: + dayTextStyle.color != null + ? dayTextStyle.color!.withValues(alpha: 0.38) + : themeData.brightness == Brightness.light + ? Colors.black26 + : Colors.white38, ); dateTextStyle = dateTextStyle.copyWith( - color: dateTextStyle.color != null - ? dateTextStyle.color!.withValues(alpha: 0.38) - : themeData.brightness == Brightness.light - ? Colors.black26 - : Colors.white38, + color: + dateTextStyle.color != null + ? dateTextStyle.color!.withValues(alpha: 0.38) + : themeData.brightness == Brightness.light + ? Colors.black26 + : Colors.white38, ); } @@ -1618,30 +1627,31 @@ class TimelineViewHeaderView extends CustomPainter { timelineViewHeaderScrollController.position.viewportDimension - size.width; } - final double leftPosition = isRTL && cellWidth == null - ? size.width - - _xPosition - - (_padding * 2) - - _dayTextPainter.width - - _dateTextPainter.width - - _padding - : _xPosition; - final double rightPosition = isRTL && cellWidth == null - ? size.width - _xPosition - : cellWidth != null - ? _xPosition + cellWidth - _padding - : _xPosition + - _dayTextPainter.width + - _dateTextPainter.width + - (2 * _padding); + final double leftPosition = + isRTL && cellWidth == null + ? size.width - + _xPosition - + (_padding * 2) - + _dayTextPainter.width - + _dateTextPainter.width - + _padding + : _xPosition; + final double rightPosition = + isRTL && cellWidth == null + ? size.width - _xPosition + : cellWidth != null + ? _xPosition + cellWidth - _padding + : _xPosition + + _dayTextPainter.width + + _dateTextPainter.width + + (2 * _padding); if (leftPosition + difference <= viewHeaderNotifier.value!.dx && rightPosition + difference >= viewHeaderNotifier.value!.dx && (size.height) - _padding >= viewHeaderNotifier.value!.dy) { - _hoverPainter.color = - (themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black87) - .withValues(alpha: 0.04); + _hoverPainter.color = (themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black87) + .withValues(alpha: 0.04); canvas.drawRect( Rect.fromLTRB(leftPosition, 0, rightPosition + _padding, size.height), _hoverPainter, diff --git a/packages/syncfusion_flutter_calendar/pubspec.yaml b/packages/syncfusion_flutter_calendar/pubspec.yaml index 23e430109..43c64eb61 100644 --- a/packages/syncfusion_flutter_calendar/pubspec.yaml +++ b/packages/syncfusion_flutter_calendar/pubspec.yaml @@ -1,7 +1,7 @@ name: syncfusion_flutter_calendar description: The Flutter Calendar widget has nine built-in configurable views that provide basic functionalities for scheduling and representing appointments/events efficiently. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_calendar screenshots: @@ -14,7 +14,7 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" flutter: assets: @@ -35,5 +35,3 @@ dependencies: syncfusion_localizations: path: ../syncfusion_localizations - - diff --git a/packages/syncfusion_flutter_charts/CHANGELOG.md b/packages/syncfusion_flutter_charts/CHANGELOG.md index d682cc4a6..60429e187 100644 --- a/packages/syncfusion_flutter_charts/CHANGELOG.md +++ b/packages/syncfusion_flutter_charts/CHANGELOG.md @@ -1,3 +1,19 @@ +## Unreleased + +### Features + +* \#FR68922 - [PlotBand](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/PlotBand-class.html) now provides an option to override its rendering using the `drawRect` and `drawText` methods. + +**Bugs** + +* \#GH2464 - Now, the series fill updates correctly when the axis range changes during screen resize or orientation changes. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter charts widget has been updated to Flutter SDK 3.35.0. + ## [30.2.6+1] - 20/08/2025 **Bugs** diff --git a/packages/syncfusion_flutter_charts/example/android/app/build.gradle b/packages/syncfusion_flutter_charts/example/android/app/build.gradle.kts similarity index 76% rename from packages/syncfusion_flutter_charts/example/android/app/build.gradle rename to packages/syncfusion_flutter_charts/example/android/app/build.gradle.kts index beb1a9fa2..d0ab331f6 100644 --- a/packages/syncfusion_flutter_charts/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_charts/example/android/app/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { @@ -11,12 +11,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_charts/example/android/app/src/main/kotlin/com/example/charts_example/MainActivity.kt b/packages/syncfusion_flutter_charts/example/android/app/src/main/kotlin/com/example/charts_example/MainActivity.kt index 713a4bb67..76ebaac95 100644 --- a/packages/syncfusion_flutter_charts/example/android/app/src/main/kotlin/com/example/charts_example/MainActivity.kt +++ b/packages/syncfusion_flutter_charts/example/android/app/src/main/kotlin/com/example/charts_example/MainActivity.kt @@ -2,4 +2,4 @@ package com.example.charts_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/packages/syncfusion_flutter_charts/example/android/build.gradle b/packages/syncfusion_flutter_charts/example/android/build.gradle deleted file mode 100644 index d2ffbffa4..000000000 --- a/packages/syncfusion_flutter_charts/example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/packages/syncfusion_flutter_charts/example/android/build.gradle.kts b/packages/syncfusion_flutter_charts/example/android/build.gradle.kts new file mode 100644 index 000000000..dbee657bb --- /dev/null +++ b/packages/syncfusion_flutter_charts/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_charts/example/android/gradle.properties b/packages/syncfusion_flutter_charts/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_charts/example/android/gradle.properties +++ b/packages/syncfusion_flutter_charts/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_charts/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_charts/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_charts/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_charts/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_charts/example/android/settings.gradle b/packages/syncfusion_flutter_charts/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/syncfusion_flutter_charts/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_charts/example/android/settings.gradle.kts b/packages/syncfusion_flutter_charts/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_charts/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/axis/axis.dart b/packages/syncfusion_flutter_charts/lib/src/charts/axis/axis.dart index 0717ac546..d3a93a324 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/axis/axis.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/axis/axis.dart @@ -3301,6 +3301,7 @@ abstract class RenderChartAxis extends RenderBox with ChartAreaUpdateMixin { translateX: paddingFromSize(plotBand.horizontalTextPadding, bounds.width), translateY: paddingFromSize(plotBand.verticalTextPadding, bounds.height), shouldRenderAboveSeries: plotBand.shouldRenderAboveSeries, + plotBand: plotBand, ); visiblePlotBands!.add(plotBandDetails); } @@ -4095,6 +4096,7 @@ class AxisPlotBand { required this.translateX, required this.translateY, required this.shouldRenderAboveSeries, + required this.plotBand, }); final Rect bounds; @@ -4112,6 +4114,7 @@ class AxisPlotBand { final double translateX; final double translateY; final bool shouldRenderAboveSeries; + final PlotBand plotBand; } abstract class _PlotBandRenderer { @@ -4146,43 +4149,44 @@ abstract class _PlotBandRenderer { offset += plotAreaOffset; context.canvas.save(); context.canvas.clipRect(axis.parent!.plotAreaBounds); - for (final AxisPlotBand plotBand in axis.visiblePlotBands!) { - if (shouldRenderAboveSeries == plotBand.shouldRenderAboveSeries) { - final Rect bounds = plotBand.bounds.translate(offset.dx, offset.dy); - final Paint paint = Paint(); - if (plotBand.gradient != null) { - paint.shader = plotBand.gradient!.createShader(bounds); + final List visiblePlotBands = axis.visiblePlotBands!; + for (final AxisPlotBand axisPlotBand in visiblePlotBands) { + if (shouldRenderAboveSeries == axisPlotBand.shouldRenderAboveSeries) { + final Rect bounds = axisPlotBand.bounds.translate(offset.dx, offset.dy); + final Paint fillPaint = Paint(); + if (axisPlotBand.gradient != null) { + fillPaint.shader = axisPlotBand.gradient!.createShader(bounds); } else { - if (plotBand.opacity < 1.0) { - paint.color = plotBand.color.withValues(alpha: plotBand.opacity); + if (axisPlotBand.opacity < 1.0) { + fillPaint.color = axisPlotBand.color.withValues( + alpha: axisPlotBand.opacity, + ); } else { - paint.color = plotBand.color; + fillPaint.color = axisPlotBand.color; } } - if (paint.color != Colors.transparent && bounds.width != 0.0) { - context.canvas.drawRect(bounds, paint); - } - - if (plotBand.borderWidth > 0 && - plotBand.borderColor != Colors.transparent) { - paint + final Paint strokePaint = Paint(); + if (axisPlotBand.borderWidth > 0 && + axisPlotBand.borderColor != Colors.transparent) { + strokePaint ..color = - plotBand.opacity < 1.0 - ? plotBand.borderColor.withValues(alpha: plotBand.opacity) - : plotBand.borderColor - ..strokeWidth = plotBand.borderWidth + axisPlotBand.opacity < 1.0 + ? axisPlotBand.borderColor.withValues( + alpha: axisPlotBand.opacity, + ) + : axisPlotBand.borderColor + ..strokeWidth = axisPlotBand.borderWidth ..style = PaintingStyle.stroke; - final Path path = - Path() - ..moveTo(bounds.left, bounds.top) - ..lineTo(bounds.left + bounds.width, bounds.top) - ..lineTo(bounds.left + bounds.width, bounds.top + bounds.height) - ..lineTo(bounds.left, bounds.top + bounds.height) - ..close(); - drawDashes(context.canvas, plotBand.dashArray, paint, path: path); } - _drawText(context, bounds, plotBand); + + axisPlotBand.plotBand.drawRect( + context.canvas, + bounds, + fillPaint, + strokePaint, + ); + _drawText(context, bounds, axisPlotBand); } } context.canvas.restore(); @@ -4236,37 +4240,35 @@ class _HorizontalPlotBandRenderer extends _PlotBandRenderer { _HorizontalPlotBandRenderer(RenderChartAxis axis) : super(axis); @override - void _drawText(PaintingContext context, Rect bounds, AxisPlotBand plotBand) { - if (plotBand.text.isNotEmpty) { - TextStyle style = plotBand.textStyle; - if (plotBand.opacity < 1.0) { + void _drawText( + PaintingContext context, + Rect bounds, + AxisPlotBand axisPlotBand, + ) { + if (axisPlotBand.text.isNotEmpty) { + TextStyle style = axisPlotBand.textStyle; + if (axisPlotBand.opacity < 1.0) { style = style.copyWith( - color: style.color?.withValues(alpha: plotBand.opacity), + color: style.color?.withValues(alpha: axisPlotBand.opacity), ); } - final TextSpan span = TextSpan(text: plotBand.text, style: style); + final TextSpan span = TextSpan(text: axisPlotBand.text, style: style); _textPainter ..text = span ..textAlign = TextAlign.center ..textDirection = TextDirection.ltr ..layout(); final Offset position = _textPosition( - plotBand, + axisPlotBand, bounds, _textPainter.size, ); - if (plotBand.textAngle == 0) { - _textPainter.paint(context.canvas, position); - } else { - final double halfWidth = _textPainter.width / 2; - final double halfHeight = _textPainter.height / 2; - context.canvas - ..save() - ..translate(position.dx + halfWidth, position.dy + halfHeight) - ..rotate(degreeToRadian(plotBand.textAngle)); - _textPainter.paint(context.canvas, Offset(-halfWidth, -halfHeight)); - context.canvas.restore(); - } + axisPlotBand.plotBand.drawText( + context.canvas, + position, + style, + axisPlotBand.textAngle, + ); } } } @@ -4275,37 +4277,35 @@ class _VerticalPlotBandRenderer extends _PlotBandRenderer { _VerticalPlotBandRenderer(RenderChartAxis axis) : super(axis); @override - void _drawText(PaintingContext context, Rect bounds, AxisPlotBand plotBand) { - if (plotBand.text.isNotEmpty) { - TextStyle style = plotBand.textStyle; - if (plotBand.opacity < 1.0) { + void _drawText( + PaintingContext context, + Rect bounds, + AxisPlotBand axisPlotBand, + ) { + if (axisPlotBand.text.isNotEmpty) { + TextStyle style = axisPlotBand.textStyle; + if (axisPlotBand.opacity < 1.0) { style = style.copyWith( - color: style.color?.withValues(alpha: plotBand.opacity), + color: style.color?.withValues(alpha: axisPlotBand.opacity), ); } - final TextSpan span = TextSpan(text: plotBand.text, style: style); + final TextSpan span = TextSpan(text: axisPlotBand.text, style: style); _textPainter ..text = span ..textAlign = TextAlign.center ..textDirection = TextDirection.ltr ..layout(); final Offset position = _textPosition( - plotBand, + axisPlotBand, bounds, _textPainter.size, ); - if (plotBand.textAngle == 0) { - _textPainter.paint(context.canvas, position); - } else { - final double halfWidth = _textPainter.width / 2; - final double halfHeight = _textPainter.height / 2; - context.canvas - ..save() - ..translate(position.dx + halfWidth, position.dy + halfHeight) - ..rotate(degreeToRadian(plotBand.textAngle)); - _textPainter.paint(context.canvas, Offset(-halfWidth, -halfHeight)); - context.canvas.restore(); - } + axisPlotBand.plotBand.drawText( + context.canvas, + position, + style, + axisPlotBand.textAngle, + ); } } } diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/axis/category_axis.dart b/packages/syncfusion_flutter_charts/lib/src/charts/axis/category_axis.dart index 7b099177b..9abcd1478 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/axis/category_axis.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/axis/category_axis.dart @@ -584,7 +584,7 @@ class RenderCategoryAxis extends RenderChartAxis { for (final AxisDependent dependent in dependents) { if (dependent is CartesianSeriesRenderer) { if (dependent.controller.isVisible) { - final List actualXValues = dependent.xRawValues; + final List actualXValues = dependent.xRawValues; final int actualXValuesLength = actualXValues.length; for (int i = 0; i < actualXValuesLength; i++) { final String rawX = actualXValues[i].toString(); @@ -938,7 +938,7 @@ class RenderCategoryAxis extends RenderChartAxis { for (final AxisDependent dependent in dependents) { if (dependent is CartesianSeriesRenderer && dependent.controller.isVisible) { - final List xRawValues = dependent.xRawValues; + final List xRawValues = dependent.xRawValues; final int length = xRawValues.length; if (length > 0) { num minValue = 0; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/axis/datetime_category_axis.dart b/packages/syncfusion_flutter_charts/lib/src/charts/axis/datetime_category_axis.dart index ec00cdda2..53955e324 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/axis/datetime_category_axis.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/axis/datetime_category_axis.dart @@ -1150,7 +1150,7 @@ class RenderDateTimeCategoryAxis extends RenderChartAxis { for (final AxisDependent dependent in dependents) { if (dependent is CartesianSeriesRenderer && dependent.controller.isVisible) { - final List xRawValues = dependent.xRawValues; + final List xRawValues = dependent.xRawValues; final int length = xRawValues.length; if (length > 0) { const int minValue = 0; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/axis/plot_band.dart b/packages/syncfusion_flutter_charts/lib/src/charts/axis/plot_band.dart index bcb60468e..9c7345078 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/axis/plot_band.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/axis/plot_band.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../utils/enum.dart'; +import '../utils/helper.dart'; /// Render plot band. /// @@ -474,8 +475,8 @@ class PlotBand { /// /// Defaults to `TextAnchor.middle`. /// - ///```dart - ///Widget build(BuildContext context) { + /// ```dart + /// Widget build(BuildContext context) { /// return Container( /// child: SfCartesianChart( /// primaryXAxis: NumericAxis( @@ -488,8 +489,8 @@ class PlotBand { /// ) /// ) /// ); - ///} - ///``` + /// } + /// ``` final TextAnchor horizontalTextAlignment; /// Fills the plot band with gradient color. @@ -529,20 +530,19 @@ class PlotBand { /// /// Takes pixel or percentage value. For pixel, input should be like `10px` /// and for percentage input should be like `10%`. If no suffix is specified - // (`10`), it will be considered as pixel value. Percentage value refers to - // the overall height of the chart. i.e. 100% is equal to the height + /// (`10`), it will be considered as pixel value. Percentage value refers to + /// the overall height of the chart. i.e. 100% is equal to the height /// of the chart. /// /// This is applicable for both vertical and horizontal axis. Positive value /// for this property moves the text upwards and negative - // value moves downwards. + /// value moves downwards. /// /// If [verticalTextAlignment] or [horizontalTextAlignment] is specified, /// text padding will be calculated from that modified position. /// /// Defaults to `null`. /// - /// /// ```dart /// Widget build(BuildContext context) { /// return Container( @@ -592,6 +592,132 @@ class PlotBand { /// } /// ``` final String? horizontalTextPadding; + + /// The rectangle rendering of a plotband, based on the start + /// and end values defined. + /// + /// Allows complete customization of the plot band custom shapes + /// appearance using canvas drawing operations. + /// + /// Custom visuals such as gradients, patterns, textures, borders, and + /// transparency effects can be implemented. + /// + /// [rect] defines the plot band rendering bounds. + /// + /// Example – render a rectangle with corner radius: + /// + /// ```dart + /// class CustomPlotBand extends PlotBand { + /// @override + /// void drawRect( + /// Canvas canvas, + /// Rect rect, + /// Paint fillPaint, [ + /// Paint? strokePaint, + /// ]) { + /// canvas.drawRRect( + /// RRect.fromRectAndRadius(rect, const Radius.circular(8)), + /// fillPaint, + /// ); + /// } + /// } + /// ``` + void drawRect( + Canvas canvas, + Rect rect, + Paint fillPaint, [ + Paint? strokePaint, + ]) { + if (fillPaint.color != Colors.transparent && rect.width != 0.0) { + canvas.drawRect(rect, fillPaint); + } + if (strokePaint != null && + strokePaint.strokeWidth > 0 && + strokePaint.color != Colors.transparent) { + final double left = rect.left; + final double top = rect.top; + final double width = rect.width; + final double height = rect.height; + final Path path = + Path() + ..moveTo(left, top) + ..lineTo(left + width, top) + ..lineTo(left + width, top + height) + ..lineTo(left, top + height) + ..close(); + drawDashes(canvas, dashArray, strokePaint, path: path); + } + } + + /// Draws the context (label) of a plotband. + /// + /// Allows a complete customization of bespoke typography, + /// dynamic positioning, drop shadows, or interactive effects. + /// + /// [position] represents the top-left origin of the text. + /// [angle] is the clockwise rotation angle in degrees. + /// + /// Example – render a rotated label with a pill-shaped highlight: + /// + /// ```dart + /// class RibbonLabelPlotBand extends PlotBand { + /// const RibbonLabelPlotBand() + /// : super(text: 'Target Range', textAngle: 45); + /// + /// @override + /// void drawText(Canvas canvas, Offset position, TextStyle style, + /// int angle) { + /// final TextPainter painter = TextPainter( + /// text: TextSpan(text: text), + /// textAlign: TextAlign.center, + /// textDirection: TextDirection.ltr, + /// )..layout(); + /// final Offset center = + /// position + Offset(painter.width / 2, painter.height / 2); + /// + /// canvas.save(); + /// canvas.translate(center.dx, center.dy); + /// canvas.rotate(angle * (pi / 180)); + /// final Rect capsule = Rect.fromCenter( + /// center: Offset.zero, + /// width: painter.width + 12, + /// height: painter.height + 8, + /// ); + /// canvas.drawRRect( + /// RRect.fromRectAndRadius(capsule, const Radius.circular(12)), + /// Paint()..color = Colors.deepPurple.withAlpha(115), + /// ); + /// painter.paint(canvas, + /// Offset(-painter.width / 2, -painter.height / 2)); + /// canvas.restore(); + /// } + /// } + /// ``` + void drawText(Canvas canvas, Offset position, TextStyle style, int angle) { + if (text == null || text!.isEmpty) { + return; + } + final TextSpan span = TextSpan(text: text, style: style); + final TextPainter textPainter = TextPainter( + text: span, + textAlign: TextAlign.center, + textDirection: TextDirection.ltr, + ); + textPainter.layout(); + if (angle == 0) { + textPainter.paint(canvas, position); + } else { + final double halfWidth = textPainter.width / 2; + final double halfHeight = textPainter.height / 2; + canvas + ..save() + ..translate(position.dx + halfWidth, position.dy + halfHeight) + ..rotate(degreesToRadians(angle.toDouble())); + textPainter.paint(canvas, Offset(-halfWidth, -halfHeight)); + canvas.restore(); + } + } + @override bool operator ==(Object other) { if (identical(this, other)) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/base.dart b/packages/syncfusion_flutter_charts/lib/src/charts/base.dart index 62d9e4db0..c2fcd3645 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/base.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/base.dart @@ -2000,7 +2000,7 @@ class CartesianAxes extends MultiChildRenderObjectWidget { final bool isTransposed; final ChartAxisLabelTapCallback? onAxisLabelTapped; final ChartActualRangeChangedCallback? onActualRangeChanged; - final List indicators; + final List> indicators; final SfChartThemeData chartThemeData; @override @@ -2090,9 +2090,10 @@ class RenderCartesianAxes extends RenderBox } } - List get indicators => _indicators; - List _indicators = []; - set indicators(List value) { + List> get indicators => _indicators; + List> _indicators = + >[]; + set indicators(List> value) { if (_indicators != value) { _indicators = value; markNeedsUpdate(); @@ -2696,7 +2697,7 @@ class IndicatorStack extends StatefulWidget { }); final TickerProvider vsync; - final List indicators; + final List> indicators; final bool isTransposed; final ChartLegendTapCallback? onLegendTapped; final ChartLegendRenderCallback? onLegendItemRender; @@ -2714,7 +2715,8 @@ class _IndicatorStackState extends State { final int length = widget.indicators.length; for (int i = 0; i < length; i++) { late Widget current; - final TechnicalIndicator indicator = widget.indicators[i]; + final TechnicalIndicator indicator = + widget.indicators[i]; switch (indicator.toString()) { case 'AD': current = ADIndicatorWidget( @@ -2869,7 +2871,7 @@ class IndicatorArea extends MultiChildRenderObjectWidget { super.children, }); - final List indicators; + final List> indicators; final TrackballBehavior? trackballBehavior; final TextDirection? textDirection; @@ -2902,7 +2904,7 @@ class RenderIndicatorArea extends RenderBox RenderCartesianChartArea? chartArea; TrackballBehavior? trackballBehavior; late TextDirection? textDirection; - late List indicators; + late List> indicators; final Map series = {}; @override diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/crosshair.dart b/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/crosshair.dart index 4135e1a68..5872db02b 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/crosshair.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/crosshair.dart @@ -342,7 +342,7 @@ class CrosshairBehavior extends ChartBehavior { if (parent != null && parent.plotArea != null && parent.plotArea!.firstChild != null) { - final CartesianSeriesRenderer seriesRenderer = + final CartesianSeriesRenderer seriesRenderer = parent.plotArea!.firstChild! as CartesianSeriesRenderer; final List visibleIndexes = seriesRenderer.visibleIndexes; if (visibleIndexes.isNotEmpty && diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/trackball.dart b/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/trackball.dart index 398e6bb36..a37894b2b 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/trackball.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/behaviors/trackball.dart @@ -360,7 +360,7 @@ class TrackballBehavior extends ChartBehavior { /// ); /// } /// ``` - final ChartTrackballBuilder? builder; + final ChartTrackballBuilder? builder; /// Hold trackball target position. Offset? _position; @@ -493,7 +493,7 @@ class TrackballBehavior extends ChartBehavior { if (parent != null && parent.plotArea != null && parent.plotArea!.firstChild != null) { - final CartesianSeriesRenderer renderer = + final CartesianSeriesRenderer renderer = parent.plotArea!.firstChild! as CartesianSeriesRenderer; final List visibleIndexes = renderer.visibleIndexes; if (visibleIndexes.isNotEmpty && @@ -661,7 +661,8 @@ class TrackballBehavior extends ChartBehavior { parent.invalidate(); if (builder != null) { final List details = []; - final List chartPoints = []; + final List> chartPoints = + >[]; final List currentPointIndices = []; final List visibleSeriesIndices = []; final List visibleSeriesList = []; @@ -767,7 +768,7 @@ class TrackballBehavior extends ChartBehavior { ); if (trackballInfo != null) { - final ChartTrackballInfo trackInfo = + final ChartTrackballInfo trackInfo = trackballInfo as ChartTrackballInfo; if (trackInfo.pointIndex >= 0) { final Offset trackPosition = trackInfo.position!; @@ -817,8 +818,9 @@ class TrackballBehavior extends ChartBehavior { trackballInfo.isNotEmpty && child.animationFactor == 1) { for (final TrackballInfo trackInfo in trackballInfo) { - final ChartTrackballInfo info = trackInfo as ChartTrackballInfo; - final CartesianChartPoint chartPoint = info.point; + final ChartTrackballInfo info = + trackInfo as ChartTrackballInfo; + final CartesianChartPoint chartPoint = info.point; final bool pointIsNaN = (chartPoint.xValue != null && chartPoint.xValue!.isNaN) || (chartPoint.y != null && chartPoint.y!.isNaN); @@ -917,7 +919,7 @@ class TrackballBehavior extends ChartBehavior { } List _findNearestChartPointIndexes( - CartesianSeriesRenderer series, + CartesianSeriesRenderer series, Offset position, ) { final List indexes = []; @@ -987,7 +989,7 @@ class TrackballBehavior extends ChartBehavior { } void _addChartPointInfo( - ChartTrackballInfo trackballInfo, + ChartTrackballInfo trackballInfo, double xPos, double yPos, ) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/cartesian_chart.dart b/packages/syncfusion_flutter_charts/lib/src/charts/cartesian_chart.dart index 07a5062ad..2d8621618 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/cartesian_chart.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/cartesian_chart.dart @@ -152,10 +152,10 @@ class SfCartesianChart extends StatefulWidget { this.enableMultiSelection = false, this.crosshairBehavior, this.trackballBehavior, - this.series = const [], + this.series = const >[], this.title = const ChartTitle(), this.axes = const [], - this.indicators = const [], + this.indicators = const >[], }) : super(key: key); /// Customizes the chart title. @@ -990,7 +990,7 @@ class SfCartesianChart extends StatefulWidget { /// ); /// } /// ``` - final List series; + final List> series; /// Color palette for chart series. If the series color is not specified, /// then the series will be rendered with appropriate palette color. @@ -1008,7 +1008,7 @@ class SfCartesianChart extends StatefulWidget { final List? palette; /// Technical indicators for charts. - final List indicators; + final List> indicators; /// A builder that builds the widget (ex., loading indicator or load more /// button) to display at the top of the chart area when horizontal scrolling diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/circular_chart.dart b/packages/syncfusion_flutter_charts/lib/src/charts/circular_chart.dart index 0eaac161d..ce71d5284 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/circular_chart.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/circular_chart.dart @@ -74,7 +74,7 @@ class SfCircularChart extends StatefulWidget { this.onCreateShader, this.palette, this.margin = const EdgeInsets.fromLTRB(10, 10, 10, 10), - this.series = const [], + this.series = const >[], this.title = const ChartTitle(), this.legend = const Legend(), this.centerX = '50%', @@ -112,7 +112,7 @@ class SfCircularChart extends StatefulWidget { /// ); /// } /// ``` - final List series; + final List> series; /// Specifies the margin for circular chart. /// diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/callbacks.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/callbacks.dart index e8d879604..973a890cb 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/callbacks.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/callbacks.dart @@ -36,7 +36,7 @@ class TooltipArgs { final dynamic seriesIndex; /// Get the list of data points in the series. - final List? dataPoints; + final List? dataPoints; /// Get the overall index value of the tooltip. final num? pointIndex; @@ -429,7 +429,7 @@ class ChartPointDetails { final int? pointIndex; /// Get the list of data points. - final List? dataPoints; + final List? dataPoints; /// Get the view port index value. final num? viewportPointIndex; @@ -554,7 +554,7 @@ class IndicatorRenderArgs { ]); /// Get the technical indicator information. - final TechnicalIndicator? indicator; + final TechnicalIndicator? indicator; /// Get the indicator name. late String indicatorName; @@ -575,7 +575,7 @@ class IndicatorRenderArgs { final String? seriesName; /// Get the current data points. - final List? dataPoints; + final List? dataPoints; } /// Holds the onMarkerRender event arguments. @@ -701,7 +701,7 @@ class IndicatorRenderParams { ); /// Gets the calculated indicator data points details. - final List? calculatedDataPoints; + final List>? calculatedDataPoints; /// Gets the width of the signal line. late double signalLineWidth; @@ -736,10 +736,10 @@ class BollingerBandIndicatorRenderParams extends IndicatorRenderParams { ); /// Gets the calculated upper line values of the Bollinger band indicator. - final List? upperLineValues; + final List>? upperLineValues; /// Gets the calculated lower line values of the Bollinger band indicator. - final List? lowerLineValues; + final List>? lowerLineValues; } /// Holds the onRenderDetailsUpdate callback arguments. @@ -747,7 +747,7 @@ class MomentumIndicatorRenderParams extends IndicatorRenderParams { /// Creating an argument constructor of MomentumIndicatorRenderParams class. MomentumIndicatorRenderParams( this.centerLineValue, - List? calculatedDataPoints, + List>? calculatedDataPoints, String name, double signalLineWidth, Color signalLineColor, @@ -769,7 +769,7 @@ class RocIndicatorRenderParams extends IndicatorRenderParams { /// Creating an argument constructor of RocIndicatorRenderParams class. RocIndicatorRenderParams( this.centerLineValue, - List? calculatedDataPoints, + List>? calculatedDataPoints, String name, double signalLineWidth, Color signalLineColor, @@ -791,7 +791,7 @@ class StochasticIndicatorRenderParams extends IndicatorRenderParams { /// Creating an argument constructor of StochasticIndicatorRenderParams class. StochasticIndicatorRenderParams( this.periodLineValues, - List? calculatedDataPoints, + List>? calculatedDataPoints, String name, double signalLineWidth, Color signalLineColor, @@ -805,7 +805,7 @@ class StochasticIndicatorRenderParams extends IndicatorRenderParams { ); /// Gets the calculated period line values of the stochastic indicator. - final List? periodLineValues; + final List>? periodLineValues; } /// Holds the onRenderDetailsUpdate callback arguments. @@ -814,7 +814,7 @@ class MacdIndicatorRenderParams extends IndicatorRenderParams { MacdIndicatorRenderParams( this.macdLineValues, this.macdHistogramValues, - List? calculatedDataPoints, + List>? calculatedDataPoints, String name, double signalLineWidth, Color signalLineColor, @@ -828,10 +828,10 @@ class MacdIndicatorRenderParams extends IndicatorRenderParams { ); /// Gets the calculated Macd line values of the Macd indicator. - final List? macdLineValues; + final List>? macdLineValues; /// Gets the calculated histogram values of the Macd indicator. - final List? macdHistogramValues; + final List>? macdHistogramValues; } /// Holds the TechnicalIndicatorRenderDetails values @@ -908,7 +908,7 @@ class TrackballDetails { ]); /// It specifies the Cartesian chart point. - final CartesianChartPoint? point; + final CartesianChartPoint? point; /// It specifies the Cartesian series. final dynamic series; @@ -962,7 +962,7 @@ class TrackballGroupingModeInfo { ); /// Specifies the cartesian chart points. - final List points; + final List> points; /// Specifies the current point indices. final List currentPointIndices; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/chart_point.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/chart_point.dart index f0e03487c..055700244 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/chart_point.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/chart_point.dart @@ -412,7 +412,7 @@ class ChartPointInfo { dynamic series; /// Cartesian chart point. - CartesianChartPoint? chartPoint; + CartesianChartPoint? chartPoint; /// X position of the label. double? xPosition; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label.dart index bac3876e5..dca0bfeff 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label.dart @@ -37,7 +37,7 @@ base class CircularChartDataLabelPositioned Offset offset = Offset.zero; Size size = Size.zero; - CircularChartPoint? point; + CircularChartPoint? point; @override void applyParentData(RenderObject renderObject) { @@ -353,7 +353,7 @@ class _CircularDataLabelContainerState } class CircularDataLabelBoxParentData extends ChartElementParentData { - CircularChartPoint? point; + CircularChartPoint? point; } class CircularDataLabelStack extends ChartElementStack { @@ -476,7 +476,8 @@ class RenderCircularDataLabelStack extends RenderChartElementStack { if (selectedIndex == -1) { return; } - final CircularChartPoint point = labels!.elementAt(selectedIndex).point!; + final CircularChartPoint point = + labels!.elementAt(selectedIndex).point!; if (point.isVisible && point.trimmedText != null && point.text != point.trimmedText) { @@ -492,7 +493,8 @@ class RenderCircularDataLabelStack extends RenderChartElementStack { if (selectedIndex == -1) { return; } - final CircularChartPoint point = labels!.elementAt(selectedIndex).point!; + final CircularChartPoint point = + labels!.elementAt(selectedIndex).point!; if (point.isVisible && point.trimmedText != null && point.text != point.trimmedText) { @@ -502,7 +504,7 @@ class RenderCircularDataLabelStack extends RenderChartElementStack { } void _showTooltipForTrimmedDataLabel( - CircularChartPoint point, + CircularChartPoint point, int pointIndex, ) { final RenderCircularChartPlotArea plotArea = @@ -652,7 +654,7 @@ class RenderCircularDataLabelStack extends RenderChartElementStack { while (child != null) { final CircularDataLabelBoxParentData childParentData = child.parentData! as CircularDataLabelBoxParentData; - final CircularChartPoint point = childParentData.point!; + final CircularChartPoint point = childParentData.point!; if (point.isVisible) { if (point.connectorPath != null) { series!.drawConnectorLine( diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label_helper.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label_helper.dart index b2c3c4180..eb36d2ba5 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label_helper.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/circular_data_label_helper.dart @@ -19,10 +19,10 @@ import 'data_label.dart'; bool isIncreaseAngle = false; /// To store the points which render at left and positioned outside. -List leftPoints = []; +List> leftPoints = >[]; /// To store the points which render at right and positioned outside. -List rightPoints = []; +List> rightPoints = >[]; List renderDataLabelRegions = []; @@ -53,10 +53,10 @@ bool findingCollision(Rect rect, List regions, [Rect? pathRect]) { /// Method to get a text when the text overlap with another segment/slice. String segmentOverflowTrimmedText( - CircularSeriesRenderer seriesRenderer, + CircularSeriesRenderer seriesRenderer, String text, Size size, - CircularChartPoint point, + CircularChartPoint point, Rect labelRect, Offset centerLocation, Offset labelLocation, @@ -205,8 +205,8 @@ bool _isInsideSegment( /// Method for setting color to data label. Color findThemeColor( - CircularSeriesRenderer seriesRenderer, - CircularChartPoint point, + CircularSeriesRenderer seriesRenderer, + CircularChartPoint point, DataLabelSettings dataLabelSettings, ) { // TODO(Lavanya): Recheck here. @@ -223,10 +223,10 @@ Color findThemeColor( /// To render outside positioned data labels. void renderOutsideDataLabel( - CircularChartPoint point, + CircularChartPoint point, Size textSize, int pointIndex, - CircularSeriesRenderer seriesRenderer, + CircularSeriesRenderer seriesRenderer, int seriesIndex, TextStyle textStyle, List renderDataLabelRegions, @@ -401,10 +401,11 @@ Rect? getDataLabelRect( } void shiftCircularDataLabels( - CircularSeriesRenderer seriesRenderer, + CircularSeriesRenderer seriesRenderer, LinkedList labels, ) { - final List points = []; + final List> points = + >[]; if (seriesRenderer is RadialBarSeriesRenderer) { return; @@ -416,11 +417,11 @@ void shiftCircularDataLabels( final DataLabelSettings dataLabelSettings = seriesRenderer.dataLabelSettings; if (dataLabelSettings.builder == null) { - leftPoints = []; - rightPoints = []; + leftPoints = >[]; + rightPoints = >[]; for (int i = 0; i < labels.length; i++) { - final CircularChartPoint point = labels.elementAt(i).point!; + final CircularChartPoint point = labels.elementAt(i).point!; points.add(point); if (point.isVisible) { point.newAngle = point.midAngle; @@ -434,7 +435,7 @@ void shiftCircularDataLabels( } } leftPoints.sort( - (CircularChartPoint a, CircularChartPoint b) => + (CircularChartPoint a, CircularChartPoint b) => a.newAngle!.compareTo(b.newAngle!), ); if (leftPoints.isNotEmpty) { @@ -449,7 +450,7 @@ void shiftCircularDataLabels( for (int pointIndex = 0; pointIndex < labels.length; pointIndex++) { final CircularChartDataLabelPositioned dataLabelPositioned = labels .elementAt(pointIndex); - final CircularChartPoint point = dataLabelPositioned.point!; + final CircularChartPoint point = dataLabelPositioned.point!; if (point.isVisible) { final EdgeInsets margin = seriesRenderer.dataLabelSettings.margin; Rect rect = point.labelRect; @@ -584,9 +585,11 @@ void shiftCircularDataLabels( } /// Left side points alignment calculation. -void _arrangeLeftSidePoints(CircularSeriesRenderer seriesRenderer) { - CircularChartPoint previousPoint; - CircularChartPoint currentPoint; +void _arrangeLeftSidePoints( + CircularSeriesRenderer seriesRenderer, +) { + CircularChartPoint previousPoint; + CircularChartPoint currentPoint; bool angleChanged = false; bool startFresh = false; for (int i = 1; i < leftPoints.length; i++) { @@ -636,14 +639,16 @@ void _arrangeLeftSidePoints(CircularSeriesRenderer seriesRenderer) { } /// Right side points alignments calculation. -void _arrangeRightSidePoints(CircularSeriesRenderer seriesRenderer) { +void _arrangeRightSidePoints( + CircularSeriesRenderer seriesRenderer, +) { bool startFresh = false; bool angleChanged = false; num checkAngle; - CircularChartPoint currentPoint; - final CircularChartPoint? lastPoint = + CircularChartPoint currentPoint; + final CircularChartPoint? lastPoint = rightPoints.length > 1 ? rightPoints[rightPoints.length - 1] : null; - CircularChartPoint nextPoint; + CircularChartPoint nextPoint; if (lastPoint != null) { if (lastPoint.newAngle! > 360) { lastPoint.newAngle = lastPoint.newAngle! - 360; @@ -707,9 +712,9 @@ void _arrangeRightSidePoints(CircularSeriesRenderer seriesRenderer) { /// Decrease the angle of the label if it intersects with labels. void _decreaseAngle( - CircularChartPoint currentPoint, - CircularChartPoint previousPoint, - CircularSeriesRenderer seriesRenderer, + CircularChartPoint currentPoint, + CircularChartPoint previousPoint, + CircularSeriesRenderer seriesRenderer, bool isRightSide, ) { int count = 1; @@ -766,9 +771,9 @@ void _decreaseAngle( /// Increase the angle of the label if it intersects labels. void _increaseAngle( - CircularChartPoint currentPoint, - CircularChartPoint nextPoint, - CircularSeriesRenderer seriesRenderer, + CircularChartPoint currentPoint, + CircularChartPoint nextPoint, + CircularSeriesRenderer seriesRenderer, bool isRightSide, ) { int count = 1; @@ -816,9 +821,9 @@ void _increaseAngle( /// Change the label angle based on the given new angle. void _changeLabelAngle( - CircularChartPoint currentPoint, + CircularChartPoint currentPoint, num newAngle, - CircularSeriesRenderer seriesRenderer, + CircularSeriesRenderer seriesRenderer, ) { // TODO(Lavanya): Code cleanup for seriesRenderer field. @@ -883,8 +888,8 @@ bool isOverlap(Rect currentRect, Rect rect) { /// To find the current point overlapped with previous points. bool isOverlapWithPrevious( - CircularChartPoint currentPoint, - List points, + CircularChartPoint currentPoint, + List> points, int currentPointIndex, ) { for (int i = 0; i < currentPointIndex; i++) { @@ -899,8 +904,8 @@ bool isOverlapWithPrevious( /// To find the current point overlapped with next points. bool isOverlapWithNext( - CircularChartPoint point, - List points, + CircularChartPoint point, + List> points, int pointIndex, ) { for (int i = pointIndex; i < points.length; i++) { @@ -916,7 +921,10 @@ bool isOverlapWithNext( } /// Calculate the connected line path for shifted data label. -Offset getPerpendicularDistance(Offset startPoint, CircularChartPoint point) { +Offset getPerpendicularDistance( + Offset startPoint, + CircularChartPoint point, +) { Offset increasedLocation; const num add = 10; final num height = add + 10 * sin(point.midAngle! * pi / 360); @@ -979,22 +987,23 @@ String getTrimmedText( /// To shift the data label template in the circular chart. void shiftCircularDataLabelTemplate( - CircularSeriesRenderer seriesRenderer, + CircularSeriesRenderer seriesRenderer, List widgets, ) { if (seriesRenderer is RadialBarSeriesRenderer) { return; } - leftPoints = []; - rightPoints = []; - final List points = []; + leftPoints = >[]; + rightPoints = >[]; + final List> points = + >[]; final List renderDataLabelRegions = []; const int labelPadding = 2; final List templates = widgets; for (int i = 0; i < templates.length; i++) { - final CircularChartPoint point = templates[i].point!; + final CircularChartPoint point = templates[i].point!; if (point.newAngle == null && point.isVisible) { // For the data label position is inside. @@ -1045,7 +1054,7 @@ void shiftCircularDataLabelTemplate( } for (int i = 0; i < templates.length; i++) { - final CircularChartPoint point = templates[i].point!; + final CircularChartPoint point = templates[i].point!; points.add(point); if (point.isVisible) { point.newAngle = point.midAngle; @@ -1059,7 +1068,7 @@ void shiftCircularDataLabelTemplate( } } leftPoints.sort( - (CircularChartPoint a, CircularChartPoint b) => + (CircularChartPoint a, CircularChartPoint b) => a.newAngle!.compareTo(b.newAngle!), ); if (leftPoints.isNotEmpty) { @@ -1075,7 +1084,7 @@ void shiftCircularDataLabelTemplate( while (pointIndex < templates.length) { final CircularDataLabelBoxParentData child = templates[pointIndex]; - final CircularChartPoint point = child.point!; + final CircularChartPoint point = child.point!; if (point.isVisible) { final EdgeInsets margin = seriesRenderer.dataLabelSettings.margin; final Rect rect = point.labelRect; @@ -1153,8 +1162,8 @@ bool isTemplateWithinBounds(Rect bounds, Rect templateRect) => // Calculate the data label rectangle value when the data label template // position is outside and it consider the outer radius. void _renderOutsideDataLabelTemplate( - CircularChartPoint point, - CircularSeriesRenderer seriesRenderer, + CircularChartPoint point, + CircularSeriesRenderer seriesRenderer, Size templateSize, List renderDataLabelRegion, ) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/core_legend.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/core_legend.dart index 4999969fe..57edbfb17 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/core_legend.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/core_legend.dart @@ -242,7 +242,7 @@ abstract class LegendItem { VoidCallback? onToggled; /// Specifies the series associated with the legend item. - final ChartSeriesRenderer? series; + final ChartSeriesRenderer? series; /// Specifies the index of the series associated with the legend item. final int seriesIndex; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/data_label.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/data_label.dart index 8a2039591..fa0004e4b 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/data_label.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/data_label.dart @@ -186,7 +186,7 @@ class DataLabelSettings { /// ); /// } /// ``` - final ChartWidgetBuilder? builder; + final ChartWidgetBuilder? builder; /// Color of the data label. /// @@ -1386,7 +1386,9 @@ class RenderCartesianDataLabelStack extends RenderChartElementStack { // To handle multiple series data collision, we need to check the data label // collision for all the series after data label layout. @override - void handleDataLabelCollision(CartesianSeriesRenderer series) { + void handleDataLabelCollision( + CartesianSeriesRenderer series, + ) { series.parent?.visitChildren((RenderObject child) { if (child is CartesianSeriesRenderer && child.controller.isVisible && diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/element_widget.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/element_widget.dart index d56557ac9..7f6affc23 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/element_widget.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/element_widget.dart @@ -72,7 +72,9 @@ class RenderChartFadeTransition extends RenderAnimatedOpacity { (child as RenderChartElementStack?)?.handleMultiSeriesDataLabelCollisions(); } - void handleDataLabelCollision(CartesianSeriesRenderer series) { + void handleDataLabelCollision( + CartesianSeriesRenderer series, + ) { (child as RenderChartElementStack?)?.handleDataLabelCollision(series); } } @@ -160,7 +162,9 @@ class RenderChartElementLayoutBuilder extends RenderBox ?.handleMultiSeriesDataLabelCollisions(); } - void handleDataLabelCollision(CartesianSeriesRenderer series) { + void handleDataLabelCollision( + CartesianSeriesRenderer series, + ) { (child as RenderChartFadeTransition?)?.handleDataLabelCollision(series); } @@ -223,7 +227,9 @@ class RenderChartElementStack extends RenderBox // To handle multiple series data collision, we need to check the data label // collision for all the series after data label layout. - void handleDataLabelCollision(CartesianSeriesRenderer series) {} + void handleDataLabelCollision( + CartesianSeriesRenderer series, + ) {} } abstract class CustomConstrainedLayoutBuilder< diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/common/legend.dart b/packages/syncfusion_flutter_charts/lib/src/charts/common/legend.dart index 73c8f4fc0..119419ecd 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/common/legend.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/common/legend.dart @@ -448,7 +448,7 @@ class Legend { /// ); /// } /// ``` - final LegendItemBuilder? legendItemBuilder; + final LegendItemBuilder? legendItemBuilder; /// Overflow legend items. /// diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/funnel_chart.dart b/packages/syncfusion_flutter_charts/lib/src/charts/funnel_chart.dart index ca47ace23..4ac25c5ac 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/funnel_chart.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/funnel_chart.dart @@ -129,7 +129,7 @@ class SfFunnelChart extends StatefulWidget { /// ); /// } /// ``` - final FunnelSeries series; + final FunnelSeries series; /// Margin for chart. /// diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/accumulation_distribution_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/accumulation_distribution_indicator.dart index 6919cc45c..109e0217f 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/accumulation_distribution_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/accumulation_distribution_indicator.dart @@ -142,15 +142,15 @@ class ADIndicatorWidget extends IndicatorWidget { /// Create the ADIndicatorRenderer renderer. @override - ADIndicatorRenderer createRenderer() { + ADIndicatorRenderer createRenderer() { return ADIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final ADIndicatorRenderer renderer = + final ADIndicatorRenderer renderer = super.createRenderObject(context) as ADIndicatorRenderer; - final AccumulationDistributionIndicator adi = + final AccumulationDistributionIndicator adi = indicator as AccumulationDistributionIndicator; renderer @@ -164,10 +164,10 @@ class ADIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - ADIndicatorRenderer renderObject, + ADIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final AccumulationDistributionIndicator adi = + final AccumulationDistributionIndicator adi = indicator as AccumulationDistributionIndicator; renderObject diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/atr_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/atr_indicator.dart index 6e3597d97..413604940 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/atr_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/atr_indicator.dart @@ -156,15 +156,15 @@ class AtrIndicatorWidget extends IndicatorWidget { /// Create the ADIndicatorRenderer renderer. @override - AtrIndicatorRenderer createRenderer() { + AtrIndicatorRenderer createRenderer() { return AtrIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final AtrIndicatorRenderer renderer = + final AtrIndicatorRenderer renderer = super.createRenderObject(context) as AtrIndicatorRenderer; - final AtrIndicator atr = indicator as AtrIndicator; + final AtrIndicator atr = indicator as AtrIndicator; renderer ..highValueMapper = atr.highValueMapper @@ -177,10 +177,10 @@ class AtrIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - AtrIndicatorRenderer renderObject, + AtrIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final AtrIndicator atr = indicator as AtrIndicator; + final AtrIndicator atr = indicator as AtrIndicator; renderObject ..highValueMapper = atr.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/bollinger_bands_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/bollinger_bands_indicator.dart index 1396cd86c..75d12aeec 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/bollinger_bands_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/bollinger_bands_indicator.dart @@ -273,15 +273,15 @@ class BollingerIndicatorWidget extends IndicatorWidget { // Create the BollingerIndicatorRenderer renderer. @override - BollingerIndicatorRenderer createRenderer() { + BollingerIndicatorRenderer createRenderer() { return BollingerIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final BollingerIndicatorRenderer renderer = + final BollingerIndicatorRenderer renderer = super.createRenderObject(context) as BollingerIndicatorRenderer; - final BollingerBandIndicator bollinger = + final BollingerBandIndicator bollinger = indicator as BollingerBandIndicator; renderer @@ -299,10 +299,10 @@ class BollingerIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - BollingerIndicatorRenderer renderObject, + BollingerIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final BollingerBandIndicator bollinger = + final BollingerBandIndicator bollinger = indicator as BollingerBandIndicator; renderObject diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/ema_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/ema_indicator.dart index 50a7588a5..e9401cfa5 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/ema_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/ema_indicator.dart @@ -192,15 +192,15 @@ class EmaIndicatorWidget extends IndicatorWidget { // Create the EmaIndicatorRenderer renderer. @override - EmaIndicatorRenderer createRenderer() { + EmaIndicatorRenderer createRenderer() { return EmaIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final EmaIndicatorRenderer renderer = + final EmaIndicatorRenderer renderer = super.createRenderObject(context) as EmaIndicatorRenderer; - final EmaIndicator ema = indicator as EmaIndicator; + final EmaIndicator ema = indicator as EmaIndicator; renderer ..highValueMapper = ema.highValueMapper @@ -215,10 +215,10 @@ class EmaIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - EmaIndicatorRenderer renderObject, + EmaIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final EmaIndicator ema = indicator as EmaIndicator; + final EmaIndicator ema = indicator as EmaIndicator; renderObject ..highValueMapper = ema.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/macd_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/macd_indicator.dart index cfebd9868..7ef04731e 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/macd_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/macd_indicator.dart @@ -329,15 +329,15 @@ class MacdIndicatorWidget extends IndicatorWidget { // Create the MacdIndicatorRenderer renderer. @override - MacdIndicatorRenderer createRenderer() { + MacdIndicatorRenderer createRenderer() { return MacdIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final MacdIndicatorRenderer renderer = + final MacdIndicatorRenderer renderer = super.createRenderObject(context) as MacdIndicatorRenderer; - final MacdIndicator macd = indicator as MacdIndicator; + final MacdIndicator macd = indicator as MacdIndicator; renderer ..closeValueMapper = macd.closeValueMapper @@ -355,10 +355,10 @@ class MacdIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - MacdIndicatorRenderer renderObject, + MacdIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final MacdIndicator macd = indicator as MacdIndicator; + final MacdIndicator macd = indicator as MacdIndicator; renderObject ..closeValueMapper = macd.closeValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/momentum_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/momentum_indicator.dart index 8e4404915..f06a618c7 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/momentum_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/momentum_indicator.dart @@ -214,15 +214,16 @@ class MomentumIndicatorWidget extends IndicatorWidget { // Create the MomentumIndicatorRenderer renderer. @override - MomentumIndicatorRenderer createRenderer() { + MomentumIndicatorRenderer createRenderer() { return MomentumIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final MomentumIndicatorRenderer renderer = + final MomentumIndicatorRenderer renderer = super.createRenderObject(context) as MomentumIndicatorRenderer; - final MomentumIndicator momentum = indicator as MomentumIndicator; + final MomentumIndicator momentum = + indicator as MomentumIndicator; renderer ..highValueMapper = momentum.highValueMapper @@ -239,10 +240,11 @@ class MomentumIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - MomentumIndicatorRenderer renderObject, + MomentumIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final MomentumIndicator momentum = indicator as MomentumIndicator; + final MomentumIndicator momentum = + indicator as MomentumIndicator; renderObject ..highValueMapper = momentum.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/roc_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/roc_indicator.dart index 15ed26f5b..d916c393f 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/roc_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/roc_indicator.dart @@ -340,15 +340,15 @@ class RocIndicatorWidget extends IndicatorWidget { // Create the RocIndicatorRenderer renderer. @override - RocIndicatorRenderer createRenderer() { + RocIndicatorRenderer createRenderer() { return RocIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final RocIndicatorRenderer renderer = + final RocIndicatorRenderer renderer = super.createRenderObject(context) as RocIndicatorRenderer; - final RocIndicator roc = indicator as RocIndicator; + final RocIndicator roc = indicator as RocIndicator; renderer ..highValueMapper = roc.highValueMapper ..lowValueMapper = roc.lowValueMapper @@ -364,10 +364,10 @@ class RocIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - RocIndicatorRenderer renderObject, + RocIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final RocIndicator roc = indicator as RocIndicator; + final RocIndicator roc = indicator as RocIndicator; renderObject ..highValueMapper = roc.highValueMapper ..lowValueMapper = roc.lowValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/rsi_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/rsi_indicator.dart index 1e7758ad7..ab900fe24 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/rsi_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/rsi_indicator.dart @@ -341,15 +341,15 @@ class RsiIndicatorWidget extends IndicatorWidget { // Create the RsiIndicatorRenderer renderer. @override - RsiIndicatorRenderer createRenderer() { + RsiIndicatorRenderer createRenderer() { return RsiIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final RsiIndicatorRenderer renderer = + final RsiIndicatorRenderer renderer = super.createRenderObject(context) as RsiIndicatorRenderer; - final RsiIndicator rsi = indicator as RsiIndicator; + final RsiIndicator rsi = indicator as RsiIndicator; renderer ..highValueMapper = rsi.highValueMapper @@ -370,10 +370,10 @@ class RsiIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - RsiIndicatorRenderer renderObject, + RsiIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final RsiIndicator rsi = indicator as RsiIndicator; + final RsiIndicator rsi = indicator as RsiIndicator; renderObject ..highValueMapper = rsi.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/sma_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/sma_indicator.dart index 1c0543255..34cb43996 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/sma_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/sma_indicator.dart @@ -190,15 +190,15 @@ class SmaIndicatorWidget extends IndicatorWidget { // Create the SmaIndicatorRenderer renderer. @override - SmaIndicatorRenderer createRenderer() { + SmaIndicatorRenderer createRenderer() { return SmaIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final SmaIndicatorRenderer renderer = + final SmaIndicatorRenderer renderer = super.createRenderObject(context) as SmaIndicatorRenderer; - final SmaIndicator sma = indicator as SmaIndicator; + final SmaIndicator sma = indicator as SmaIndicator; renderer ..highValueMapper = sma.highValueMapper @@ -214,10 +214,10 @@ class SmaIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - SmaIndicatorRenderer renderObject, + SmaIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final SmaIndicator sma = indicator as SmaIndicator; + final SmaIndicator sma = indicator as SmaIndicator; renderObject ..highValueMapper = sma.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/stochastic_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/stochastic_indicator.dart index c876c987b..bc0673b53 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/stochastic_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/stochastic_indicator.dart @@ -449,15 +449,16 @@ class StochasticIndicatorWidget extends IndicatorWidget { // Create the StochasticIndicatorRenderer renderer. @override - StochasticIndicatorRenderer createRenderer() { + StochasticIndicatorRenderer createRenderer() { return StochasticIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final StochasticIndicatorRenderer renderer = + final StochasticIndicatorRenderer renderer = super.createRenderObject(context) as StochasticIndicatorRenderer; - final StochasticIndicator stochastic = indicator as StochasticIndicator; + final StochasticIndicator stochastic = + indicator as StochasticIndicator; renderer ..highValueMapper = stochastic.highValueMapper @@ -482,10 +483,11 @@ class StochasticIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - StochasticIndicatorRenderer renderObject, + StochasticIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final StochasticIndicator stochastic = indicator as StochasticIndicator; + final StochasticIndicator stochastic = + indicator as StochasticIndicator; renderObject ..highValueMapper = stochastic.highValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/technical_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/technical_indicator.dart index 965602699..ec2b9b7fb 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/technical_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/technical_indicator.dart @@ -579,18 +579,18 @@ abstract class IndicatorWidget extends LeafRenderObjectWidget { final TickerProvider vsync; final bool isTransposed; - final TechnicalIndicator indicator; + final TechnicalIndicator indicator; final int index; final ChartLegendTapCallback? onLegendTapped; final ChartLegendRenderCallback? onLegendItemRender; @protected @factory - IndicatorRenderer createRenderer(); + IndicatorRenderer createRenderer(); @override RenderObject createRenderObject(BuildContext context) { - final IndicatorRenderer renderer = createRenderer(); + final IndicatorRenderer renderer = createRenderer(); return renderer ..vsync = vsync ..isTransposed = isTransposed @@ -618,7 +618,7 @@ abstract class IndicatorWidget extends LeafRenderObjectWidget { @override void updateRenderObject( BuildContext context, - IndicatorRenderer renderObject, + IndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); renderObject diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/tma_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/tma_indicator.dart index 8fb289059..ee63f9c8a 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/tma_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/tma_indicator.dart @@ -190,15 +190,15 @@ class TmaIndicatorWidget extends IndicatorWidget { // Create the TmaIndicatorRenderer renderer. @override - TmaIndicatorRenderer createRenderer() { + TmaIndicatorRenderer createRenderer() { return TmaIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final TmaIndicatorRenderer renderer = + final TmaIndicatorRenderer renderer = super.createRenderObject(context) as TmaIndicatorRenderer; - final TmaIndicator tma = indicator as TmaIndicator; + final TmaIndicator tma = indicator as TmaIndicator; renderer ..highValueMapper = tma.highValueMapper @@ -213,10 +213,10 @@ class TmaIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - TmaIndicatorRenderer renderObject, + TmaIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final TmaIndicator tma = indicator as TmaIndicator; + final TmaIndicator tma = indicator as TmaIndicator; renderObject ..highValueMapper = tma.highValueMapper @@ -362,7 +362,7 @@ class TmaIndicatorRenderer extends IndicatorRenderer { yMax = yMaximum.isInfinite ? yMax : yMaximum; } - List _splice(List list, int index, num? elements) { + List _splice(List list, int index, num? elements) { if (elements != null) { list.insertAll(index, [elements]); } diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/wma_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/wma_indicator.dart index 905427f60..834ddc582 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/indicators/wma_indicator.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/indicators/wma_indicator.dart @@ -323,15 +323,15 @@ class WmaIndicatorWidget extends IndicatorWidget { // Create the WmaIndicatorRenderer renderer. @override - WmaIndicatorRenderer createRenderer() { + WmaIndicatorRenderer createRenderer() { return WmaIndicatorRenderer(); } @override RenderObject createRenderObject(BuildContext context) { - final WmaIndicatorRenderer renderer = + final WmaIndicatorRenderer renderer = super.createRenderObject(context) as WmaIndicatorRenderer; - final WmaIndicator wma = indicator as WmaIndicator; + final WmaIndicator wma = indicator as WmaIndicator; return renderer ..highValueMapper = wma.highValueMapper ..lowValueMapper = wma.lowValueMapper @@ -344,10 +344,10 @@ class WmaIndicatorWidget extends IndicatorWidget { @override void updateRenderObject( BuildContext context, - WmaIndicatorRenderer renderObject, + WmaIndicatorRenderer renderObject, ) { super.updateRenderObject(context, renderObject); - final WmaIndicator wma = indicator as WmaIndicator; + final WmaIndicator wma = indicator as WmaIndicator; renderObject ..highValueMapper = wma.highValueMapper ..lowValueMapper = wma.lowValueMapper diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/behavior.dart b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/behavior.dart index be62bd8d7..a7dc4099a 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/behavior.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/behavior.dart @@ -511,7 +511,8 @@ class RenderBehaviorArea extends RenderBox if (tooltipBehavior != null && tooltipBehavior!.shared && info is! TrendlineTooltipInfo) { - final ChartTooltipInfo chartTooltipInfo = info as ChartTooltipInfo; + final ChartTooltipInfo chartTooltipInfo = + info as ChartTooltipInfo; tooltipBehavior!.showByIndex( chartTooltipInfo.seriesIndex, chartTooltipInfo.pointIndex, diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/selection.dart b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/selection.dart index 799b4680b..1824dc9c5 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/selection.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/selection.dart @@ -408,7 +408,7 @@ class SelectionBehavior extends ChartBehavior { return; } - ChartSeriesRenderer? seriesRenderer; + ChartSeriesRenderer? seriesRenderer; RenderBox? child = plotArea.firstChild; while (child != null) { final ContainerParentDataMixin childParentData = @@ -434,7 +434,7 @@ class SelectionBehavior extends ChartBehavior { } /// Provides the list of selected point indices for given series. - List getSelectedDataPoints(CartesianSeries series) { + List getSelectedDataPoints(CartesianSeries series) { RenderChartPlotArea? plotArea; if (parentBox is RenderChartPlotArea) { plotArea = parentBox! as RenderChartPlotArea; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/tooltip.dart b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/tooltip.dart index da34c316f..aaeed29d3 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/interactions/tooltip.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/interactions/tooltip.dart @@ -356,7 +356,7 @@ class TooltipBehavior extends ChartBehavior { /// ); /// } ///``` - final ChartWidgetBuilder? builder; + final ChartWidgetBuilder? builder; /// Color of the tooltip shadow. /// @@ -602,9 +602,10 @@ class TooltipBehavior extends ChartBehavior { String? header; num? baseXValue; Offset? position; - ChartTooltipInfo? tooltipInfo; + ChartTooltipInfo? tooltipInfo; final List markerColors = []; - final List tooltipInfoList = []; + final List> tooltipInfoList = + >[]; final RenderBox? firstChild = parent.plotArea?.firstChild; RenderBox? series = firstChild; while (series != null && series.parentData != null) { @@ -614,7 +615,7 @@ class TooltipBehavior extends ChartBehavior { if (series is CartesianSeriesRenderer && series.isVisible() && series.enableTooltip) { - final ChartTooltipInfo? info = + final ChartTooltipInfo? info = series.tooltipInfoFromPointIndex(pointIndex) as ChartTooltipInfo?; if (info != null && series.index == seriesIndex) { @@ -633,7 +634,7 @@ class TooltipBehavior extends ChartBehavior { if (child is ChartSeriesRenderer && child.isVisible() && child.enableTooltip) { - final ChartTooltipInfo? info = + final ChartTooltipInfo? info = child.tooltipInfoFromPointIndex(pointIndex) as ChartTooltipInfo?; if (info != null && info.text != null) { @@ -658,7 +659,7 @@ class TooltipBehavior extends ChartBehavior { child.dataCount - 1, ); if (binaryIndex >= 0) { - final ChartTooltipInfo? info = + final ChartTooltipInfo? info = child.tooltipInfoFromPointIndex(binaryIndex) as ChartTooltipInfo?; if (info != null && info.text != null) { @@ -672,7 +673,7 @@ class TooltipBehavior extends ChartBehavior { } else { final int index = child.xValues.indexOf(baseXValue); if (index >= 0) { - final ChartTooltipInfo? info = + final ChartTooltipInfo? info = child.tooltipInfoFromPointIndex(index) as ChartTooltipInfo?; if (info != null && info.text != null) { @@ -686,7 +687,7 @@ class TooltipBehavior extends ChartBehavior { child = childParentData.nextSibling; } - for (final ChartTooltipInfo info in tooltipInfoList) { + for (final ChartTooltipInfo info in tooltipInfoList) { if (text == null) { text = '${info.text}'; } else { @@ -803,13 +804,13 @@ class ChartTooltipInfo extends TooltipInfo { point: point ?? this.point, series: series ?? this.series, renderer: renderer ?? this.renderer, - header: name ?? this.header, + header: name ?? header, seriesIndex: seriesIndex ?? this.seriesIndex, segmentIndex: segmentIndex ?? this.segmentIndex, pointIndex: pointIndex ?? this.pointIndex, markerColors: markerColors ?? this.markerColors, markerBorderColor: markerBorderColor ?? this.markerBorderColor, - markerType: markerShape ?? this.markerType, + markerType: markerShape ?? markerType, ); } diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/pyramid_chart.dart b/packages/syncfusion_flutter_charts/lib/src/charts/pyramid_chart.dart index a2db855a8..588524da8 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/pyramid_chart.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/pyramid_chart.dart @@ -124,7 +124,7 @@ class SfPyramidChart extends StatefulWidget { /// ); /// } /// ``` - final PyramidSeries series; + final PyramidSeries series; /// Customizes the chart. /// diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/area_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/area_series.dart index cb8e6023b..1eb48974d 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/area_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/area_series.dart @@ -326,6 +326,9 @@ class AreaSegment extends ChartSegment { _highPoints.clear(); _lowPoints.clear(); + bottom = + series.xAxis!.crossesAt ?? max(series.yAxis!.visibleRange!.minimum, 0); + _fillPath.reset(); _strokePath.reset(); diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/bar_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/bar_series.dart index 88bd4616f..f76501157 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/bar_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/bar_series.dart @@ -459,6 +459,7 @@ class BarSegment extends ChartSegment with BarSeriesTrackerMixin { } points.clear(); + bottom = series.bottom; final PointToPixelCallback transformX = series.pointToPixelX; final PointToPixelCallback transformY = series.pointToPixelY; final num left = x + series.sbsInfo.minimum; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/chart_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/chart_series.dart index 1fce875d5..be8862de1 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/chart_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/chart_series.dart @@ -2890,7 +2890,10 @@ class ChartSeriesController { return CartesianChartPoint(x: rawX, xValue: xValue, y: yValue); } - D? _rawXValue(CartesianSeriesRenderer seriesRenderer, num xValue) { + D? _rawXValue( + CartesianSeriesRenderer seriesRenderer, + num xValue, + ) { final int index = seriesRenderer.xValues.indexOf(xValue); final RenderChartAxis xAxis = seriesRenderer.xAxis!; @@ -4199,7 +4202,7 @@ abstract class CartesianSeriesRenderer extends ChartSeriesRenderer @override int viewportIndex(int index, [List? visibleIndexes]) { - return super.viewportIndex(index, visibleIndexes ?? this._viewPortIndexes); + return super.viewportIndex(index, visibleIndexes ?? _viewPortIndexes); } List contains(Offset position) { @@ -5914,7 +5917,7 @@ mixin BarSeriesTrackerMixin on ChartSegment { BorderRadius borderRadius, double trackPadding, double trackBorderWidth, - CartesianSeriesRenderer series, + CartesianSeriesRenderer series, ) { final PointToPixelCallback transformX = series.pointToPixelX; final PointToPixelCallback transformY = series.pointToPixelY; @@ -8289,7 +8292,7 @@ abstract class CircularSeries extends ChartSeries { /// final Shader pointShader; ///} ///``` - final ChartShaderMapper? pointShaderMapper; + final ChartShaderMapper? pointShaderMapper; /// Maps the field name, which will be considered for calculating the radius /// of all the data points. @@ -8855,7 +8858,7 @@ class CircularSeriesController { /// ) /// ``` - ChartPoint pixelToPoint(Offset position) { + ChartPoint pixelToPoint(Offset position) { int pointIndex = -1; for (int i = 0; i < seriesRenderer.segments.length; i++) { final ChartSegment segment = seriesRenderer.segments[i]; @@ -8886,7 +8889,7 @@ abstract class CircularSeriesRenderer extends ChartSeriesRenderer ChartValueMapper? yValueMapper; - ChartShaderMapper? pointShaderMapper; + ChartShaderMapper? pointShaderMapper; ChartValueMapper? pointRadiusMapper; @@ -9487,7 +9490,7 @@ abstract class CircularSeriesRenderer extends ChartSeriesRenderer parent!.themeData!.textTheme.bodySmall! ..merge(chartThemeData!.dataLabelTextStyle) ..merge(dataLabelSettings.textStyle); - final CircularChartPoint point = current.point!; + final CircularChartPoint point = current.point!; if (point.isExplode) { point.center = calculateExplodingCenter( point.midAngle!, @@ -9743,7 +9746,7 @@ abstract class CircularSeriesRenderer extends ChartSeriesRenderer segment, ); TextStyle effectiveTextStyle = saturatedTextStyle(surfaceColor, style); - final CircularChartPoint point = dataLabelPositioned.point!; + final CircularChartPoint point = dataLabelPositioned.point!; if (!point.isVisible || !segments[index].isVisible || point.text == '') { return; } diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/column_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/column_series.dart index a2147cef8..16bd28ffd 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/column_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/column_series.dart @@ -444,6 +444,7 @@ class ColumnSegment extends ChartSegment with BarSeriesTrackerMixin { } points.clear(); + bottom = series.bottom; final PointToPixelCallback transformX = series.pointToPixelX; final PointToPixelCallback transformY = series.pointToPixelY; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/doughnut_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/doughnut_series.dart index 7e17542a1..5d527f5a5 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/doughnut_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/doughnut_series.dart @@ -440,7 +440,7 @@ class DoughnutSeriesRenderer extends CircularSeriesRenderer { } /// To find data label position. - void _findDataLabelPosition(CircularChartPoint point) { + void _findDataLabelPosition(CircularChartPoint point) { point.midAngle = point.midAngle! > 360 ? point.midAngle! - 360 : point.midAngle!; point.dataLabelPosition = diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/fast_line_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/fast_line_series.dart index 5182822ec..72a54e2e1 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/fast_line_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/fast_line_series.dart @@ -104,7 +104,8 @@ class FastLineSeriesRenderer extends XyDataSeriesRenderer @override int dataPointIndex(Offset position, ChartSegment segment) { - final FastLineSegment fastLineSegment = segment as FastLineSegment; + final FastLineSegment fastLineSegment = + segment as FastLineSegment; final int nearestPointIndex = fastLineSegment._findNearestPoint( fastLineSegment.points, position, diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/funnel_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/funnel_series.dart index 06000c32f..a7e5df38c 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/funnel_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/funnel_series.dart @@ -1785,7 +1785,7 @@ class FunnelSeriesController { /// ) /// ); /// ``` - PointInfo pixelToPoint(Offset position) { + PointInfo pixelToPoint(Offset position) { int pointIndex = -1; final List segments = seriesRenderer.segments; for (int i = 0; i < segments.length; i++) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/pie_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/pie_series.dart index f643f6388..7d18c2981 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/pie_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/pie_series.dart @@ -444,7 +444,7 @@ class PieSeriesRenderer extends CircularSeriesRenderer { } /// To find data label position. - void _findDataLabelPosition(CircularChartPoint point) { + void _findDataLabelPosition(CircularChartPoint point) { point.midAngle = point.midAngle! > 360 ? point.midAngle! - 360 : point.midAngle!; point.dataLabelPosition = diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/pyramid_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/pyramid_series.dart index ac9cd17bb..884e62da5 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/pyramid_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/pyramid_series.dart @@ -1738,7 +1738,7 @@ class PyramidSeriesController { /// ), /// ); /// ``` - PointInfo pixelToPoint(Offset position) { + PointInfo pixelToPoint(Offset position) { int pointIndex = -1; final List segments = seriesRenderer.segments; for (int i = 0; i < segments.length; i++) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/radial_bar_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/radial_bar_series.dart index 56dedd9e5..8870d2f0d 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/radial_bar_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/radial_bar_series.dart @@ -407,7 +407,7 @@ class RadialBarSeriesRenderer extends CircularSeriesRenderer { super.handleLegendItemTapped(item, isToggled); // Resets `_isLegendToggled` to `true` to handle legend inner and outer radius animations. if (item is CircularLegendItem && item.pointIndex != -1) { - final RadialBarSegment segment = + final RadialBarSegment segment = segmentAt(item.pointIndex) as RadialBarSegment; segment._isLegendToggled = true; } @@ -480,7 +480,7 @@ class RadialBarSeriesRenderer extends CircularSeriesRenderer { ..outerRadius = segment._outerRadius ..center = center ..fill = palette[current.dataPointIndex % palette.length]; - final CircularChartPoint point = current.point!; + final CircularChartPoint point = current.point!; Offset labelLocation = calculateOffset( point.startAngle!, @@ -525,7 +525,7 @@ class RadialBarSeriesRenderer extends CircularSeriesRenderer { .merge(parent!.chartThemeData!.dataLabelTextStyle) .merge(dataLabelSettings.textStyle); - final CircularChartPoint point = dataLabelPositioned.point!; + final CircularChartPoint point = dataLabelPositioned.point!; if (!point.isVisible || !segments[index].isVisible) { return; } diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/range_area_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/range_area_series.dart index 8ee2451cb..c232d0301 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/range_area_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/range_area_series.dart @@ -161,7 +161,8 @@ class RangeAreaSeriesRenderer extends RangeSeriesRendererBase @override int segmentPointIndex(Offset position, ChartSegment segment) { - final RangeAreaSegment rangeAreaSegment = segment as RangeAreaSegment; + final RangeAreaSegment rangeAreaSegment = + segment as RangeAreaSegment; final int index = _computePointIndex(rangeAreaSegment._lowPoints, position); if (index != -1) { return index; diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/spline_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/spline_series.dart index 7d8692982..fb42008da 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/spline_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/spline_series.dart @@ -1410,6 +1410,9 @@ class SplineAreaSegment extends ChartSegment { _startControlHighPoints.clear(); _endControlHighPoints.clear(); + bottom = + series.xAxis!.crossesAt ?? max(series.yAxis!.visibleRange!.minimum, 0); + _fillPath.reset(); _strokePath.reset(); if (_xValues.isEmpty || _yValues.isEmpty) { @@ -2189,7 +2192,7 @@ class SplineRangeAreaSeriesRenderer extends RangeSeriesRendererBase @override int segmentPointIndex(Offset position, ChartSegment segment) { - final SplineRangeAreaSegment splineRangeAreaSegment = + final SplineRangeAreaSegment splineRangeAreaSegment = segment as SplineRangeAreaSegment; final int index = _computePointIndex( splineRangeAreaSegment._lowPoints, diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/series/step_area_series.dart b/packages/syncfusion_flutter_charts/lib/src/charts/series/step_area_series.dart index 5f4a51da5..4c8590d92 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/series/step_area_series.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/series/step_area_series.dart @@ -302,6 +302,9 @@ class StepAreaSegment extends ChartSegment { _highPoints.clear(); _lowPoints.clear(); + _bottom = + series.xAxis!.crossesAt ?? max(series.yAxis!.visibleRange!.minimum, 0); + _fillPath.reset(); _strokePath.reset(); if (_xValues.isEmpty || _yValues.isEmpty) { diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/trendline/trendline.dart b/packages/syncfusion_flutter_charts/lib/src/charts/trendline/trendline.dart index b7f0e51ee..0d7a23b08 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/trendline/trendline.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/trendline/trendline.dart @@ -564,7 +564,7 @@ class RenderTrendlineStack extends RenderBox TrendlineRenderer, TrendlineParentData > { - CartesianSeriesRenderer? renderer; + CartesianSeriesRenderer? renderer; bool get _isTooltipEnabled => renderer != null && @@ -658,7 +658,7 @@ class RenderTrendlineStack extends RenderBox } } - void performUpdate(CartesianSeriesRenderer renderer) { + void performUpdate(CartesianSeriesRenderer renderer) { this.renderer = renderer; TrendlineRenderer? child = firstChild; while (child != null) { @@ -1053,7 +1053,7 @@ class TrendlineRenderer extends RenderBox { DoubleRange xRange = DoubleRange(double.infinity, double.negativeInfinity); DoubleRange yRange = DoubleRange(double.infinity, double.negativeInfinity); - CartesianSeriesRenderer? series; + CartesianSeriesRenderer? series; final List _markers = []; final List _points = []; // The _points list updates with calculatedDataPoints values when the @@ -1146,7 +1146,7 @@ class TrendlineRenderer extends RenderBox { return null; } - CartesianChartPoint _chartPoint(int pointIndex) { + CartesianChartPoint _chartPoint(int pointIndex) { final num xValue = trendlineXValues[pointIndex]; return CartesianChartPoint( x: _xRawValue(xValue), diff --git a/packages/syncfusion_flutter_charts/lib/src/charts/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/charts/utils/helper.dart index ecf8bd71e..daf3346cd 100644 --- a/packages/syncfusion_flutter_charts/lib/src/charts/utils/helper.dart +++ b/packages/syncfusion_flutter_charts/lib/src/charts/utils/helper.dart @@ -32,7 +32,7 @@ import '../utils/enum.dart'; import 'constants.dart'; // A circular array for dash offsets and lengths. -class _IntervalList { +class _IntervalList { _IntervalList(this.dashArray); final List dashArray; @@ -309,14 +309,14 @@ void drawDashes( paint.isAntiAlias = false; canvas.drawPath( - _dashPath(path, dashArray: _IntervalList(dashArray!))!, + _dashPath(path, dashArray: _IntervalList(dashArray!))!, paint, ); } } /// To calculate dash array path for series. -Path? _dashPath(Path? source, {required _IntervalList dashArray}) { +Path? _dashPath(Path? source, {required _IntervalList dashArray}) { if (source == null) { return null; } @@ -2283,7 +2283,7 @@ Widget buildLegendItem( core.LegendItem legendItem, Legend legend, ) { - ChartPoint point; + ChartPoint point; if (legendItem.series != null) { final int length = legendItem.series!.chartPoints.length; final int pointIndex = legendItem.pointIndex; @@ -2451,7 +2451,7 @@ String _labelValue( NumberFormat? numberFormat, String? labelFormat, ) { - final List pieces = value.toString().split('.'); + final List pieces = value.toString().split('.'); if (pieces.length > 1) { value = double.parse(value.toStringAsFixed(showDigits)); final String decimals = pieces[1]; @@ -2476,7 +2476,7 @@ String _labelValue( } RRect performLegendToggleAnimation( - SbsSeriesMixin series, + SbsSeriesMixin series, RRect segmentRect, RRect oldSegmentRect, BorderRadius borderRadius, @@ -2496,9 +2496,9 @@ RRect performLegendToggleAnimation( } final RenderCartesianChartPlotArea plotArea = series.parent!; - final CartesianSeriesRenderer firstSeries = + final CartesianSeriesRenderer firstSeries = plotArea.firstChild! as CartesianSeriesRenderer; - final CartesianSeriesRenderer lastSeries = + final CartesianSeriesRenderer lastSeries = plotArea.lastChild! as CartesianSeriesRenderer; final bool isSingleBarSeries = _isSingleBarSeries(plotArea); @@ -2563,7 +2563,7 @@ RRect performLegendToggleAnimation( } RRect performTransposedLegendToggleAnimation( - SbsSeriesMixin series, + SbsSeriesMixin series, RRect segmentRect, RRect oldSegmentRect, bool oldSeriesVisible, @@ -2571,9 +2571,9 @@ RRect performTransposedLegendToggleAnimation( BorderRadius borderRadius, ) { final RenderCartesianChartPlotArea plotArea = series.parent!; - final CartesianSeriesRenderer firstSeries = + final CartesianSeriesRenderer firstSeries = plotArea.firstChild! as CartesianSeriesRenderer; - final CartesianSeriesRenderer lastSeries = + final CartesianSeriesRenderer lastSeries = plotArea.lastChild! as CartesianSeriesRenderer; final bool isSingleBarSeries = _isSingleBarSeries(plotArea); diff --git a/packages/syncfusion_flutter_charts/lib/src/sparkline/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/sparkline/utils/helper.dart index c8bb9a389..6658346a6 100644 --- a/packages/syncfusion_flutter_charts/lib/src/sparkline/utils/helper.dart +++ b/packages/syncfusion_flutter_charts/lib/src/sparkline/utils/helper.dart @@ -93,7 +93,7 @@ void drawDashedPath( /// To calculate dash array path for series. Path? _dashPath( Path? source, { - @required DashArrayIntervalList? dashArray, + required DashArrayIntervalList? dashArray, }) { if (source == null) { return null; diff --git a/packages/syncfusion_flutter_charts/pubspec.yaml b/packages/syncfusion_flutter_charts/pubspec.yaml index 76aeaea9e..21bc133b3 100644 --- a/packages/syncfusion_flutter_charts/pubspec.yaml +++ b/packages/syncfusion_flutter_charts/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_charts description: A Flutter Charts library which includes data visualization widgets such as cartesian and circular charts, to create real-time, interactive, high-performance, animated charts. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_charts screenshots: @@ -19,14 +19,12 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" dependencies: flutter: sdk: flutter intl: '>=0.18.1 <0.21.0' - vector_math: ">=2.1.0 <=3.0.0" + vector_math: ">=2.2.0 <=3.0.0" syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_chat/CHANGELOG.md b/packages/syncfusion_flutter_chat/CHANGELOG.md index 8b74e6e73..c672376a8 100644 --- a/packages/syncfusion_flutter_chat/CHANGELOG.md +++ b/packages/syncfusion_flutter_chat/CHANGELOG.md @@ -2,6 +2,18 @@ * No changes. +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter chat and AI assistView widgets has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter chat and AI assistView widgets has been updated to Flutter SDK 3.35. + ## [30.1.37] - 06/25/2025 **General** diff --git a/packages/syncfusion_flutter_chat/example/android/build.gradle.kts b/packages/syncfusion_flutter_chat/example/android/build.gradle.kts index 89176ef44..dbee657bb 100644 --- a/packages/syncfusion_flutter_chat/example/android/build.gradle.kts +++ b/packages/syncfusion_flutter_chat/example/android/build.gradle.kts @@ -5,7 +5,10 @@ allprojects { } } -val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { diff --git a/packages/syncfusion_flutter_chat/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_chat/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0..ac3b47926 100644 --- a/packages/syncfusion_flutter_chat/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_chat/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_chat/example/android/settings.gradle.kts b/packages/syncfusion_flutter_chat/example/android/settings.gradle.kts index a439442c2..c571d1e63 100644 --- a/packages/syncfusion_flutter_chat/example/android/settings.gradle.kts +++ b/packages/syncfusion_flutter_chat/example/android/settings.gradle.kts @@ -1,11 +1,12 @@ pluginManagement { - val flutterSdkPath = run { - val properties = java.util.Properties() - file("local.properties").inputStream().use { properties.load(it) } - val flutterSdkPath = properties.getProperty("flutter.sdk") - require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } - flutterSdkPath - } + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") @@ -18,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/syncfusion_flutter_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_chat/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_chat/pubspec.yaml b/packages/syncfusion_flutter_chat/pubspec.yaml index a819e66a0..eb912f2ce 100644 --- a/packages/syncfusion_flutter_chat/pubspec.yaml +++ b/packages/syncfusion_flutter_chat/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_chat description: The Flutter Chat package is a UI library designed for creating customizable chat applications, both standard and AI-driven, using Flutter. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_chat screenshots: @@ -11,7 +11,7 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" flutter: uses-material-design: true @@ -22,5 +22,3 @@ dependencies: intl: '>=0.18.1 <0.21.0' syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_core/CHANGELOG.md b/packages/syncfusion_flutter_core/CHANGELOG.md index 23f076215..873a5b120 100644 --- a/packages/syncfusion_flutter_core/CHANGELOG.md +++ b/packages/syncfusion_flutter_core/CHANGELOG.md @@ -1,6 +1,18 @@ ## Unreleased -* No changes. +* No changes. + +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of all our Flutter widgets has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of all our Flutter widgets has been updated to Flutter SDK 3.35. ## [30.1.38] - 02/07/2025 diff --git a/packages/syncfusion_flutter_core/example/android/build.gradle.kts b/packages/syncfusion_flutter_core/example/android/build.gradle.kts index 89176ef44..dbee657bb 100644 --- a/packages/syncfusion_flutter_core/example/android/build.gradle.kts +++ b/packages/syncfusion_flutter_core/example/android/build.gradle.kts @@ -5,7 +5,10 @@ allprojects { } } -val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { diff --git a/packages/syncfusion_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0..ac3b47926 100644 --- a/packages/syncfusion_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_core/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_core/example/android/settings.gradle.kts b/packages/syncfusion_flutter_core/example/android/settings.gradle.kts index a439442c2..c571d1e63 100644 --- a/packages/syncfusion_flutter_core/example/android/settings.gradle.kts +++ b/packages/syncfusion_flutter_core/example/android/settings.gradle.kts @@ -1,11 +1,12 @@ pluginManagement { - val flutterSdkPath = run { - val properties = java.util.Properties() - file("local.properties").inputStream().use { properties.load(it) } - val flutterSdkPath = properties.getProperty("flutter.sdk") - require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } - flutterSdkPath - } + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") @@ -18,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/syncfusion_flutter_core/lib/src/legend/legend.dart b/packages/syncfusion_flutter_core/lib/src/legend/legend.dart index 588ff4fc9..33b1fa7ab 100644 --- a/packages/syncfusion_flutter_core/lib/src/legend/legend.dart +++ b/packages/syncfusion_flutter_core/lib/src/legend/legend.dart @@ -2165,10 +2165,13 @@ class __SolidBarLegendItemState extends State<_SolidBarLegendItem> { if (widget.direction == Axis.horizontal) { matrix4 = - Matrix4.identity()..translate( + Matrix4.identity()..translateByDouble( widget.pointerController!.position!.dx * widget.segmentSize!.width - (widget.pointerSize!.width / 2), + 0.0, + 0.0, + 1.0, ); if (_textDirection == TextDirection.rtl) { matrix4.invert(); @@ -2177,11 +2180,13 @@ class __SolidBarLegendItemState extends State<_SolidBarLegendItem> { } else { current = RotatedBox(quarterTurns: 3, child: current); matrix4 = - Matrix4.identity()..translate( + Matrix4.identity()..translateByDouble( 0.0, widget.pointerController!.position!.dy * widget.segmentSize!.width - (widget.pointerSize!.width / 2), + 0.0, + 1.0, ); current = Transform(transform: matrix4, child: current); } @@ -2752,9 +2757,12 @@ class _GradientBarLegendState extends State<_GradientBarLegend> { if (_direction == Axis.horizontal) { matrix4 = - Matrix4.identity()..translate( + Matrix4.identity()..translateByDouble( widget.pointerController!.position!.dx * _segmentSize.width - (widget.pointerSize!.width / 2), + 0.0, + 0.0, + 1.0, ); if (_isRTL) { matrix4.invert(); @@ -2763,10 +2771,12 @@ class _GradientBarLegendState extends State<_GradientBarLegend> { } else { current = RotatedBox(quarterTurns: 3, child: current); matrix4 = - Matrix4.identity()..translate( + Matrix4.identity()..translateByDouble( 0.0, widget.pointerController!.position!.dy * _segmentSize.height - (widget.pointerSize!.width / 2), + 0.0, + 1.0, ); current = Transform(transform: matrix4, child: current); } diff --git a/packages/syncfusion_flutter_core/lib/src/license.dart b/packages/syncfusion_flutter_core/lib/src/license.dart deleted file mode 100644 index 6b92aa725..000000000 --- a/packages/syncfusion_flutter_core/lib/src/license.dart +++ /dev/null @@ -1,19 +0,0 @@ -part of core; - -//ignore: avoid_classes_with_only_static_members -/// The class for license validation. -@Deprecated('License registration is not required now') -class SyncfusionLicense { - /// - /// Method to validate the license and display popup. - /// - /// context - // ignore: missing_return - static void validateLicense(BuildContext context) {} - - /// - /// Method to register the license key. - /// - /// licenseKey - static void registerLicense(String licenseKey) {} -} diff --git a/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart b/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart index fa251b8ab..d062cd794 100644 --- a/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart +++ b/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart @@ -316,6 +316,10 @@ abstract class SfLocalizations { /// `Select All` option in the popup menu. String get selectAllDataGridFilteringLabel; + /// The label displayed in the filter popup calendar header in SfDataGrid + /// for the `Select a date` option. + String get selectADateDataGridFilteringLabel; + /// The label that is displayed in the filter view in SfDataGrid for /// `Sort and Filter` option in the popup menu. String get sortAndFilterDataGridFilteringLabel; @@ -736,6 +740,9 @@ class _DefaultLocalizations implements SfLocalizations { @override String get selectAllDataGridFilteringLabel => 'Select All'; + @override + String get selectADateDataGridFilteringLabel => 'Select a date'; + @override String get sortAndFilterDataGridFilteringLabel => 'Sort and Filter'; diff --git a/packages/syncfusion_flutter_core/lib/src/slider_controller.dart b/packages/syncfusion_flutter_core/lib/src/slider_controller.dart index 83ae2ea33..9e104e037 100644 --- a/packages/syncfusion_flutter_core/lib/src/slider_controller.dart +++ b/packages/syncfusion_flutter_core/lib/src/slider_controller.dart @@ -189,7 +189,7 @@ class RangeController extends DiagnosticableTree with ChangeNotifier { /// corresponding to this value. /// /// [start] and [end] - RangeController({@required dynamic start, @required dynamic end}) + RangeController({required dynamic start, required dynamic end}) : assert(start != null), assert(end != null), _previousStart = start, diff --git a/packages/syncfusion_flutter_core/lib/src/widgets/interactive_scroll_viewer.dart b/packages/syncfusion_flutter_core/lib/src/widgets/interactive_scroll_viewer.dart index 5d0c04b91..a138b4e52 100644 --- a/packages/syncfusion_flutter_core/lib/src/widgets/interactive_scroll_viewer.dart +++ b/packages/syncfusion_flutter_core/lib/src/widgets/interactive_scroll_viewer.dart @@ -189,9 +189,11 @@ class InteractiveScrollViewerState extends State { Offset.zero, ); widget.transformationController?.value = - widget.transformationController!.value.clone()..translate( + widget.transformationController!.value.clone()..translateByDouble( previousOffset.dx - offset.dx, previousOffset.dy - offset.dy, + 0.0, + 1.0, ); } } @@ -234,9 +236,10 @@ class InteractiveScrollViewerState extends State { final Offset previousOffset = widget.transformationController!.toScene( Offset.zero, ); + final double tx = scale / zoomLevel; widget.transformationController?.value = widget.transformationController!.value.clone() - ..scale(scale / zoomLevel, scale / zoomLevel); + ..scaleByDouble(tx, tx, tx, 1.0); scrollTo(previousOffset); } } diff --git a/packages/syncfusion_flutter_core/pubspec.yaml b/packages/syncfusion_flutter_core/pubspec.yaml index 8320268e7..a19827dcd 100644 --- a/packages/syncfusion_flutter_core/pubspec.yaml +++ b/packages/syncfusion_flutter_core/pubspec.yaml @@ -1,14 +1,14 @@ name: syncfusion_flutter_core description: Syncfusion Flutter Core is a dependent package for all the Syncfusion Flutter widgets. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_core environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" dependencies: flutter: sdk: flutter - vector_math: ">=2.1.0 <=4.0.0" + vector_math: ">=2.2.0 <=4.0.0" diff --git a/packages/syncfusion_flutter_datagrid/CHANGELOG.md b/packages/syncfusion_flutter_datagrid/CHANGELOG.md index fd6b53b19..6d6c731cb 100644 --- a/packages/syncfusion_flutter_datagrid/CHANGELOG.md +++ b/packages/syncfusion_flutter_datagrid/CHANGELOG.md @@ -1,14 +1,32 @@ ## Unreleased +**Bugs** + +* The `Clear Filter` label is now correctly localized for the Spanish locale. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter DataGrid widget has been updated to Flutter SDK 3.35.0. + +## [30.1.38] - 07/02/2025 + +**Bugs** + +* The `SfDataGrid` now properly handles the tap action on the Filter icon. + +## [30.1.37] - 06/25/2025 + **General** * The compatible version of our Flutter DataGrid widget has been updated to Flutter SDK 3.32.0. **Features** -- Provided support to customize the default appearance of checkbox and advanced filtering popup menus. -- Provided support to obtain the row details by row index using a helper method. -- Provided built-in support to customize the background color of the caption summary row. +* Provided support to customize the default appearance of checkbox and advanced filtering popup menus. +* Provided support to obtain the row details by row index using a helper method. +* Provided built-in support to customize the background color of the caption summary row. ## [29.1.39] - 04/22/2025 diff --git a/packages/syncfusion_flutter_gauges/example/android/app/build.gradle b/packages/syncfusion_flutter_datagrid/example/android/app/build.gradle.kts similarity index 69% rename from packages/syncfusion_flutter_gauges/example/android/app/build.gradle rename to packages/syncfusion_flutter_datagrid/example/android/app/build.gradle.kts index b5511a9a3..ac2e54de1 100644 --- a/packages/syncfusion_flutter_gauges/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_datagrid/example/android/app/build.gradle.kts @@ -1,27 +1,27 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { - namespace = "com.example.example" + namespace = "com.example.datagrid_example" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.example" + applicationId = "com.example.datagrid_example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_datagrid/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_datagrid/example/android/app/src/main/AndroidManifest.xml index 74a78b939..32321703f 100644 --- a/packages/syncfusion_flutter_datagrid/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_datagrid/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ ("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_datagrid/example/android/gradle.properties b/packages/syncfusion_flutter_datagrid/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_datagrid/example/android/gradle.properties +++ b/packages/syncfusion_flutter_datagrid/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_datagrid/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_datagrid/example/android/gradle/wrapper/gradle-wrapper.properties index e1ca574ef..ac3b47926 100644 --- a/packages/syncfusion_flutter_datagrid/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_datagrid/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_datagrid/example/android/settings.gradle b/packages/syncfusion_flutter_datagrid/example/android/settings.gradle deleted file mode 100644 index 536165d35..000000000 --- a/packages/syncfusion_flutter_datagrid/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_datagrid/example/android/settings.gradle.kts b/packages/syncfusion_flutter_datagrid/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_datagrid/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_datagrid/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_datagrid/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_datagrid/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_datagrid/example/pubspec.yaml b/packages/syncfusion_flutter_datagrid/example/pubspec.yaml index ad116ff64..e6cfc967c 100644 --- a/packages/syncfusion_flutter_datagrid/example/pubspec.yaml +++ b/packages/syncfusion_flutter_datagrid/example/pubspec.yaml @@ -1,21 +1,19 @@ name: datagrid_example -description: This project demonstrates how to use Syncfusion Flutter DataGrid widget?. +description: This project demonstrates how to use Syncfusion Flutter DataGrid widget. version: 1.0.0+1 environment: sdk: ^3.7.0 +flutter: + uses-material-design: true + dependencies: flutter: sdk: flutter syncfusion_flutter_datagrid: path: ../ - cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter - -flutter: - uses-material-design: true - \ No newline at end of file diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart index 427c18445..5ff537ea7 100644 --- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart +++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart @@ -1527,6 +1527,12 @@ class ColumnResizeController { /// [SystemMouseCursors.resizeColumn] or not. bool canSwitchResizeColumnCursor = false; + /// Notifies listeners when [canSwitchResizeColumnCursor] and [isResizeIndicatorVisible] changes. + /// This is used to trigger rebuilds in UI elements (like feedback widgets) + final ValueNotifier canSwitchResizeColumnCursorNotifier = ValueNotifier( + true, + ); + /// Determines whether the resizing indicator is enable or not. bool isResizeIndicatorVisible = false; @@ -2141,6 +2147,10 @@ class ColumnResizeController { if (resizingLine != null && isResizeIndicatorVisible) { _isLongPressEnabled = true; + if (dataGridConfiguration.columnDragAndDropController + .canAllowColumnDragAndDrop()) { + canSwitchResizeColumnCursorNotifier.value = true; + } // Rebuild to enable the resizing indicator. _rebuild(); } @@ -2165,10 +2175,8 @@ class ColumnResizeController { if (canSwitchResizeColumnCursor && dataGridConfiguration.columnDragAndDropController .canAllowColumnDragAndDrop()) { - notifyDataGridPropertyChangeListeners( - dataGridConfiguration.source, - propertyName: 'columnDragAndDrop', - ); + // Notify the feedback widget to initiate a rebuild. + canSwitchResizeColumnCursorNotifier.value = canSwitchResizeColumnCursor; } } @@ -3839,6 +3847,12 @@ class ColumnDragAndDropController { void onPointerUp(PointerUpEvent event) { final DataGridConfiguration dataGridConfiguration = dataGridStateDetails(); disableScrolling = true; + + // Returns early as drag-and-drop was not in progress when the pointer was released. + if (!allowColumnDrag && dragColumnStartIndex == null) { + return; + } + if (allowColumnDrag && scrollOrigin != null && event.position.dy >= scrollOrigin!.dy) { diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart index 46ee012b7..c4a44d909 100644 --- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart +++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart @@ -5192,7 +5192,10 @@ class DataGridController extends DataGridSourceChangeNotifier { /// Determines the row type based on the given row index. /// Returns a [RowType] that represents different types of rows such as /// header, footer, summary, or dataRows. - RowType? _getRowType(dataGridConfiguration, rowIndex) { + RowType? _getRowType( + DataGridConfiguration dataGridConfiguration, + int rowIndex, + ) { if (rowIndex < dataGridConfiguration.stackedHeaderRows.length) { return RowType.stackedHeaderRow; } diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart index d3c30502d..ec2c2dbf6 100644 --- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart +++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart @@ -69,7 +69,7 @@ class _GridCellState extends State { TapDownDetails details, bool isSecondaryTapDown, ) async { - _kind = details.kind!; + _kind = details.kind ?? PointerDeviceKind.touch; final DataCellBase dataCell = widget.dataCell; final DataGridConfiguration dataGridConfiguration = dataGridStateDetails(); @@ -329,7 +329,7 @@ class _GridHeaderCellState extends State { } void _handleOnTapDown(TapDownDetails details) { - _kind = details.kind!; + _kind = details.kind ?? PointerDeviceKind.touch; final DataGridConfiguration dataGridConfiguration = dataGridStateDetails(); // Clear editing when tap on the header cell _clearEditing(dataGridConfiguration); @@ -374,6 +374,8 @@ class _GridHeaderCellState extends State { Widget _wrapInsideContainer() { final DataGridConfiguration dataGridConfiguration = dataGridStateDetails(); final GridColumn? column = widget.dataCell.gridColumn; + final bool isWindowsPlatform = + dataGridConfiguration.columnDragAndDropController.isWindowsPlatform!; Widget checkHeaderCellConstraints(Widget child) { return LayoutBuilder( @@ -383,16 +385,6 @@ class _GridHeaderCellState extends State { ); } - _ensureSortIconVisibility(column!, dataGridConfiguration); - - Widget child = _wrapInsideCellContainer( - dataGridConfiguration: dataGridConfiguration, - child: checkHeaderCellConstraints(widget.child), - dataCell: widget.dataCell, - key: widget.key!, - backgroundColor: widget.backgroundColor, - ); - Widget getFeedbackWidget(DataGridConfiguration configuration) { return dataGridConfiguration.columnDragFeedbackBuilder != null ? dataGridConfiguration.columnDragFeedbackBuilder!( @@ -420,42 +412,60 @@ class _GridHeaderCellState extends State { ); } - Widget buildDraggableHeaderCell(Widget child) { - final DataGridConfiguration configuration = dataGridStateDetails(); - final bool isWindowsPlatform = - configuration.columnDragAndDropController.isWindowsPlatform!; - return Draggable( - onDragStarted: () { - if (widget.dataCell.cellType != CellType.indentCell) { - configuration.columnDragAndDropController.onPointerDown( - widget.dataCell, - ); - } - }, - ignoringFeedbackPointer: isWindowsPlatform, - feedback: MouseRegion( - cursor: - isWindowsPlatform - ? MouseCursor.defer - : (dataGridConfiguration.isMacPlatform && !kIsWeb) - ? SystemMouseCursors.grabbing - : SystemMouseCursors.move, - child: getFeedbackWidget(configuration), - ), - child: child, - ); - } + _ensureSortIconVisibility(column!, dataGridConfiguration); - if (dataGridConfiguration.columnDragAndDropController - .canAllowColumnDragAndDrop() && - dataGridConfiguration - .columnDragAndDropController - .canWrapDraggableView && - !dataGridConfiguration - .columnResizeController - .canSwitchResizeColumnCursor) { - child = buildDraggableHeaderCell(child); - } + bool canEnableDraggableView() { + return dataGridConfiguration.columnDragAndDropController + .canAllowColumnDragAndDrop() && + dataGridConfiguration + .columnDragAndDropController + .canWrapDraggableView && + !dataGridConfiguration + .columnResizeController + .canSwitchResizeColumnCursor && + !dataGridConfiguration + .columnResizeController + .isResizeIndicatorVisible; + } + + final Widget child = Draggable( + onDragStarted: () { + if (widget.dataCell.cellType != CellType.indentCell && + canEnableDraggableView()) { + dataGridConfiguration.columnDragAndDropController.onPointerDown( + widget.dataCell, + ); + } + }, + ignoringFeedbackPointer: isWindowsPlatform, + feedback: ValueListenableBuilder( + valueListenable: + dataGridConfiguration + .columnResizeController + .canSwitchResizeColumnCursorNotifier, + builder: (context, isResizeCursorActive, _) { + return MouseRegion( + cursor: + isWindowsPlatform + ? MouseCursor.defer + : (dataGridConfiguration.isMacPlatform && !kIsWeb) + ? SystemMouseCursors.grabbing + : SystemMouseCursors.move, + child: + isResizeCursorActive + ? const SizedBox.shrink() + : getFeedbackWidget(dataGridConfiguration), + ); + }, + ), + child: _wrapInsideCellContainer( + dataGridConfiguration: dataGridConfiguration, + child: checkHeaderCellConstraints(widget.child), + dataCell: widget.dataCell, + key: widget.key!, + backgroundColor: widget.backgroundColor, + ), + ); return Container( key: widget.key, @@ -1225,11 +1235,15 @@ class _FilterPopupState extends State<_FilterPopup> { late DataGridFilterHelper filterHelper; late DataGridThemeHelper dataGridThemeHelper; + + late ValueNotifier _filterPopupValueNotifier; + @override void initState() { super.initState(); _initializeFilterProperties(); filterHelper.isFilterPopupMenuShowing = true; + _filterPopupValueNotifier = ValueNotifier(null); } @override @@ -1260,6 +1274,7 @@ class _FilterPopupState extends State<_FilterPopup> { @override void dispose() { + _filterPopupValueNotifier.dispose(); filterHelper.isFilterPopupMenuShowing = false; super.dispose(); } @@ -1318,58 +1333,67 @@ class _FilterPopupState extends State<_FilterPopup> { PreferredSize buildAppBar(BuildContext context) { return PreferredSize( preferredSize: const Size.fromHeight(52.0), - child: AppBar( - elevation: 0.0, - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container( - height: 1.0, - color: - dataGridThemeHelper.appBarBottomBorderColor ?? - dataGridThemeHelper.filterPopupBorderColor, - ), - ), - backgroundColor: dataGridThemeHelper.filterPopupBackgroundColor, - leading: IconButton( - key: const ValueKey('datagrid_filtering_cancelFilter_icon'), - onPressed: closePage, - icon: Icon( - Icons.close, - size: 22.0, - color: - dataGridThemeHelper.cancelFilteringLabelButtonColor ?? - dataGridThemeHelper.filterPopupIconColor, - ), - ), - centerTitle: false, - titleSpacing: 0, - title: Text( - widget - .dataGridConfiguration - .localizations - .sortAndFilterDataGridFilteringLabel, - style: filterHelper.textStyle, - ), - actions: [ - IconButton( - key: const ValueKey('datagrid_filtering_applyFilter_icon'), - onPressed: canDisableOkButton() ? null : onHandleOkButtonTap, - icon: Icon( - Icons.check, - size: 22.0, - color: - canDisableOkButton() - ? dataGridThemeHelper - .okFilteringLabelDisabledButtonColor ?? - widget - .dataGridConfiguration - .colorScheme! - .onSurface[97] - : dataGridThemeHelper.okFilteringLabelButtonColor ?? - filterHelper.primaryColor, + child: ValueListenableBuilder( + valueListenable: _filterPopupValueNotifier, + builder: (context, value, child) { + return AppBar( + elevation: 0.0, + bottom: PreferredSize( + preferredSize: const Size.fromHeight(1.0), + child: Container( + height: 1.0, + color: + dataGridThemeHelper.appBarBottomBorderColor ?? + dataGridThemeHelper.filterPopupBorderColor, + ), ), - ), - ], + backgroundColor: dataGridThemeHelper.filterPopupBackgroundColor, + leading: IconButton( + key: const ValueKey( + 'datagrid_filtering_cancelFilter_icon', + ), + onPressed: closePage, + icon: Icon( + Icons.close, + size: 22.0, + color: + dataGridThemeHelper.cancelFilteringLabelButtonColor ?? + dataGridThemeHelper.filterPopupIconColor, + ), + ), + centerTitle: false, + titleSpacing: 0, + title: Text( + widget + .dataGridConfiguration + .localizations + .sortAndFilterDataGridFilteringLabel, + style: filterHelper.textStyle, + ), + actions: [ + IconButton( + key: const ValueKey( + 'datagrid_filtering_applyFilter_icon', + ), + onPressed: canDisableOkButton() ? null : onHandleOkButtonTap, + icon: Icon( + Icons.check, + size: 22.0, + color: + canDisableOkButton() + ? dataGridThemeHelper + .okFilteringLabelDisabledButtonColor ?? + widget + .dataGridConfiguration + .colorScheme! + .onSurface[97] + : dataGridThemeHelper.okFilteringLabelButtonColor ?? + filterHelper.primaryColor, + ), + ), + ], + ); + }, ), ); } @@ -1422,281 +1446,301 @@ class _FilterPopupState extends State<_FilterPopup> { setState: setState, dataGridConfiguration: widget.dataGridConfiguration, advanceFilterTopPadding: advanceFilterTopPadding, + filterPopupValueNotifier: _filterPopupValueNotifier, ); - return SingleChildScrollView( - key: const ValueKey('datagrid_filtering_scrollView'), - child: Container( - width: isMobile ? null : 274.0, - color: dataGridThemeHelper.filterPopupBackgroundColor, - child: Column( - children: [ - if (canShowSortingOptions) - _FilterPopupMenuTile( - style: - isSortAscendingEnabled - ? filterHelper.textStyle - : filterHelper.disableTextStyle, - height: filterHelper.tileHeight, - prefix: Icon( - const IconData( - 0xe700, - fontFamily: 'FilterIcon', - fontPackage: 'syncfusion_flutter_datagrid', - ), - color: - isSortAscendingEnabled - ? iconColor - : dataGridThemeHelper.filterPopupDisabledIconColor, - size: filterHelper.textStyle.fontSize! + 10, - ), - prefixPadding: EdgeInsets.only( - left: 4.0, - right: filterHelper.textStyle.fontSize!, - bottom: - filterHelper.textStyle.fontSize! > 14 - ? filterHelper.textStyle.fontSize! - 14 - : 0, - ), - onTap: - isSortAscendingEnabled ? onHandleSortAscendingTap : null, - child: Text( - grid_helper.getSortButtonText( - localizations, - true, - filterType, - ), - overflow: TextOverflow.ellipsis, - ), - ), - if (canShowSortingOptions) - _FilterPopupMenuTile( - style: - isSortDescendingEnabled - ? filterHelper.textStyle - : filterHelper.disableTextStyle, - height: filterHelper.tileHeight, - prefix: Icon( - const IconData( - 0xe701, - fontFamily: 'FilterIcon', - fontPackage: 'syncfusion_flutter_datagrid', - ), - color: - isSortDescendingEnabled - ? iconColor - : dataGridThemeHelper.filterPopupDisabledIconColor, - size: filterHelper.textStyle.fontSize! + 10, - ), - prefixPadding: EdgeInsets.only( - left: 4.0, - right: filterHelper.textStyle.fontSize!, - bottom: - filterHelper.textStyle.fontSize! > 14 - ? filterHelper.textStyle.fontSize! - 14 - : 0, - ), - onTap: - isSortDescendingEnabled - ? onHandleSortDescendingTap - : null, - child: Text( - grid_helper.getSortButtonText( - localizations, - false, - filterType, - ), - overflow: TextOverflow.ellipsis, - ), - ), - if (canShowSortingOptions) - Divider( - indent: 8.0, - endIndent: 8.0, - color: dataGridThemeHelper.filterPopupTopDividerColor, - ), - if (canShowClearFilterOption) - _FilterPopupMenuTile( - style: - isClearFilterEnabled - ? filterHelper.textStyle - : filterHelper.disableTextStyle, - height: filterHelper.tileHeight, - prefix: Icon( - const IconData( - 0xe703, - fontFamily: 'FilterIcon', - fontPackage: 'syncfusion_flutter_datagrid', + return ValueListenableBuilder( + valueListenable: _filterPopupValueNotifier, + builder: (context, value, child) { + return SingleChildScrollView( + key: const ValueKey('datagrid_filtering_scrollView'), + child: Container( + width: isMobile ? null : 274.0, + color: dataGridThemeHelper.filterPopupBackgroundColor, + child: Column( + children: [ + if (canShowSortingOptions) + _FilterPopupMenuTile( + style: + isSortAscendingEnabled + ? filterHelper.textStyle + : filterHelper.disableTextStyle, + height: filterHelper.tileHeight, + prefix: Icon( + const IconData( + 0xe700, + fontFamily: 'FilterIcon', + fontPackage: 'syncfusion_flutter_datagrid', + ), + color: + isSortAscendingEnabled + ? iconColor + : dataGridThemeHelper + .filterPopupDisabledIconColor, + size: filterHelper.textStyle.fontSize! + 10, + ), + prefixPadding: EdgeInsets.only( + left: 4.0, + right: filterHelper.textStyle.fontSize!, + bottom: + filterHelper.textStyle.fontSize! > 14 + ? filterHelper.textStyle.fontSize! - 14 + : 0, + ), + onTap: + isSortAscendingEnabled + ? onHandleSortAscendingTap + : null, + child: Text( + grid_helper.getSortButtonText( + localizations, + true, + filterType, + ), + overflow: TextOverflow.ellipsis, + ), ), - size: filterHelper.textStyle.fontSize! + 8, - color: - isClearFilterEnabled - ? iconColor - : dataGridThemeHelper.filterPopupDisabledIconColor, - ), - prefixPadding: EdgeInsets.only( - left: 4.0, - right: filterHelper.textStyle.fontSize!, - bottom: - filterHelper.textStyle.fontSize! > 14 - ? filterHelper.textStyle.fontSize! - 14 - : 0, - ), - onTap: isClearFilterEnabled ? onHandleClearFilterTap : null, - child: Text( - getClearFilterText(localizations, showColumnName), - overflow: TextOverflow.ellipsis, - ), - ), - if (isAdvancedFilterEnabled) - _AdvancedFilterPopupMenu( - setState: setState, - dataGridConfiguration: widget.dataGridConfiguration, - advanceFilterTopPadding: advanceFilterTopPadding, - ), - if (isBothFilterEnabled) - _FilterPopupMenuTile( - style: filterHelper.textStyle, - height: filterHelper.tileHeight, - onTap: onHandleExpansionTileTap, - prefix: Icon( - filterHelper.getFilterForm(widget.column) == - FilteredFrom.advancedFilter - ? const IconData( - 0xe704, + if (canShowSortingOptions) + _FilterPopupMenuTile( + style: + isSortDescendingEnabled + ? filterHelper.textStyle + : filterHelper.disableTextStyle, + height: filterHelper.tileHeight, + prefix: Icon( + const IconData( + 0xe701, fontFamily: 'FilterIcon', fontPackage: 'syncfusion_flutter_datagrid', - ) - : const IconData( - 0xe702, + ), + color: + isSortDescendingEnabled + ? iconColor + : dataGridThemeHelper + .filterPopupDisabledIconColor, + size: filterHelper.textStyle.fontSize! + 10, + ), + prefixPadding: EdgeInsets.only( + left: 4.0, + right: filterHelper.textStyle.fontSize!, + bottom: + filterHelper.textStyle.fontSize! > 14 + ? filterHelper.textStyle.fontSize! - 14 + : 0, + ), + onTap: + isSortDescendingEnabled + ? onHandleSortDescendingTap + : null, + child: Text( + grid_helper.getSortButtonText( + localizations, + false, + filterType, + ), + overflow: TextOverflow.ellipsis, + ), + ), + if (canShowSortingOptions) + Divider( + indent: 8.0, + endIndent: 8.0, + color: dataGridThemeHelper.filterPopupTopDividerColor, + ), + if (canShowClearFilterOption) + _FilterPopupMenuTile( + style: + isClearFilterEnabled + ? filterHelper.textStyle + : filterHelper.disableTextStyle, + height: filterHelper.tileHeight, + prefix: Icon( + const IconData( + 0xe703, fontFamily: 'FilterIcon', fontPackage: 'syncfusion_flutter_datagrid', ), - size: filterHelper.textStyle.fontSize! + 6, - color: iconColor, - ), - suffix: Icon( - isAdvancedFilter - ? Icons.keyboard_arrow_down - : Icons.keyboard_arrow_right, - size: filterHelper.textStyle.fontSize! + 6, - color: - dataGridThemeHelper - .advancedFilterPopupDropdownIconColor ?? - iconColor, - ), - prefixPadding: EdgeInsets.only( - left: 4.0, - right: filterHelper.textStyle.fontSize!, - bottom: - filterHelper.textStyle.fontSize! > 14 - ? filterHelper.textStyle.fontSize! - 14 - : 0, - ), - child: Text( - grid_helper.getFilterTileText(localizations, filterType), - overflow: TextOverflow.ellipsis, - ), - ), - if (isCheckboxFilterEnabled || isBothFilterEnabled) - Visibility( - visible: isAdvancedFilter, - replacement: _CheckboxFilterMenu( - column: widget.column, - setState: setState, - viewSize: viewSize, - dataGridConfiguration: widget.dataGridConfiguration, - ), - child: - isMobile - ? ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewSize!.height, - ), - child: advanceFilterPopupMenu, - ) - : advanceFilterPopupMenu, - ), - if (!isMobile) - Divider( - height: 10, - color: dataGridThemeHelper.filterPopupBottomDividerColor, - ), - if (!isMobile) - Padding( - padding: const EdgeInsets.symmetric(vertical: 6.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SizedBox( - width: 120.0, - height: filterHelper.tileHeight - 8, - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: WidgetStateProperty.resolveWith< - Color? - >((Set states) { - // Issue: - // FLUT-7487-The buttons UX in the filter popup menu is not very intuitive when using Material 3 design. - // - // Fix: - // There is an issue with the button user experience (UX) in the filter popup menu, - // which is caused by the default background color of the "ElevatedButton" widget - // being set to the surface color in the Material 3 design. To address this issue, - // we set the background color of the button to the primary color if it is not disabled. - // This means that the default value is ignored, and the given color is used instead. - if (states.contains(WidgetState.disabled)) { - return dataGridThemeHelper - .okFilteringLabelDisabledButtonColor; - } else { - return dataGridThemeHelper - .okFilteringLabelButtonColor ?? - filterHelper.primaryColor; - } - }), - ), - onPressed: - canDisableOkButton() ? null : onHandleOkButtonTap, - child: Text( - localizations.okDataGridFilteringLabel, - style: TextStyle( - color: - dataGridThemeHelper.okFilteringLabelColor ?? - const Color(0xFFFFFFFF), - fontSize: filterHelper.textStyle.fontSize, - fontFamily: filterHelper.textStyle.fontFamily, + size: filterHelper.textStyle.fontSize! + 8, + color: + isClearFilterEnabled + ? iconColor + : dataGridThemeHelper + .filterPopupDisabledIconColor, + ), + prefixPadding: EdgeInsets.only( + left: 4.0, + right: filterHelper.textStyle.fontSize!, + bottom: + filterHelper.textStyle.fontSize! > 14 + ? filterHelper.textStyle.fontSize! - 14 + : 0, + ), + onTap: + isClearFilterEnabled ? onHandleClearFilterTap : null, + child: Text( + getClearFilterText(localizations, showColumnName), + overflow: TextOverflow.ellipsis, + ), + ), + if (isAdvancedFilterEnabled) + _AdvancedFilterPopupMenu( + setState: setState, + dataGridConfiguration: widget.dataGridConfiguration, + advanceFilterTopPadding: advanceFilterTopPadding, + filterPopupValueNotifier: _filterPopupValueNotifier, + ), + if (isBothFilterEnabled) + _FilterPopupMenuTile( + style: filterHelper.textStyle, + height: filterHelper.tileHeight, + onTap: onHandleExpansionTileTap, + prefix: Icon( + filterHelper.getFilterForm(widget.column) == + FilteredFrom.advancedFilter + ? const IconData( + 0xe704, + fontFamily: 'FilterIcon', + fontPackage: 'syncfusion_flutter_datagrid', + ) + : const IconData( + 0xe702, + fontFamily: 'FilterIcon', + fontPackage: 'syncfusion_flutter_datagrid', ), - ), + size: filterHelper.textStyle.fontSize! + 6, + color: iconColor, + ), + suffix: Icon( + isAdvancedFilter + ? Icons.keyboard_arrow_down + : Icons.keyboard_arrow_right, + size: filterHelper.textStyle.fontSize! + 6, + color: + dataGridThemeHelper + .advancedFilterPopupDropdownIconColor ?? + iconColor, + ), + prefixPadding: EdgeInsets.only( + left: 4.0, + right: filterHelper.textStyle.fontSize!, + bottom: + filterHelper.textStyle.fontSize! > 14 + ? filterHelper.textStyle.fontSize! - 14 + : 0, + ), + child: Text( + grid_helper.getFilterTileText( + localizations, + filterType, ), + overflow: TextOverflow.ellipsis, + ), + ), + if (isCheckboxFilterEnabled || isBothFilterEnabled) + Visibility( + visible: isAdvancedFilter, + replacement: _CheckboxFilterMenu( + column: widget.column, + setState: setState, + viewSize: viewSize, + dataGridConfiguration: widget.dataGridConfiguration, + filterPopupValueNotifier: _filterPopupValueNotifier, ), - SizedBox( - width: 120.0, - height: filterHelper.tileHeight - 8, - child: OutlinedButton( - style: OutlinedButton.styleFrom( - backgroundColor: - dataGridThemeHelper - .cancelFilteringLabelButtonColor, + child: + isMobile + ? ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewSize!.height, + ), + child: advanceFilterPopupMenu, + ) + : advanceFilterPopupMenu, + ), + if (!isMobile) + Divider( + height: 10, + color: dataGridThemeHelper.filterPopupBottomDividerColor, + ), + if (!isMobile) + Padding( + padding: const EdgeInsets.symmetric(vertical: 6.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + width: 120.0, + height: filterHelper.tileHeight - 8, + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.resolveWith< + Color? + >((Set states) { + // Issue: + // FLUT-7487-The buttons UX in the filter popup menu is not very intuitive when using Material 3 design. + // + // Fix: + // There is an issue with the button user experience (UX) in the filter popup menu, + // which is caused by the default background color of the "ElevatedButton" widget + // being set to the surface color in the Material 3 design. To address this issue, + // we set the background color of the button to the primary color if it is not disabled. + // This means that the default value is ignored, and the given color is used instead. + if (states.contains(WidgetState.disabled)) { + return dataGridThemeHelper + .okFilteringLabelDisabledButtonColor; + } else { + return dataGridThemeHelper + .okFilteringLabelButtonColor ?? + filterHelper.primaryColor; + } + }), + ), + onPressed: + canDisableOkButton() + ? null + : onHandleOkButtonTap, + child: Text( + localizations.okDataGridFilteringLabel, + style: TextStyle( + color: + dataGridThemeHelper + .okFilteringLabelColor ?? + const Color(0xFFFFFFFF), + fontSize: filterHelper.textStyle.fontSize, + fontFamily: filterHelper.textStyle.fontFamily, + ), + ), + ), ), - onPressed: closePage, - child: Text( - localizations.cancelDataGridFilteringLabel, - style: TextStyle( - color: - dataGridThemeHelper - .cancelFilteringLabelColor ?? - filterHelper.primaryColor, - fontSize: filterHelper.textStyle.fontSize, - fontFamily: filterHelper.textStyle.fontFamily, + SizedBox( + width: 120.0, + height: filterHelper.tileHeight - 8, + child: OutlinedButton( + style: OutlinedButton.styleFrom( + backgroundColor: + dataGridThemeHelper + .cancelFilteringLabelButtonColor, + ), + onPressed: closePage, + child: Text( + localizations.cancelDataGridFilteringLabel, + style: TextStyle( + color: + dataGridThemeHelper + .cancelFilteringLabelColor ?? + filterHelper.primaryColor, + fontSize: filterHelper.textStyle.fontSize, + fontFamily: filterHelper.textStyle.fontFamily, + ), + ), ), ), - ), + ], ), - ], - ), - ), - ], - ), - ), + ), + ], + ), + ), + ); + }, ); } @@ -1914,6 +1958,7 @@ class _CheckboxFilterMenu extends StatelessWidget { required this.column, required this.viewSize, required this.dataGridConfiguration, + required this.filterPopupValueNotifier, }) : super(key: key); final StateSetter setState; @@ -1926,6 +1971,8 @@ class _CheckboxFilterMenu extends StatelessWidget { final FocusNode checkboxFocusNode = FocusNode(skipTraversal: true); + final ValueNotifier filterPopupValueNotifier; + bool get isMobile { return !dataGridConfiguration.isDesktop; } @@ -2199,7 +2246,7 @@ class _CheckboxFilterMenu extends StatelessWidget { void onHandleSearchTextFieldChanged(String value) { filterHelper.onSearchTextFieldTextChanged(value); - setState(() {}); + filterPopupValueNotifier.value = value; } } @@ -2209,6 +2256,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { required this.setState, required this.dataGridConfiguration, required this.advanceFilterTopPadding, + required this.filterPopupValueNotifier, }) : super(key: key); final StateSetter setState; @@ -2217,6 +2265,8 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { final double advanceFilterTopPadding; + final ValueNotifier filterPopupValueNotifier; + bool get isMobile { return !dataGridConfiguration.isDesktop; } @@ -2291,50 +2341,54 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { return Row( children: [ - Row( - children: [ - SizedBox.fromSize( - size: const Size(24.0, 24.0), - child: Radio( - key: const ValueKey('datagrid_filtering_and_button'), - value: false, - activeColor: - dataGridThemeHelper.andRadioActiveColor ?? - helper.primaryColor, - fillColor: dataGridThemeHelper.andRadioFillColor, - onChanged: handleChanged, - groupValue: filterHelper.isOrPredicate, + RadioGroup( + groupValue: filterHelper.isOrPredicate, + onChanged: handleChanged, + child: Row( + children: [ + SizedBox.fromSize( + size: const Size(24.0, 24.0), + child: Radio( + key: const ValueKey('datagrid_filtering_and_button'), + value: false, + activeColor: + dataGridThemeHelper.andRadioActiveColor ?? + helper.primaryColor, + fillColor: dataGridThemeHelper.andRadioFillColor, + ), ), - ), - const SizedBox(width: 8.0), - Text( - localizations.andDataGridFilteringLabel, - style: helper.textStyle, - ), - ], + const SizedBox(width: 8.0), + Text( + localizations.andDataGridFilteringLabel, + style: helper.textStyle, + ), + ], + ), ), const SizedBox(width: 16.0), - Row( - children: [ - SizedBox.fromSize( - size: const Size(24.0, 24.0), - child: Radio( - key: const ValueKey('datagrid_filtering_or_button'), - value: true, - activeColor: - dataGridThemeHelper.orRadioActiveColor ?? - helper.primaryColor, - fillColor: dataGridThemeHelper.orRadioFillColor, - onChanged: handleChanged, - groupValue: filterHelper.isOrPredicate, + RadioGroup( + onChanged: handleChanged, + groupValue: filterHelper.isOrPredicate, + child: Row( + children: [ + SizedBox.fromSize( + size: const Size(24.0, 24.0), + child: Radio( + key: const ValueKey('datagrid_filtering_or_button'), + value: true, + activeColor: + dataGridThemeHelper.orRadioActiveColor ?? + helper.primaryColor, + fillColor: dataGridThemeHelper.orRadioFillColor, + ), ), - ), - const SizedBox(width: 8.0), - Text( - localizations.orDataGridFilteringLabel, - style: helper.textStyle, - ), - ], + const SizedBox(width: 8.0), + Text( + localizations.orDataGridFilteringLabel, + style: helper.textStyle, + ), + ], + ), ), ], ); @@ -2347,13 +2401,15 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { final DataGridThemeHelper dataGridThemeHelper = dataGridConfiguration.dataGridThemeHelper!; - void setValue(Object? value) { + void setValue(Object? value, {bool canRebuild = true}) { if (isTopButton) { filterHelper.filterValue1 = value; } else { filterHelper.filterValue2 = value; } - setState(() {}); + if (canRebuild) { + setState(() {}); + } } TextInputType getTextInputType() { @@ -2429,7 +2485,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { dataGridThemeHelper.filterPopupIconColor, ), isExpanded: true, - value: + initialValue: isTopButton ? filterHelper.filterValue1 : filterHelper.filterValue2, @@ -2469,7 +2525,9 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { inputFormatters: getInputFormatters(), onChanged: (String? value) { value = value != null && value.isEmpty ? null : value; - setValue(helper.getActualValue(value)); + final actualValue = helper.getActualValue(value); + setValue(actualValue, canRebuild: false); + filterPopupValueNotifier.value = actualValue; }, decoration: InputDecoration( focusedBorder: @@ -2611,7 +2669,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { dataGridThemeHelper.filterPopupIconColor, ), isExpanded: true, - value: + initialValue: isFirstButton ? filterHelper.filterType1 : filterHelper.filterType2, style: helper.textStyle, items: @@ -2643,6 +2701,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { final DateTime firstDate = filterHelper.items.first.value as DateTime; final DateTime lastDate = filterHelper.items.last.value as DateTime; DateTime initialDate = firstDate; + final SfLocalizations localizations = dataGridConfiguration.localizations; if ((currentDate.isAfter(firstDate) && currentDate.isBefore(lastDate)) || (lastDate.day == currentDate.day && @@ -2655,7 +2714,13 @@ class _AdvancedFilterPopupMenu extends StatelessWidget { initialDate: initialDate, firstDate: firstDate, lastDate: lastDate, - helpText: 'Select a date', + helpText: + localizations + .selectADateDataGridFilteringLabel, // BUG 992105 - Introduced a new property to replace the hardcoded value, ensuring the text adapts to the applied locale. + confirmText: + localizations + .okDataGridFilteringLabel, // BUG 992105 - Used existing OK and Cancel label properties to prevent text capitalization issues originating from the framework. + cancelText: localizations.cancelDataGridFilteringLabel, ); // Need to return if user presses the cancel button to close the data picker view. diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/rendering_widget.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/rendering_widget.dart index 16fe46314..bb3a01ddc 100644 --- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/rendering_widget.dart +++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/rendering_widget.dart @@ -1300,6 +1300,15 @@ class RenderVirtualizingCellsWidget extends RenderBox if (event is PointerDownEvent) { columnDragAndDropController.offset = event.localPosition; columnDragAndDropController.dragDelta = event.position.dx; + + // To enable the feedback widget for drag-and-drop functionality. + final notifier = + configuration + .columnResizeController + .canSwitchResizeColumnCursorNotifier; + if (notifier.value != false) { + notifier.value = false; + } } if (event is PointerMoveEvent) { diff --git a/packages/syncfusion_flutter_datagrid/pubspec.yaml b/packages/syncfusion_flutter_datagrid/pubspec.yaml index 208a759d1..5b565bf71 100644 --- a/packages/syncfusion_flutter_datagrid/pubspec.yaml +++ b/packages/syncfusion_flutter_datagrid/pubspec.yaml @@ -1,25 +1,14 @@ name: syncfusion_flutter_datagrid description: The Syncfusion Flutter DataGrid is used to display and manipulate data in a tabular view. Its rich feature set includes different types of columns, selections, column sizing, etc. -version: 30.1.37 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_datagrid environment: - sdk: ^3.7.0-0 - -dependencies: - flutter: - sdk: flutter - - syncfusion_flutter_core: - path: ../syncfusion_flutter_core - - - - collection: ">=1.9.0 <=2.0.0" - - + sdk: ^3.7.0 + flutter: ">=3.35.1" flutter: + uses-material-design: true fonts: - family: UnsortIcon fonts: @@ -27,3 +16,11 @@ flutter: - family: FilterIcon fonts: - asset: assets/font/FilterIcon.ttf + +dependencies: + flutter: + sdk: flutter + intl: ^0.20.2 + collection: ">=1.9.0 <=2.0.0" + syncfusion_flutter_core: + path: ../syncfusion_flutter_core diff --git a/packages/syncfusion_flutter_datagrid_export/CHANGELOG.md b/packages/syncfusion_flutter_datagrid_export/CHANGELOG.md index 7f1491795..32a8d3e64 100644 --- a/packages/syncfusion_flutter_datagrid_export/CHANGELOG.md +++ b/packages/syncfusion_flutter_datagrid_export/CHANGELOG.md @@ -1,3 +1,19 @@ +## Unreleased + +No changes. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter DataGrid Export widget has been updated to Flutter SDK 3.35.0. + +## [30.1.37] - 06/25/2025 + +**General** + +* The compatible version of our Flutter DataGrid Export widget has been updated to Flutter SDK 3.32.0. + ## [29.1.39] - 04/22/2025 **General** diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle b/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle deleted file mode 100644 index 5fe3c929f..000000000 --- a/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion flutter.compileSdkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle.kts b/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle.kts new file mode 100644 index 000000000..1117d316c --- /dev/null +++ b/packages/syncfusion_flutter_datagrid_export/example/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.datagrid_export_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.datagrid_export_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/debug/AndroidManifest.xml b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/debug/AndroidManifest.xml index c208884f3..399f6981d 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/debug/AndroidManifest.xml +++ b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/AndroidManifest.xml index 3f41384db..8a64452f8 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/AndroidManifest.xml @@ -1,13 +1,13 @@ - - + + + + + + + + diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/datagrid_export_example/MainActivity.kt b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/datagrid_export_example/MainActivity.kt new file mode 100644 index 000000000..27cef1301 --- /dev/null +++ b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/datagrid_export_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.datagrid_export_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a000d..000000000 --- a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/res/values-night/styles.xml b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/res/values-night/styles.xml index 3db14bb53..06952be74 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/res/values-night/styles.xml +++ b/packages/syncfusion_flutter_datagrid_export/example/android/app/src/main/res/values-night/styles.xml @@ -3,7 +3,7 @@ diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle b/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle deleted file mode 100644 index 4256f9173..000000000 --- a/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.6.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle.kts b/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle.kts new file mode 100644 index 000000000..dbee657bb --- /dev/null +++ b/packages/syncfusion_flutter_datagrid_export/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/gradle.properties b/packages/syncfusion_flutter_datagrid_export/example/android/gradle.properties index 94adc3a3f..f018a6181 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/android/gradle.properties +++ b/packages/syncfusion_flutter_datagrid_export/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_datagrid_export/example/android/gradle/wrapper/gradle-wrapper.properties index bc6a58afd..ac3b47926 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_datagrid_export/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle b/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle deleted file mode 100644 index 44e62bcf0..000000000 --- a/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle.kts b/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_datagrid_export/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_datagrid_export/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_datagrid_export/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_datagrid_export/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_datagrid_export/example/lib/helper/save_file_mobile.dart b/packages/syncfusion_flutter_datagrid_export/example/lib/helper/save_file_mobile.dart index d2edbbbda..24dd20dfd 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/lib/helper/save_file_mobile.dart +++ b/packages/syncfusion_flutter_datagrid_export/example/lib/helper/save_file_mobile.dart @@ -14,24 +14,24 @@ Future saveAndLaunchFile(List bytes, String fileName) async { Platform.isLinux || Platform.isWindows) { if (Platform.isAndroid) { - final Directory? directory = await path_provider - .getExternalStorageDirectory(); + final Directory? directory = + await path_provider.getExternalStorageDirectory(); if (directory != null) { path = directory.path; } } else { - final Directory directory = await path_provider - .getApplicationSupportDirectory(); + final Directory directory = + await path_provider.getApplicationSupportDirectory(); path = directory.path; } } else { - path = await path_provider_interface.PathProviderPlatform.instance - .getApplicationSupportPath(); + path = + await path_provider_interface.PathProviderPlatform.instance + .getApplicationSupportPath(); } - final String fileLocation = Platform.isWindows - ? '$path\\$fileName' - : '$path/$fileName'; + final String fileLocation = + Platform.isWindows ? '$path\\$fileName' : '$path/$fileName'; final File file = File(fileLocation); await file.writeAsBytes(bytes, flush: true); diff --git a/packages/syncfusion_flutter_datagrid_export/example/lib/main.dart b/packages/syncfusion_flutter_datagrid_export/example/lib/main.dart index d8d540c62..961cef976 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/lib/main.dart +++ b/packages/syncfusion_flutter_datagrid_export/example/lib/main.dart @@ -209,21 +209,22 @@ class Employee { class EmployeeDataSource extends DataGridSource { /// Creates the employee data source class with required details. EmployeeDataSource({required List employeeData}) { - _employeeData = employeeData - .map( - (Employee e) => DataGridRow( - cells: [ - DataGridCell(columnName: 'ID', value: e.id), - DataGridCell(columnName: 'Name', value: e.name), - DataGridCell( - columnName: 'Designation', - value: e.designation, + _employeeData = + employeeData + .map( + (Employee e) => DataGridRow( + cells: [ + DataGridCell(columnName: 'ID', value: e.id), + DataGridCell(columnName: 'Name', value: e.name), + DataGridCell( + columnName: 'Designation', + value: e.designation, + ), + DataGridCell(columnName: 'Salary', value: e.salary), + ], ), - DataGridCell(columnName: 'Salary', value: e.salary), - ], - ), - ) - .toList(); + ) + .toList(); } List _employeeData = []; @@ -234,13 +235,14 @@ class EmployeeDataSource extends DataGridSource { @override DataGridRowAdapter buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((DataGridCell cell) { - return Container( - alignment: Alignment.center, - padding: const EdgeInsets.all(8.0), - child: Text(cell.value.toString()), - ); - }).toList(), + cells: + row.getCells().map((DataGridCell cell) { + return Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(8.0), + child: Text(cell.value.toString()), + ); + }).toList(), ); } } diff --git a/packages/syncfusion_flutter_datagrid_export/example/pubspec.yaml b/packages/syncfusion_flutter_datagrid_export/example/pubspec.yaml index 62035a0ce..0583632c6 100644 --- a/packages/syncfusion_flutter_datagrid_export/example/pubspec.yaml +++ b/packages/syncfusion_flutter_datagrid_export/example/pubspec.yaml @@ -1,26 +1,23 @@ -name: example -description: A new Flutter project. - +name: datagrid_export_example +description: This project demonstrates how to use Syncfusion Flutter DataGrid Export widget. publish_to: "none" - version: 1.0.0+1 environment: - sdk: ^3.7.0-0 + sdk: ^3.7.0 + +flutter: + uses-material-design: true dependencies: - cupertino_icons: ^1.0.2 flutter: sdk: flutter + web: ^1.1.0 open_file: ^3.2.1 path_provider: ^2.0.2 syncfusion_flutter_datagrid_export: path: ../ - web: ^1.1.0 dev_dependencies: flutter_test: sdk: flutter - -flutter: - uses-material-design: true diff --git a/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_excel.dart b/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_excel.dart index bd5554b78..111317c68 100644 --- a/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_excel.dart +++ b/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_excel.dart @@ -274,9 +274,10 @@ class DataGridToExcelConverter { return; } - final List summaryRows = dataGrid.tableSummaryRows - .where((GridTableSummaryRow row) => row.position == position) - .toList(); + final List summaryRows = + dataGrid.tableSummaryRows + .where((GridTableSummaryRow row) => row.position == position) + .toList(); if (summaryRows.isEmpty) { return; @@ -362,9 +363,10 @@ class DataGridToExcelConverter { /// Gets the cell value required for data rows. @protected Object? getCellValue(DataGridRow row, GridColumn column) { - final DataGridCell cellValue = row.getCells().firstWhereOrNull( - (DataGridCell cell) => cell.columnName == column.columnName, - )!; + final DataGridCell cellValue = + row.getCells().firstWhereOrNull( + (DataGridCell cell) => cell.columnName == column.columnName, + )!; return cellValue.value; } @@ -374,11 +376,13 @@ class DataGridToExcelConverter { List? rows, Worksheet worksheet, ) { - _columns = dataGrid.columns - .where( - (GridColumn column) => !excludeColumns.contains(column.columnName), - ) - .toList(); + _columns = + dataGrid.columns + .where( + (GridColumn column) => + !excludeColumns.contains(column.columnName), + ) + .toList(); // Return if all the columns are `excludeColumns`. if (columns.isEmpty) { @@ -573,16 +577,14 @@ class DataGridToExcelConverter { switch (cellType) { case DataGridExportCellType.columnHeader: case DataGridExportCellType.stackedHeader: - final double height = dataGrid.headerRowHeight.isNaN - ? 56.0 - : dataGrid.headerRowHeight; + final double height = + dataGrid.headerRowHeight.isNaN ? 56.0 : dataGrid.headerRowHeight; sheet.setRowHeightInPixels(excelRowIndex, height); break; case DataGridExportCellType.row: case DataGridExportCellType.tableSummaryRow: - final double height = dataGrid.rowHeight.isNaN - ? 49.0 - : dataGrid.rowHeight; + final double height = + dataGrid.rowHeight.isNaN ? 49.0 : dataGrid.rowHeight; sheet.setRowHeightInPixels(excelRowIndex, height); break; } diff --git a/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_pdf.dart b/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_pdf.dart index 99d4cdfa6..1b5d223af 100644 --- a/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_pdf.dart +++ b/packages/syncfusion_flutter_datagrid_export/lib/src/export_to_pdf.dart @@ -466,11 +466,13 @@ class DataGridToPdfConverter { ); //final List columns = dataGrid.columns; - _columns = dataGrid.columns - .where( - (GridColumn column) => !excludeColumns.contains(column.columnName), - ) - .toList(); + _columns = + dataGrid.columns + .where( + (GridColumn column) => + !excludeColumns.contains(column.columnName), + ) + .toList(); //if fit all columns in one page is false then horizontal overflow is true and type is next page if (!fitAllColumnsInOnePage) { @@ -638,9 +640,10 @@ class DataGridToPdfConverter { /// Gets the cell value required for data rows. @protected Object? getCellValue(GridColumn column, DataGridRow row) { - final DataGridCell cellValue = row.getCells().firstWhereOrNull( - (DataGridCell element) => element.columnName == column.columnName, - )!; + final DataGridCell cellValue = + row.getCells().firstWhereOrNull( + (DataGridCell element) => element.columnName == column.columnName, + )!; return cellValue.value; } @@ -683,9 +686,10 @@ class DataGridToPdfConverter { return; } - final List summaryRows = dataGrid.tableSummaryRows - .where((GridTableSummaryRow row) => row.position == position) - .toList(); + final List summaryRows = + dataGrid.tableSummaryRows + .where((GridTableSummaryRow row) => row.position == position) + .toList(); if (summaryRows.isEmpty) { return; diff --git a/packages/syncfusion_flutter_datagrid_export/lib/src/helper.dart b/packages/syncfusion_flutter_datagrid_export/lib/src/helper.dart index 857a17b1b..7d51f0725 100644 --- a/packages/syncfusion_flutter_datagrid_export/lib/src/helper.dart +++ b/packages/syncfusion_flutter_datagrid_export/lib/src/helper.dart @@ -133,9 +133,8 @@ List getSpannedCellStartAndEndIndex({ if (firstColumnIndex > startColumnIndex) { // Updates the first and last column index if any exclude column exists // before the `firstColumnIndex`. - excludeColumnsCount = excludeColumnIndexes - .where((int index) => index < columnIndex) - .length; + excludeColumnsCount = + excludeColumnIndexes.where((int index) => index < columnIndex).length; firstColumnIndex = max( startColumnIndex, @@ -148,12 +147,13 @@ List getSpannedCellStartAndEndIndex({ } // To remove the in-between excluded columns from the `lastColumnIndex`. - excludeColumnsCount = excludeColumnIndexes - .where( - (int index) => - index >= columnIndex && index <= columnIndex + columnSpan, - ) - .length; + excludeColumnsCount = + excludeColumnIndexes + .where( + (int index) => + index >= columnIndex && index <= columnIndex + columnSpan, + ) + .length; lastColumnIndex -= excludeColumnsCount; return [firstColumnIndex, lastColumnIndex]; @@ -188,9 +188,12 @@ int getSummaryColumnIndex( return -1; } - final List visibleColumns = columns - .where((GridColumn column) => !excludeColumns.contains(column.columnName)) - .toList(); + final List visibleColumns = + columns + .where( + (GridColumn column) => !excludeColumns.contains(column.columnName), + ) + .toList(); final GridColumn? column = visibleColumns.firstWhereOrNull( (GridColumn element) => element.columnName == columnName, ); diff --git a/packages/syncfusion_flutter_datagrid_export/pubspec.yaml b/packages/syncfusion_flutter_datagrid_export/pubspec.yaml index 79995a53f..432211d97 100644 --- a/packages/syncfusion_flutter_datagrid_export/pubspec.yaml +++ b/packages/syncfusion_flutter_datagrid_export/pubspec.yaml @@ -1,16 +1,16 @@ name: syncfusion_flutter_datagrid_export description: The Syncfusion Flutter DataGrid Export library is used to export the DataGrid content to Excel and Pdf format with several customization options. -version: 30.1.37 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_datagrid_export environment: - sdk: ^3.7.0-0 - flutter: ">=1.17.0" + sdk: ^3.7.0 + flutter: ">=3.35.1" dependencies: flutter: sdk: flutter - + collection: ">=1.9.0 <=2.0.0" syncfusion_flutter_datagrid: path: ../syncfusion_flutter_datagrid @@ -22,11 +22,3 @@ dependencies: syncfusion_flutter_pdf: path: ../syncfusion_flutter_pdf - - - - collection: ">=1.9.0 <=2.0.0" - - - -flutter: null diff --git a/packages/syncfusion_flutter_datepicker/CHANGELOG.md b/packages/syncfusion_flutter_datepicker/CHANGELOG.md index de6733777..45a08df0d 100644 --- a/packages/syncfusion_flutter_datepicker/CHANGELOG.md +++ b/packages/syncfusion_flutter_datepicker/CHANGELOG.md @@ -1,6 +1,18 @@ ## Unreleased -* No changes. +* No changes. + +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter datepicker widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter datepicker widget has been updated to Flutter SDK 3.35. ## [30.1.37] - 06/25/2025 diff --git a/packages/syncfusion_flutter_datepicker/example/android/app/build.gradle.kts b/packages/syncfusion_flutter_datepicker/example/android/app/build.gradle.kts index 21ecea973..337394e18 100644 --- a/packages/syncfusion_flutter_datepicker/example/android/app/build.gradle.kts +++ b/packages/syncfusion_flutter_datepicker/example/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.example" + namespace = "com.example.datepicker_example" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.example" + applicationId = "com.example.datepicker_example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/packages/syncfusion_flutter_datepicker/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_datepicker/example/android/app/src/main/AndroidManifest.xml index 74a78b939..d3fe3a37d 100644 --- a/packages/syncfusion_flutter_datepicker/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_datepicker/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ =3.29.0" + flutter: ">=3.35.1" flutter: uses-material-design: true @@ -20,5 +20,3 @@ dependencies: intl: '>=0.18.1 <0.21.0' syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_gauges/CHANGELOG.md b/packages/syncfusion_flutter_gauges/CHANGELOG.md index 7e8d3e87f..55da66ff5 100644 --- a/packages/syncfusion_flutter_gauges/CHANGELOG.md +++ b/packages/syncfusion_flutter_gauges/CHANGELOG.md @@ -1,6 +1,26 @@ ## Unreleased -* No changes. +* No changes. + +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter gauges widget has been updated to Flutter SDK 3.38. + +## [31.2.5] - 11/04/2025 + +## Radial Gauge + +**Bugs** + +* Now, the [MarkerPointer](https://pub.dev/documentation/syncfusion_flutter_gauges/latest/gauges/MarkerPointer-class.html) image will render properly without any clipping issues. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter gauges widget has been updated to Flutter SDK 3.35. ## [30.1.37] - 06/25/2025 diff --git a/packages/syncfusion_flutter_barcodes/example/android/app/build.gradle b/packages/syncfusion_flutter_gauges/example/android/app/build.gradle.kts similarity index 69% rename from packages/syncfusion_flutter_barcodes/example/android/app/build.gradle rename to packages/syncfusion_flutter_gauges/example/android/app/build.gradle.kts index b5511a9a3..367dfe535 100644 --- a/packages/syncfusion_flutter_barcodes/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_gauges/example/android/app/build.gradle.kts @@ -1,27 +1,27 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { - namespace = "com.example.example" + namespace = "com.example.gauges_example" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.example" + applicationId = "com.example.gauges_example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_gauges/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_gauges/example/android/app/src/main/AndroidManifest.xml index 74a78b939..432112978 100644 --- a/packages/syncfusion_flutter_gauges/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_gauges/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ ("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_gauges/example/android/gradle.properties b/packages/syncfusion_flutter_gauges/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_gauges/example/android/gradle.properties +++ b/packages/syncfusion_flutter_gauges/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_gauges/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_gauges/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_gauges/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_gauges/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_gauges/example/android/settings.gradle b/packages/syncfusion_flutter_gauges/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/syncfusion_flutter_gauges/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_gauges/example/android/settings.gradle.kts b/packages/syncfusion_flutter_gauges/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_gauges/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_gauges/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_gauges/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_gauges/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_gauges/lib/src/radial_gauge/pointers/marker_pointer_renderer.dart b/packages/syncfusion_flutter_gauges/lib/src/radial_gauge/pointers/marker_pointer_renderer.dart index bb7a60115..74b0d955a 100644 --- a/packages/syncfusion_flutter_gauges/lib/src/radial_gauge/pointers/marker_pointer_renderer.dart +++ b/packages/syncfusion_flutter_gauges/lib/src/radial_gauge/pointers/marker_pointer_renderer.dart @@ -916,7 +916,7 @@ class RenderMarkerPointer extends RenderBox { markerHeight / 2, ); if (_image != null) { - canvas.drawImageNine(_image!, rect, rect, paint); + paintImage(canvas: canvas, rect: rect, image: _image!); } } diff --git a/packages/syncfusion_flutter_gauges/pubspec.yaml b/packages/syncfusion_flutter_gauges/pubspec.yaml index 213584222..de054e8af 100644 --- a/packages/syncfusion_flutter_gauges/pubspec.yaml +++ b/packages/syncfusion_flutter_gauges/pubspec.yaml @@ -1,11 +1,11 @@ name: syncfusion_flutter_gauges description: The Flutter gauges library includes a linear gauge and radial gauge (a.k.a. circular gauge) to create modern, interactive, animated gauges and radial sliders. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_gauges environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" flutter: uses-material-design: true @@ -16,5 +16,3 @@ dependencies: intl: '>=0.18.1 <0.21.0' syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_maps/CHANGELOG.md b/packages/syncfusion_flutter_maps/CHANGELOG.md index c1300c5bc..ec989f409 100644 --- a/packages/syncfusion_flutter_maps/CHANGELOG.md +++ b/packages/syncfusion_flutter_maps/CHANGELOG.md @@ -2,6 +2,18 @@ * No changes. +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter maps widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter maps widget has been updated to Flutter SDK 3.35. + ## [30.1.37] - 06/25/2025 **General** diff --git a/packages/syncfusion_flutter_maps/example/android/build.gradle.kts b/packages/syncfusion_flutter_maps/example/android/build.gradle.kts index 89176ef44..dbee657bb 100644 --- a/packages/syncfusion_flutter_maps/example/android/build.gradle.kts +++ b/packages/syncfusion_flutter_maps/example/android/build.gradle.kts @@ -5,7 +5,10 @@ allprojects { } } -val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { diff --git a/packages/syncfusion_flutter_maps/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_maps/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0..ac3b47926 100644 --- a/packages/syncfusion_flutter_maps/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_maps/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_maps/example/android/settings.gradle.kts b/packages/syncfusion_flutter_maps/example/android/settings.gradle.kts index a439442c2..c571d1e63 100644 --- a/packages/syncfusion_flutter_maps/example/android/settings.gradle.kts +++ b/packages/syncfusion_flutter_maps/example/android/settings.gradle.kts @@ -1,11 +1,12 @@ pluginManagement { - val flutterSdkPath = run { - val properties = java.util.Properties() - file("local.properties").inputStream().use { properties.load(it) } - val flutterSdkPath = properties.getProperty("flutter.sdk") - require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } - flutterSdkPath - } + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") @@ -18,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/syncfusion_flutter_maps/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_maps/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_maps/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_maps/lib/src/layer/vector_layers.dart b/packages/syncfusion_flutter_maps/lib/src/layer/vector_layers.dart index 606613059..c244ab0be 100644 --- a/packages/syncfusion_flutter_maps/lib/src/layer/vector_layers.dart +++ b/packages/syncfusion_flutter_maps/lib/src/layer/vector_layers.dart @@ -8441,7 +8441,7 @@ class MapArc extends DiagnosticableTree { // To calculate dash array path for series Path? _dashPath( Path? source, { - required _IntervalList dashArray, + required _IntervalList dashArray, double capRadius = 0, }) { if (source == null) { @@ -8500,7 +8500,7 @@ void _drawDashedLine( canvas.drawPath( _dashPath( path, - dashArray: _IntervalList(dashArray), + dashArray: _IntervalList(dashArray), capRadius: capRadius, )!, paint, @@ -8511,7 +8511,7 @@ void _drawDashedLine( } // A circular array for dash offsets and lengths. -class _IntervalList { +class _IntervalList { _IntervalList(this.dashArray); final List dashArray; diff --git a/packages/syncfusion_flutter_maps/lib/src/layer/zoomable.dart b/packages/syncfusion_flutter_maps/lib/src/layer/zoomable.dart index f55951281..50513d531 100644 --- a/packages/syncfusion_flutter_maps/lib/src/layer/zoomable.dart +++ b/packages/syncfusion_flutter_maps/lib/src/layer/zoomable.dart @@ -226,7 +226,8 @@ class _ZoomableState extends State with TickerProviderStateMixin { return matrix.clone(); } - return matrix.clone()..translate(translation.dx, translation.dy); + return matrix.clone() + ..translateByDouble(translation.dx, translation.dy, 0.0, 1.0); } // Scales the given matrix with considering the min and max zoomLevel. @@ -242,7 +243,8 @@ class _ZoomableState extends State with TickerProviderStateMixin { _getScale(widget.maxZoomLevel), ); final double clampedScale = clampedTotalScale / currentScale; - return matrix.clone()..scale(clampedScale); + return matrix.clone() + ..scaleByDouble(clampedScale, clampedScale, clampedScale, 1.0); } ActionType _getActionTypes( @@ -840,9 +842,10 @@ class _ZoomableState extends State with TickerProviderStateMixin { .._actualRect = widget.initialRect .._zoomLevel = widget.initialZoomLevel; _boundaryRect = _getBoundaryRect(); + final double clampedScale = _getScale(widget.initialZoomLevel); widget.zoomController.controllerMatrix = Matrix4.identity() - ..scale(_getScale(widget.initialZoomLevel)) + ..scaleByDouble(clampedScale, clampedScale, clampedScale, 1.0) ..setTranslation( Vector3(widget.initialRect.left, widget.initialRect.top, 0.0), ); @@ -947,7 +950,7 @@ class ZoomableController { final double newScale = pow(2, _zoomLevel - 1).toDouble(); controllerMatrix = Matrix4.identity() - ..scale(newScale) + ..scaleByDouble(newScale, newScale, newScale, 1.0) ..setTranslation(Vector3(_actualRect.left, _actualRect.top, 0.0)); notifyListeners(); return; @@ -961,7 +964,7 @@ class ZoomableController { final double newScale = pow(2, _zoomLevel - 1).toDouble(); controllerMatrix = Matrix4.identity() - ..scale(newScale) + ..scaleByDouble(newScale, newScale, newScale, 1.0) ..setTranslation(Vector3(_actualRect.left, _actualRect.top, 0.0)); notifyListeners(); } diff --git a/packages/syncfusion_flutter_maps/pubspec.yaml b/packages/syncfusion_flutter_maps/pubspec.yaml index a740a860c..2c641fd38 100644 --- a/packages/syncfusion_flutter_maps/pubspec.yaml +++ b/packages/syncfusion_flutter_maps/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_maps description: A Flutter Maps library for creating beautiful, interactive, and customizable maps from shape files or WMTS services to visualize the geographical area. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_maps screenshots: @@ -11,14 +11,12 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" dependencies: flutter: sdk: flutter http: ^1.0.0 - vector_math: ">=2.1.0 <=3.0.0" + vector_math: ">=2.2.0 <=3.0.0" syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_pdf/CHANGELOG.md b/packages/syncfusion_flutter_pdf/CHANGELOG.md index bf01dfbf3..07257ee78 100644 --- a/packages/syncfusion_flutter_pdf/CHANGELOG.md +++ b/packages/syncfusion_flutter_pdf/CHANGELOG.md @@ -1,48 +1,144 @@ ## Unreleased +- No changes. + +## [31.2.15] - 11/25/2025 + +**Bugs** + +- Resolved an issue where the time zone sign and the offset value were incorrect for negative offset time zones in the PdfSignature dictionary. + +## [31.2.12] - 11/18/2025 + +- No changes. + +## [31.2.10] - 11/12/2025 + +- No changes. + +## [31.2.5] - 11/04/2025 + +- No changes. + +## [31.2.4] - 10/28/2025 + +- No changes. + +## [31.2.3] - 10/22/2025 + +- No changes. + +## [31.2.2] - 10/15/2025 + +- No changes. + +## [31.1.23] - 10/07/2025 + +**Bugs** + +- Resolved an issue where the application freezes when extracting text from a specific PDF document + +## [31.1.22] - 10/01/2025 + +- No changes. + +## [31.1.21] - 09/23/2025 + +- No changes. + +## [31.1.20] - 09/17/2025 + +**Bugs** + +- Resolved a typecast error encountered while accessing a form in a specific PDF document. + +## [31.1.19] - 09/12/2025 + +- No changes. + +## [31.1.18] - 09/10/2025 + +- No changes. + +## [31.1.17] - 09/05/2025 + +- No changes. + +## [30.2.7] - 08/26/2025 + +**Bugs** + +- Resolved an issue related to incorrect glyph bounding in a specific PDF document. + +## [30.2.6] - 08/19/2025 + +**Bugs** + +- Fixed performance lag during loading encrypted PDF document. + +## [30.2.5] - 08/13/2025 + +**Bugs** + +- Resolved an issue where the application hangs when accessing the read-only value of a form field in a specific PDF document. + +## [30.2.4] - 08/07/2025 + +**Bugs** + +* Resolved an issue while extracting text line bounds from 90-degree rotated pages in a specific PDF document. + +## [30.1.41] - 07/22/2025 + **Bugs** +* Resolved an exception that occurred when removing document-level layers in a specific PDF document. + +## [30.1.37] - 06/25/2025 + +**General** + * The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.32.0. -## [29.2.11] - 17/06/2025 +## [29.2.11] - 06/17/2025 **Bugs** * Resolved an exception that occurred when hiding document-level layers in a specific PDF document. -## [29.2.9] - 05/06/2025 +## [29.2.9] - 06/05/2025 **Bugs** * Resolved a mismatch error in the text word length and text glyph length from a specific PDF document. -## [29.2.7] - 27/05/2025 +## [29.2.7] - 05/27/2025 **Bugs** * Resolved a range error exception while extracting text lines from a specific PDF document. -## [29.2.4] - 13/05/2025 +## [29.2.4] - 05/14/2025 **Bugs** * Resolved an Out-Of-Memory crash that occurred during the decryption of PDF document. * Resolved a performance issue when decrypting password-protected PDF documents. -## [29.1.41] - 06/05/2025 +## [29.1.41] - 05/06/2025 **Bugs** * Resolved an issue where an exception occurred when flattening a signature field in a PDF document. -## [29.1.40] - 29/04/2025 +## [29.1.40] - 04/29/2025 **Bugs** * Resolved a content preservation issue that occurred when drawing multiple PDF grids on the same page of a PDF document. * Resolved an issue where PDF form is returned as null when acro form has no fields. -## [29.1.39] - 22/04/2025 +## [29.1.39] - 04/22/2025 **General** @@ -704,4 +800,4 @@ Initial release * Provided the support for adding hyperlinks and internal document navigations. * Provided the support for color, pen, and brushes. * Provided the support for adding Chinese, Japanese, and Korean text with the standard CJK fonts. -* Provided the support for creating and drawing PdfTemplates. +* Provided the support for creating and drawing PdfTemplates. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/android/app/build.gradle b/packages/syncfusion_flutter_pdf/example/android/app/build.gradle index e6af82920..436208f86 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_pdf/example/android/app/build.gradle @@ -11,12 +11,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a000d..000000000 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_pdf/example/android/settings.gradle b/packages/syncfusion_flutter_pdf/example/android/settings.gradle index b9e43bd37..e12d764b5 100644 --- a/packages/syncfusion_flutter_pdf/example/android/settings.gradle +++ b/packages/syncfusion_flutter_pdf/example/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.9.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/linux/main.cc b/packages/syncfusion_flutter_pdf/example/linux/main.cc deleted file mode 100644 index e7c5c5437..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/packages/syncfusion_flutter_pdf/example/linux/my_application.cc b/packages/syncfusion_flutter_pdf/example/linux/my_application.cc deleted file mode 100644 index 634f4c519..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/my_application.cc +++ /dev/null @@ -1,105 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen *screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "example"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } - else { - gtk_window_set_title(window, "example"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject *object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/packages/syncfusion_flutter_pdf/example/linux/my_application.h b/packages/syncfusion_flutter_pdf/example/linux/my_application.h deleted file mode 100644 index 72271d5e4..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/packages/syncfusion_flutter_pdf/example/pubspec.yaml b/packages/syncfusion_flutter_pdf/example/pubspec.yaml index a9e4e8e02..56d1439f5 100644 --- a/packages/syncfusion_flutter_pdf/example/pubspec.yaml +++ b/packages/syncfusion_flutter_pdf/example/pubspec.yaml @@ -3,17 +3,16 @@ description: Demo for creating a PDF file using syncfusion_flutter_pdf package. version: 1.0.0+1 environment: - sdk: ^3.7.0-0 + sdk: ^3.7.0 + +flutter: + uses-material-design: true dependencies: flutter: sdk: flutter - path_provider: ^2.1.2 + web: ^1.1.0 open_file: ^3.3.2 + path_provider: ^2.1.2 syncfusion_flutter_pdf: path: ../ - web: ^1.1.0 - -# The following section is specific to Flutter. -flutter: - uses-material-design: true diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp deleted file mode 100644 index 2d6636ab6..000000000 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "run_loop.h" - -#include - -#include - -RunLoop::RunLoop() {} - -RunLoop::~RunLoop() {} - -void RunLoop::Run() { - bool keep_running = true; - TimePoint next_flutter_event_time = TimePoint::clock::now(); - while (keep_running) { - std::chrono::nanoseconds wait_duration = - std::max(std::chrono::nanoseconds(0), - next_flutter_event_time - TimePoint::clock::now()); - ::MsgWaitForMultipleObjects( - 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), - QS_ALLINPUT); - bool processed_events = false; - MSG message; - // All pending Windows messages must be processed; MsgWaitForMultipleObjects - // won't return again for items left in the queue after PeekMessage. - while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { - processed_events = true; - if (message.message == WM_QUIT) { - keep_running = false; - break; - } - ::TranslateMessage(&message); - ::DispatchMessage(&message); - // Allow Flutter to process messages each time a Windows message is - // processed, to prevent starvation. - next_flutter_event_time = - std::min(next_flutter_event_time, ProcessFlutterMessages()); - } - // If the PeekMessage loop didn't run, process Flutter messages. - if (!processed_events) { - next_flutter_event_time = - std::min(next_flutter_event_time, ProcessFlutterMessages()); - } - } -} - -void RunLoop::RegisterFlutterInstance( - flutter::FlutterEngine* flutter_instance) { - flutter_instances_.insert(flutter_instance); -} - -void RunLoop::UnregisterFlutterInstance( - flutter::FlutterEngine* flutter_instance) { - flutter_instances_.erase(flutter_instance); -} - -RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { - TimePoint next_event_time = TimePoint::max(); - for (auto instance : flutter_instances_) { - std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); - if (wait_duration != std::chrono::nanoseconds::max()) { - next_event_time = - std::min(next_event_time, TimePoint::clock::now() + wait_duration); - } - } - return next_event_time; -} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h b/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h deleted file mode 100644 index 000d36246..000000000 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef RUNNER_RUN_LOOP_H_ -#define RUNNER_RUN_LOOP_H_ - -#include - -#include -#include - -// A runloop that will service events for Flutter instances as well -// as native messages. -class RunLoop { - public: - RunLoop(); - ~RunLoop(); - - // Prevent copying - RunLoop(RunLoop const&) = delete; - RunLoop& operator=(RunLoop const&) = delete; - - // Runs the run loop until the application quits. - void Run(); - - // Registers the given Flutter instance for event servicing. - void RegisterFlutterInstance( - flutter::FlutterEngine* flutter_instance); - - // Unregisters the given Flutter instance from event servicing. - void UnregisterFlutterInstance( - flutter::FlutterEngine* flutter_instance); - - private: - using TimePoint = std::chrono::steady_clock::time_point; - - // Processes all currently pending messages for registered Flutter instances. - TimePoint ProcessFlutterMessages(); - - std::set flutter_instances_; -}; - -#endif // RUNNER_RUN_LOOP_H_ diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart index c2b6448b8..14f639543 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart @@ -302,6 +302,9 @@ class ContentLexer { } else { ch = String.fromCharCode(int.parse(_consumeValue())); } + if (ch == '\uffff') { + break; + } } _isContentEnded = false; isContainsArtifacts = false; diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart index 7472e22f1..fe0270d44 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart @@ -417,7 +417,7 @@ class PdfTextExtractor { bool hasRotation = false; if (i < renderer.imageRenderGlyphList.length) { final Glyph tempGlyph = renderer.imageRenderGlyphList[i]; - if (tempGlyph.isRotated && rotation == 270) { + if (tempGlyph.isRotated && (rotation == 270 || rotation == 90)) { yPos = tempGlyph.boundingRect.left; hasRotation = true; } else { @@ -494,6 +494,22 @@ class PdfTextExtractor { .boundingRect .bottom; wordBound = Rect.fromLTWH(dx, dy, width, height - dy); + } else if (hasRotation && rotation == 90) { + final double startX = + renderer.imageRenderGlyphList[i].boundingRect.left; + final double startY = + renderer.imageRenderGlyphList[i].boundingRect.top; + final double endY = + renderer.imageRenderGlyphList[lastIndex].boundingRect.top; + final double lineWidth = + renderer.imageRenderGlyphList[i].boundingRect.width; + final double lineHeight = + (startY - endY).abs() + + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .height; + wordBound = Rect.fromLTWH(startX, endY, lineWidth, lineHeight); } else { height = renderer.imageRenderGlyphList[i].boundingRect.height; if (dx > @@ -691,9 +707,14 @@ class PdfTextExtractor { } final Rect currentRect = textGlyph.boundingRect; if (previousRect != null) { - if ((previousRect.left + previousRect.width - currentRect.left) - .abs() > - 1.5) { + if (_currentPage!.rotation.name != 'rotateAngle90' && + (previousRect.left + previousRect.width - currentRect.left) + .abs() > + 1.5) { + isSplit = true; + } else if (_currentPage!.rotation.name == 'rotateAngle90' && + textGlyph.isRotated && + (previousRect.width - currentRect.width).abs() > 1.5) { isSplit = true; } else { tempString += text[j]; @@ -1413,6 +1434,20 @@ class PdfTextExtractor { renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.bottom - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top, ); + } else if (rotation == 90 && + renderer.imageRenderGlyphList[lineStartIndex].isRotated) { + final double startX = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left; + final double startY = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top; + final double endY = + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.top; + final double lineWidth = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.width; + final double lineHeight = + (startY - endY).abs() + + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.height; + textLine.bounds = Rect.fromLTWH(startX, endY, lineWidth, lineHeight); } else { textLine.bounds = Rect.fromLTWH( renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart index e39c82118..3a0008f69 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart @@ -580,6 +580,9 @@ class TextElement { txtMatrix.type = MatrixTypes.identity; double changeInX = currentLocation.dx; Offset location = Offset(currentLocation.dx, currentLocation.dy); + final reverseMap = { + for (final entry in differenceMappedTable.entries) entry.value: entry.key, + }; // ignore: avoid_function_literals_in_foreach_calls decodedList.forEach((List? keys, String word) { final double? space = double.tryParse(word); @@ -809,6 +812,15 @@ class TextElement { fontGlyphWidths![cidGidKey!]! * charSizeMultiplier; } } + } else if (differenceMappedTable.containsValue(letter)) { + final key = reverseMap[letter]; + final int? mappedValue = int.tryParse(key ?? ''); + if (mappedValue != null && + glyphWidths!.containsKey(mappedValue)) { + currentGlyphWidth = + glyphWidths[mappedValue]!.toDouble() * + charSizeMultiplier; + } } else if (fontGlyphWidths != null) { currentGlyphWidth = (fontGlyphWidths!.containsKey(charCode) @@ -941,7 +953,7 @@ class TextElement { } else if (matrix.m12 < 0 && matrix.m21 < 0) { glyph.rotationAngle = 180; } - final double x = + double x = ((matrix.offsetX + ((tempFontSize + (glyph.ascent / 1000.0)) * matrix.m21)) / 1.3333333333333333) / @@ -956,7 +968,11 @@ class TextElement { zoomFactor!; double width = glyph.width * tempFontSize; double height = tempFontSize; - if (pageRotation == 270) { + if (pageRotation == 90 && glyph.rotationAngle == 270) { + height = glyph.width * tempFontSize; + width = tempFontSize; + x -= tempFontSize; + } else if (pageRotation == 270) { if (textElementGlyphList.isEmpty || renderWithSpace) { y += width; } else { diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart index 2e99b3d42..098cfebc2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart @@ -286,10 +286,10 @@ class PdfForm implements IPdfWrapper { } } if (fieldKids == null) { - if (fieldDictionary != null) { - if (!_helper.terminalFields.contains(fieldDictionary)) { - _helper.terminalFields.add(fieldDictionary as PdfDictionary); - } + if (fieldDictionary != null && + fieldDictionary is PdfDictionary && + !_helper.terminalFields.contains(fieldDictionary)) { + _helper.terminalFields.add(fieldDictionary); } } else { if (!(fieldDictionary! as PdfDictionary).containsKey( diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart index 62abf43b4..6402ada95 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart @@ -298,13 +298,17 @@ class PdfFormFieldCollectionHelper extends PdfObjectCollectionHelper { ); } dic!.remove(PdfDictionaryProperties.parent); - if (isLoaded) { - dic.setProperty( - PdfDictionaryProperties.parent, - PdfReferenceHolder(oldFieldDic), - ); + if (fieldHelper.dictionary!.containsKey( + PdfDictionaryProperties.kids, + )) { + if (isLoaded) { + dic.setProperty( + PdfDictionaryProperties.parent, + PdfReferenceHolder(oldFieldDic), + ); + } + fieldHelper.widget!.parent = oldField; } - fieldHelper.widget!.parent = oldField; if (!isLoaded && fieldHelper.page != null) { fieldHelper.page!.annotations.add(fieldHelper.widget!); } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart index 620cb5fc6..168e5264d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart @@ -538,6 +538,9 @@ class PdfLayerHelper { if (value is PdfReferenceHolder) { final PdfDictionary? dictionary = value.object as PdfDictionary?; + if (base._isPresent != null && base._isPresent!) { + return; + } _parsingDictionary(dictionary, value, page, key); } }); @@ -580,43 +583,37 @@ class PdfLayerHelper { PdfPage? page, PdfName? layerID, ) { - if (base._isPresent == null || !base._isPresent!) { - base._isPresent = false; - if (!dictionary!.containsKey(PdfDictionaryProperties.name) && - dictionary.containsKey(PdfDictionaryProperties.ocg)) { - if (dictionary.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray? pdfArray = + base._isPresent = false; + if (!dictionary!.containsKey(PdfDictionaryProperties.name) && + dictionary.containsKey(PdfDictionaryProperties.ocg)) { + if (dictionary.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray? pdfArray = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ocg]) + as PdfArray?; + if (pdfArray == null) { + reference = + dictionary[PdfDictionaryProperties.ocg] as PdfReferenceHolder?; + dictionary = PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ocg]) - as PdfArray?; - if (pdfArray == null) { - reference = - dictionary[PdfDictionaryProperties.ocg] as PdfReferenceHolder?; - dictionary = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.ocg], - ) - as PdfDictionary?; - if (dictionary != null && - dictionary.containsKey(PdfDictionaryProperties.name)) { + as PdfDictionary?; + if (dictionary != null && + dictionary.containsKey(PdfDictionaryProperties.name)) { + base._isPresent = _setLayerPage(reference, page, layerID); + } + } else { + for (int a = 0; a < pdfArray.count; a++) { + if (pdfArray[a] is PdfReferenceHolder) { + reference = pdfArray[a]! as PdfReferenceHolder; + dictionary = reference.object as PdfDictionary?; base._isPresent = _setLayerPage(reference, page, layerID); } - } else { - for (int a = 0; a < pdfArray.count; a++) { - if (pdfArray[a] is PdfReferenceHolder) { - reference = pdfArray[a]! as PdfReferenceHolder; - dictionary = reference.object as PdfDictionary?; - base._isPresent = _setLayerPage(reference, page, layerID); - } - } } } - } else if (dictionary.containsKey(PdfDictionaryProperties.name)) { - base._isPresent = _setLayerPage(reference, page, layerID); } - return base._isPresent; - } else { - return false; + } else if (dictionary.containsKey(PdfDictionaryProperties.name)) { + base._isPresent = _setLayerPage(reference, page, layerID); } + return base._isPresent; } bool _setLayerPage( diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart index 50d1a3e11..3e87b868d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart @@ -910,14 +910,19 @@ class PdfLayerCollectionHelper extends PdfObjectCollectionHelper { } if (xObject != null && PdfLayerHelper.getHelper(layer).xobject.isNotEmpty) { + final keysToRemove = []; for (final PdfName? key in xObject.items!.keys) { if (PdfLayerHelper.getHelper(layer).xobject.contains(key!.name)) { - xObject.remove(key); + keysToRemove.add(key); } if (xObject.items!.isEmpty) { break; } } + // ignore: prefer_foreach + for (final PdfName key in keysToRemove) { + xObject.remove(key); + } } final PdfArray content = PdfPageHelper.getHelper( @@ -952,7 +957,9 @@ class PdfLayerCollectionHelper extends PdfObjectCollectionHelper { } if (mOperator == PdfOperators.paintXObject) { if (PdfLayerHelper.getHelper(layer).xobject.contains( - recordCollection.recordCollection[j].operands![0], + recordCollection.recordCollection[j].operands![0] + .trim() + .replaceFirst('/', ''), )) { isSkip = true; } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart index 2a4ef2cfd..57fef9aa4 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart @@ -60,7 +60,7 @@ class PdfDictionary implements IPdfPrimitive, IPdfChangable { IPdfPrimitive? operator [](dynamic key) => returnValue(checkName(key)); /// Set the PdfDictionary items. - operator []=(dynamic key, dynamic value) => addItems(key, value); + void operator []=(dynamic key, dynamic value) => addItems(key, value); /// internal property bool get isSkip { diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart index c4c5cbcf9..6338cc4f9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart @@ -548,7 +548,11 @@ class PdfStream extends PdfDictionary { void decrypt(PdfEncryptor encryptor, int? currentObjectNumber) { if (!decrypted!) { decrypted = true; - data = encryptor.encryptData(currentObjectNumber, dataStream!, false); + data = encryptor.encryptData( + currentObjectNumber, + Uint8List.fromList(dataStream!), + false, + ); _modify(); } } @@ -560,7 +564,7 @@ class PdfStream extends PdfDictionary { if (encryptor.encrypt && !blockEncryption) { data = encryptor.encryptData( PdfDocumentHelper.getHelper(doc).currentSavingObject!.objNum, - data!, + Uint8List.fromList(data!), true, ); } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart index 8151c6936..ee4282574 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../interfaces/pdf_interface.dart'; import '../annotations/json_parser.dart'; @@ -378,7 +379,7 @@ class PdfString implements IPdfPrimitive { } else { data = PdfSecurityHelper.getHelper(security).encryptor.encryptData( PdfDocumentHelper.getHelper(document!).currentSavingObject!.objNum, - data, + Uint8List.fromList(data), true, ); } @@ -398,7 +399,7 @@ class PdfString implements IPdfPrimitive { value = byteToString(data!); final List bytes = encryptor.encryptData( currentObjectNumber, - data!, + Uint8List.fromList(data!), false, ); value = byteToString(bytes); diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart index 67912dc5c..8b1daa6c7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart @@ -287,7 +287,7 @@ class AesEngine extends IBlockCipher { /// internal method void encryptBlock( - input, + Uint8List input, int inOff, Uint8List out, int outOff, @@ -413,7 +413,7 @@ class AesEngine extends IBlockCipher { /// internal method void decryptBlock( - input, + Uint8List input, int inOff, Uint8List out, int outOff, diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart index ac3d63ed3..3a8871571 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart @@ -202,20 +202,16 @@ class PdfSignatureDictionary implements IPdfWrapper { dateTime = _sig!.signedDate!; } final DateFormat dateFormat = DateFormat('yyyyMMddHHmmss'); - final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; - String offsetMinutes = regionMinutes.toString(); - if (regionMinutes >= 0 && regionMinutes <= 9) { - offsetMinutes = '0$offsetMinutes'; - } - final int regionHours = dateTime.timeZoneOffset.inHours; - String offsetHours = regionHours.toString(); - if (regionHours >= 0 && regionHours <= 9) { - offsetHours = '0$offsetHours'; - } + final Duration offset = dateTime.timeZoneOffset; + final String sign = offset.isNegative ? '-' : '+'; + final String offsetHours = offset.inHours.abs().toString().padLeft(2, '0'); + final String offsetMinutes = (offset.inMinutes.abs() % 60) + .toString() + .padLeft(2, '0'); dictionary!.setProperty( PdfDictionaryProperties.m, PdfString( - "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'", + "D:${dateFormat.format(dateTime)}$sign$offsetHours'$offsetMinutes'", ), ); } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart index 93a2f0c96..4c7991169 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:math'; +import 'dart:math' as math; import 'dart:typed_data'; import 'package:crypto/crypto.dart'; @@ -34,8 +35,7 @@ class PdfEncryptor { int? _ownerLoopNum2; int? _ownerLoopNum; - /// internal field - List? paddingBytes; + Uint8List? _paddingBytes; int? _bytesAmount; int? _permissionSet; int? _permissionCleared; @@ -43,7 +43,7 @@ class PdfEncryptor { int? _revisionNumberOut; int? _versionNumberOut; int? _permissionValue; - List? _randomBytes; + Uint8List? _randomBytes; int? _key40; int? _key128; int? _key256; @@ -65,22 +65,22 @@ class PdfEncryptor { int? _revision; String? _userPassword; String? _ownerPassword; - List? _ownerPasswordOut; - List? _userPasswordOut; - List? _encryptionKey; + Uint8List? _ownerPasswordOut; + Uint8List? _userPasswordOut; + Uint8List? _encryptionKey; /// internal field int? keyLength; /// internal field - List? customArray; + Uint8List? customArray; List? _permissionFlagValues; - List? _fileEncryptionKey; - List? _userEncryptionKeyOut; - List? _ownerEncryptionKeyOut; - List? _permissionFlag; - List? _userRandomBytes; - List? _ownerRandomBytes; + Uint8List? _fileEncryptionKey; + Uint8List? _userEncryptionKeyOut; + Uint8List? _ownerEncryptionKeyOut; + Uint8List? _permissionFlag; + Uint8List? _userRandomBytes; + Uint8List? _ownerRandomBytes; /// internal field bool? encryptOnlyMetadata; @@ -104,15 +104,15 @@ class PdfEncryptor { } /// internal property - List? get randomBytes { + Uint8List get randomBytes { if (_randomBytes == null) { + _randomBytes = Uint8List(_randomBytesAmount!); final Random random = Random.secure(); - _randomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), - ); + for (int i = 0; i < _randomBytesAmount!; i++) { + _randomBytes![i] = random.nextInt(256); + } } - return _randomBytes; + return _randomBytes!; } /// internal property @@ -196,13 +196,13 @@ class PdfEncryptor { } /// internal property - List? get ownerPasswordOut { + Uint8List? get ownerPasswordOut { _initializeData(); return _ownerPasswordOut; } /// internal property - List? get userPasswordOut { + Uint8List? get userPasswordOut { _initializeData(); return _userPasswordOut; } @@ -253,7 +253,8 @@ class PdfEncryptor { ]; permissions = [PdfPermissionsFlags.none]; encryptionOptions = PdfEncryptionOptions.encryptAllContents; - paddingBytes = [ + + _paddingBytes = Uint8List.fromList([ 40, 191, 78, @@ -286,8 +287,9 @@ class PdfEncryptor { 83, 105, 122, - ]; - customArray = List.filled(_bytesAmount!, 0, growable: true); + ]); + + customArray = Uint8List(_bytesAmount!); changed = false; hasComputedPasswordValues = false; encryptOnlyMetadata = true; @@ -318,38 +320,46 @@ class PdfEncryptor { } } - List _createUserPassword() { + Uint8List _createUserPassword() { return revisionNumber == 2 ? _create40BitUserPassword() : _create128BitUserPassword(); } - List _create40BitUserPassword() { + Uint8List _create40BitUserPassword() { ArgumentError.checkNotNull(_encryptionKey); + final Uint8List paddingCopy = Uint8List.fromList(_paddingBytes!); return _encryptDataByCustom( - List.from(paddingBytes!), - _encryptionKey, + paddingCopy, + _encryptionKey!, _encryptionKey!.length, ); } - List _create128BitUserPassword() { + Uint8List _create128BitUserPassword() { ArgumentError.checkNotNull(_encryptionKey); - final List data = []; - data.addAll(paddingBytes!); - data.addAll(randomBytes!); - final List resultBytes = md5.convert(data).bytes; - final List dataForCustom = List.generate( - _randomBytesAmount!, - (int i) => resultBytes[i], + + final BytesBuilder dataBuilder = BytesBuilder(copy: false); + dataBuilder.add(_paddingBytes!); + dataBuilder.add(randomBytes); + + final Uint8List resultBytes = Uint8List.fromList( + md5.convert(dataBuilder.toBytes()).bytes, ); - List dataFromCustom = _encryptDataByCustom( + final Uint8List dataForCustom = Uint8List.view( + resultBytes.buffer, + 0, + _randomBytesAmount, + ); + + Uint8List dataFromCustom = _encryptDataByCustom( dataForCustom, - _encryptionKey, + _encryptionKey!, _encryptionKey!.length, ); + for (int i = 1; i < _ownerLoopNum2!; i++) { - final List currentKey = _getKeyWithOwnerPassword(_encryptionKey!, i); + final Uint8List currentKey = _getKeyWithOwnerPassword(_encryptionKey!, i); dataFromCustom = _encryptDataByCustom( dataFromCustom, currentKey, @@ -359,37 +369,49 @@ class PdfEncryptor { return _padTrancateString(dataFromCustom); } - List _create256BitUserPassword() { + Uint8List _create256BitUserPassword() { final Random random = Random.secure(); - _userRandomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), + _userRandomBytes = Uint8List(_randomBytesAmount!); + for (int i = 0; i < _randomBytesAmount!; i++) { + _userRandomBytes![i] = random.nextInt(256); + } + + final Uint8List userPasswordBytes = Uint8List.fromList( + utf8.encode(_userPassword!), ); - final List userPasswordBytes = utf8.encode(_userPassword!); - final List hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(List.generate(8, (int i) => _userRandomBytes![i])); - final List userPasswordOut = []; - userPasswordOut.addAll(sha256.convert(hash).bytes); - userPasswordOut.addAll(_userRandomBytes!); - return userPasswordOut; + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(Uint8List.view(_userRandomBytes!.buffer, 0, 8)); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hashBytes); + resultBuilder.add(_userRandomBytes!); + + return resultBuilder.toBytes(); } - List _createOwnerPassword() { + Uint8List _createOwnerPassword() { final String password = ownerPassword.isEmpty ? userPassword : ownerPassword; - final List customKey = _getKeyFromOwnerPassword(password); - final List userPasswordBytes = _padTrancateString( - utf8.encode(userPassword), + final Uint8List customKey = _getKeyFromOwnerPassword(password); + final Uint8List userPasswordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(userPassword)), ); - List dataFromCustom = _encryptDataByCustom( + + Uint8List dataFromCustom = _encryptDataByCustom( userPasswordBytes, customKey, customKey.length, ); + if (revisionNumber! > 2) { for (int i = 1; i < _ownerLoopNum2!; i++) { - final List currentKey = _getKeyWithOwnerPassword(customKey, i); + final Uint8List currentKey = _getKeyWithOwnerPassword(customKey, i); dataFromCustom = _encryptDataByCustom( dataFromCustom, currentKey, @@ -400,52 +422,69 @@ class PdfEncryptor { return dataFromCustom; } - List _create256BitOwnerPassword() { + Uint8List _create256BitOwnerPassword() { final Random random = Random.secure(); - _ownerRandomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), - ); + _ownerRandomBytes = Uint8List(_randomBytesAmount!); + for (int i = 0; i < _randomBytesAmount!; i++) { + _ownerRandomBytes![i] = random.nextInt(256); + } + final String password = ownerPassword.isEmpty ? userPassword : ownerPassword; - final List ownerPasswordBytes = utf8.encode(password); - final List hash = []; - hash.addAll(ownerPasswordBytes); - hash.addAll(List.generate(8, (int i) => _ownerRandomBytes![i])); - hash.addAll(_userPasswordOut!); - final List ownerPasswordOut = []; - ownerPasswordOut.addAll(sha256.convert(hash).bytes); - ownerPasswordOut.addAll(_ownerRandomBytes!); - return ownerPasswordOut; - } - - List? _createUserEncryptionKey() { - final List hash = []; - hash.addAll(utf8.encode(userPassword)); - hash.addAll(List.generate(8, (int i) => _userRandomBytes![i + 8])); - final List hashBytes = sha256.convert(hash).bytes; + final Uint8List ownerPasswordBytes = Uint8List.fromList( + utf8.encode(password), + ); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(Uint8List.view(_ownerRandomBytes!.buffer, 0, 8)); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hashBytes); + resultBuilder.add(_ownerRandomBytes!); + + return resultBuilder.toBytes(); + } + + Uint8List? _createUserEncryptionKey() { + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(Uint8List.fromList(utf8.encode(userPassword))); + hashBuilder.add(Uint8List.view(_userRandomBytes!.buffer, 8, 8)); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); return AesCipherNoPadding( true, - KeyParameter(Uint8List.fromList(hashBytes)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); + KeyParameter(hashBytes), + ).process(_fileEncryptionKey!); } - List? _createOwnerEncryptionKey() { + Uint8List? _createOwnerEncryptionKey() { final String password = ownerPassword.isEmpty ? userPassword : ownerPassword; - final List hash = []; - hash.addAll(utf8.encode(password)); - hash.addAll(List.generate(8, (int i) => _ownerRandomBytes![i + 8])); - hash.addAll(_userPasswordOut!); - final List hashBytes = sha256.convert(hash).bytes; + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(Uint8List.fromList(utf8.encode(password))); + hashBuilder.add(Uint8List.view(_ownerRandomBytes!.buffer, 8, 8)); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); return AesCipherNoPadding( true, - KeyParameter(Uint8List.fromList(hashBytes)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); + KeyParameter(hashBytes), + ).process(_fileEncryptionKey!); } - List? _createPermissionFlag() { - final List permissionFlagBytes = [ + Uint8List? _createPermissionFlag() { + final Uint8List permissionFlagBytes = Uint8List.fromList([ _permissionValue!.toUnsigned(8), (_permissionValue! >> 8).toUnsigned(8), (_permissionValue! >> 16).toUnsigned(8), @@ -463,119 +502,142 @@ class PdfEncryptor { 98, 98, 98, - ]; + ]); + return AesCipherNoPadding( true, - KeyParameter(Uint8List.fromList(_fileEncryptionKey!)), - ).process(Uint8List.fromList(permissionFlagBytes)); + KeyParameter(_fileEncryptionKey!), + ).process(permissionFlagBytes); } void _createAcrobatX256BitUserPassword() { - final List userPasswordBytes = utf8.encode(_userPassword!); - final Random random = Random.secure(); - final List userValidationSalt = List.generate( - 8, - (int i) => random.nextInt(256), + final Uint8List userPasswordBytes = Uint8List.fromList( + utf8.encode(_userPassword!), ); - final List userKeySalt = List.generate( - 8, - (int i) => random.nextInt(256), + final Random random = Random.secure(); + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + + for (int i = 0; i < 8; i++) { + userValidationSalt[i] = random.nextInt(256); + userKeySalt[i] = random.nextInt(256); + } + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(userValidationSalt); + + Uint8List hash = _acrobatXComputeHash( + hashBuilder.toBytes(), + userPasswordBytes, + null, ); - List hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(userValidationSalt); - hash = _acrobatXComputeHash(hash, userPasswordBytes, null); - _userPasswordOut = []; - _userPasswordOut!.addAll(hash); - _userPasswordOut!.addAll(userValidationSalt); - _userPasswordOut!.addAll(userKeySalt); - hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(userKeySalt); - hash = _acrobatXComputeHash(hash, userPasswordBytes, null); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hash); + resultBuilder.add(userValidationSalt); + resultBuilder.add(userKeySalt); + _userPasswordOut = resultBuilder.toBytes(); + + hashBuilder.clear(); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(userKeySalt); + hash = _acrobatXComputeHash(hashBuilder.toBytes(), userPasswordBytes, null); + _userEncryptionKeyOut = AesCipherNoPadding( true, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); + KeyParameter(hash), + ).process(_fileEncryptionKey!); } void _createAcrobatX256BitOwnerPassword() { final String password = ownerPassword.isEmpty ? userPassword : ownerPassword; - final List ownerPasswordBytes = utf8.encode(password); - final Random random = Random.secure(); - final List ownerValidationSalt = List.generate( - 8, - (int i) => random.nextInt(256), + final Uint8List ownerPasswordBytes = Uint8List.fromList( + utf8.encode(password), ); - final List ownerKeySalt = List.generate( - 8, - (int i) => random.nextInt(256), + final Random random = Random.secure(); + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + + for (int i = 0; i < 8; i++) { + ownerValidationSalt[i] = random.nextInt(256); + ownerKeySalt[i] = random.nextInt(256); + } + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(ownerValidationSalt); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hash = _acrobatXComputeHash( + hashBuilder.toBytes(), + ownerPasswordBytes, + _userPasswordOut, ); - final List owenrPasswordOut = []; - owenrPasswordOut.addAll(ownerPasswordBytes); - owenrPasswordOut.addAll(ownerValidationSalt); - owenrPasswordOut.addAll(_userPasswordOut!); - _ownerPasswordOut = []; - _ownerPasswordOut!.addAll( - _acrobatXComputeHash( - owenrPasswordOut, - ownerPasswordBytes, - _userPasswordOut, - ), + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hash); + resultBuilder.add(ownerValidationSalt); + resultBuilder.add(ownerKeySalt); + _ownerPasswordOut = resultBuilder.toBytes(); + + hashBuilder.clear(); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(ownerKeySalt); + hashBuilder.add(_userPasswordOut!); + + final Uint8List keyHash = _acrobatXComputeHash( + hashBuilder.toBytes(), + ownerPasswordBytes, + _userPasswordOut, ); - _ownerPasswordOut!.addAll(ownerValidationSalt); - _ownerPasswordOut!.addAll(ownerKeySalt); - List hash = []; - hash.addAll(ownerPasswordBytes); - hash.addAll(ownerKeySalt); - hash.addAll(_userPasswordOut!); - hash = _acrobatXComputeHash(hash, ownerPasswordBytes, _userPasswordOut); + _ownerEncryptionKeyOut = AesCipherNoPadding( true, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); + KeyParameter(keyHash), + ).process(_fileEncryptionKey!); } void _createFileEncryptionKey() { final Random random = Random.secure(); - _fileEncryptionKey = List.generate(32, (int i) => random.nextInt(256)); + _fileEncryptionKey = Uint8List(32); + for (int i = 0; i < 32; i++) { + _fileEncryptionKey![i] = random.nextInt(256); + } } - List _encryptDataByCustom( - List data, - List? key, - int keyLength, - ) { - final List buffer = List.filled(data.length, 0, growable: true); + Uint8List _encryptDataByCustom(Uint8List data, Uint8List key, int keyLength) { + final Uint8List buffer = Uint8List(data.length); _recreateCustomArray(key, keyLength); - keyLength = data.length; + int tmp1 = 0; int tmp2 = 0; - for (int i = 0; i < keyLength; i++) { + + for (int i = 0; i < data.length; i++) { tmp1 = (tmp1 + 1) % _bytesAmount!; tmp2 = (tmp2 + customArray![tmp1]) % _bytesAmount!; + final int temp = customArray![tmp1]; customArray![tmp1] = customArray![tmp2]; customArray![tmp2] = temp; + final int byteXor = customArray![(customArray![tmp1] + customArray![tmp2]) % _bytesAmount!]; - buffer[i] = (data[i] ^ byteXor).toUnsigned(8); + buffer[i] = (data[i] ^ byteXor) & 0xFF; } return buffer; } - void _recreateCustomArray(List? key, int keyLength) { - final List tempArray = List.filled( - _bytesAmount!, - 0, - growable: true, - ); + void _recreateCustomArray(Uint8List key, int keyLength) { + final Uint8List tempArray = Uint8List(_bytesAmount!); + for (int i = 0; i < _bytesAmount!; i++) { - tempArray[i] = key![i % keyLength]; - customArray![i] = i.toUnsigned(8); + tempArray[i] = key[i % keyLength]; + customArray![i] = i; } + int temp = 0; for (int i = 0; i < _bytesAmount!; i++) { temp = (temp + customArray![i] + tempArray[i]) % _bytesAmount!; @@ -585,25 +647,33 @@ class PdfEncryptor { } } - List _getKeyFromOwnerPassword(String password) { - final List passwordBytes = _padTrancateString(utf8.encode(password)); - List currentHash = md5.convert(passwordBytes).bytes; - final int? length = _getKeyLength(); + Uint8List _getKeyFromOwnerPassword(String password) { + final Uint8List passwordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(password)), + ); + Uint8List currentHash = Uint8List.fromList( + md5.convert(passwordBytes).bytes, + ); + final int length = _getKeyLength()!; + if (revisionNumber! > 2) { for (int i = 0; i < _ownerLoopNum!; i++) { - currentHash = - md5 - .convert( - currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]), - ) - .bytes; + if (currentHash.length != length) { + final Uint8List truncated = Uint8List(length); + truncated.setRange(0, length, currentHash); + currentHash = Uint8List.fromList(md5.convert(truncated).bytes); + } else { + currentHash = Uint8List.fromList(md5.convert(currentHash).bytes); + } } } - return currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]); + + if (currentHash.length != length) { + final Uint8List result = Uint8List(length); + result.setRange(0, length, currentHash); + return result; + } + return currentHash; } int? _getKeyLength() { @@ -617,142 +687,161 @@ class PdfEncryptor { : _key256)); } - List _padTrancateString(List source) { - final List passwordBytes = []; + Uint8List _padTrancateString(Uint8List source) { + final Uint8List result = Uint8List(_stringLength!); + if (source.isNotEmpty) { - passwordBytes.addAll(source); - } - if (source.length < _stringLength!) { - passwordBytes.addAll( - paddingBytes!.getRange(0, paddingBytes!.length - passwordBytes.length), - ); + final int copyLength = math.min(source.length, _stringLength!); + result.setRange(0, copyLength, source); + + if (copyLength < _stringLength!) { + result.setRange( + copyLength, + _stringLength!, + _paddingBytes!.sublist(0, _stringLength! - copyLength), + ); + } + } else { + result.setRange(0, _stringLength!, _paddingBytes!); } - return List.generate(_stringLength!, (int i) => passwordBytes[i]); + + return result; } - List _getKeyWithOwnerPassword(List originalKey, int index) { - final List result = List.filled( - originalKey.length, - 0, - growable: true, - ); + Uint8List _getKeyWithOwnerPassword(Uint8List originalKey, int index) { + final Uint8List result = Uint8List(originalKey.length); for (int i = 0; i < originalKey.length; i++) { - result[i] = (originalKey[i] ^ index).toUnsigned(8); + result[i] = (originalKey[i] ^ index) & 0xFF; } return result; } - List _createEncryptionKey( + Uint8List _createEncryptionKey( String inputPassword, - List ownerPasswordBytes, + Uint8List ownerPasswordBytes, ) { - final List passwordBytes = _padTrancateString( - utf8.encode(inputPassword), + final Uint8List passwordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(inputPassword)), ); - final List encryptionKeyData = []; - encryptionKeyData.addAll(passwordBytes); - encryptionKeyData.addAll(ownerPasswordBytes); - encryptionKeyData.addAll([ - _permissionValue!.toUnsigned(8), - (_permissionValue! >> 8).toUnsigned(8), - (_permissionValue! >> 16).toUnsigned(8), - (_permissionValue! >> 24).toUnsigned(8), - ]); - encryptionKeyData.addAll(randomBytes!); - int? revisionNumber; + + final BytesBuilder encryptionKeyDataBuilder = BytesBuilder(copy: false); + encryptionKeyDataBuilder.add(passwordBytes); + encryptionKeyDataBuilder.add(ownerPasswordBytes); + + final Uint8List permissionBytes = Uint8List(4); + permissionBytes[0] = _permissionValue!.toUnsigned(8); + permissionBytes[1] = (_permissionValue! >> 8).toUnsigned(8); + permissionBytes[2] = (_permissionValue! >> 16).toUnsigned(8); + permissionBytes[3] = (_permissionValue! >> 24).toUnsigned(8); + encryptionKeyDataBuilder.add(permissionBytes); + encryptionKeyDataBuilder.add(randomBytes); + + int revNum; if (_revision != 0) { - revisionNumber = this.revisionNumber; + revNum = revisionNumber!; } else { - revisionNumber = getKeyLength() + 2; + revNum = getKeyLength() + 2; } - if (revisionNumber! > 3 && !encryptMetadata) { - encryptionKeyData.add(255); - encryptionKeyData.add(255); - encryptionKeyData.add(255); - encryptionKeyData.add(255); + + if (revNum > 3 && !encryptMetadata) { + encryptionKeyDataBuilder.add(Uint8List.fromList([255, 255, 255, 255])); } - List currentHash = md5.convert(encryptionKeyData).bytes; - final int? length = _getKeyLength(); - if (this.revisionNumber! > 2) { + + Uint8List currentHash = Uint8List.fromList( + md5.convert(encryptionKeyDataBuilder.toBytes()).bytes, + ); + final int length = _getKeyLength()!; + + if (revisionNumber! > 2) { for (int i = 0; i < _ownerLoopNum!; i++) { - currentHash = - md5 - .convert( - currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]), - ) - .bytes; + if (currentHash.length != length) { + final Uint8List truncated = Uint8List(length); + truncated.setRange(0, length, currentHash); + currentHash = Uint8List.fromList(md5.convert(truncated).bytes); + } else { + currentHash = Uint8List.fromList(md5.convert(currentHash).bytes); + } } } - return currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]); + + if (currentHash.length != length) { + final Uint8List result = Uint8List(length); + result.setRange(0, length, currentHash); + return result; + } + return currentHash; } - List _acrobatXComputeHash( - List input, - List password, - List? key, + Uint8List _acrobatXComputeHash( + Uint8List input, + Uint8List password, + Uint8List? key, ) { - List hash = sha256.convert(input).bytes; - List? finalHashKey; + Uint8List hash = Uint8List.fromList(sha256.convert(input).bytes); + Uint8List? finalHashKey; + for ( int i = 0; - i < 64 || (finalHashKey![finalHashKey.length - 1] & 0xFF) > i - 32; + i < 64 || + (finalHashKey != null && + (finalHashKey[finalHashKey.length - 1] & 0xFF) > i - 32); i++ ) { - final List roundHash = List.filled( - (key != null && key.length >= 48) - ? 64 * (password.length + hash.length + 48) - : 64 * (password.length + hash.length), - 0, - growable: true, - ); + final int roundHashSize = + (key != null && key.length >= 48) + ? 64 * (password.length + hash.length + 48) + : 64 * (password.length + hash.length); + + final Uint8List roundHash = Uint8List(roundHashSize); int position = 0; + for (int j = 0; j < 64; j++) { - List.copyRange(roundHash, position, password, 0, password.length); + roundHash.setRange(position, position + password.length, password); position += password.length; - List.copyRange(roundHash, position, hash, 0, hash.length); + roundHash.setRange(position, position + hash.length, hash); position += hash.length; if (key != null && key.length >= 48) { - List.copyRange(roundHash, position, key, 0, 48); + roundHash.setRange(position, position + 48, key.sublist(0, 48)); position += 48; } } - final List hashFirst = List.generate(16, (int i) => hash[i]); - final List hashSecond = List.generate( - 16, - (int i) => hash[i + 16], - ); + + final Uint8List hashFirst = Uint8List.view(hash.buffer, 0, 16); + final Uint8List hashSecond = Uint8List.view(hash.buffer, 16, 16); final AesCipher encrypt = AesCipher(true, hashFirst, hashSecond); - finalHashKey = encrypt.update(roundHash, 0, roundHash.length); - final List finalHashKeyFirst = List.generate( - 16, - (int i) => finalHashKey![i], - ); - final BigInt finalKeyBigInteger = _readBigIntFromBytes( - finalHashKeyFirst, - 0, - finalHashKeyFirst.length, - ); - final BigInt divisior = BigInt.parse('3'); - final BigInt algorithmNumber = finalKeyBigInteger % divisior; - final int algorithmIndex = algorithmNumber.toInt(); - if (algorithmIndex == 0) { - hash = sha256.convert(finalHashKey!).bytes; - } else if (algorithmIndex == 1) { - hash = sha384.convert(finalHashKey!).bytes; - } else { - hash = sha512.convert(finalHashKey!).bytes; + + final updateResult = encrypt.update(roundHash, 0, roundHash.length); + finalHashKey = + updateResult != null ? Uint8List.fromList(updateResult) : null; + + if (finalHashKey != null) { + final Uint8List finalHashKeyFirst = Uint8List.view( + finalHashKey.buffer, + 0, + 16, + ); + final BigInt finalKeyBigInteger = _readBigIntFromBytes( + finalHashKeyFirst, + 0, + finalHashKeyFirst.length, + ); + final BigInt algorithmNumber = finalKeyBigInteger % BigInt.from(3); + final int algorithmIndex = algorithmNumber.toInt(); + + if (algorithmIndex == 0) { + hash = Uint8List.fromList(sha256.convert(finalHashKey).bytes); + } else if (algorithmIndex == 1) { + hash = Uint8List.fromList(sha384.convert(finalHashKey).bytes); + } else { + hash = Uint8List.fromList(sha512.convert(finalHashKey).bytes); + } } } - return (hash.length > 32) - ? List.generate(32, (int i) => hash[i]) - : hash; + + return (hash.length > 32) ? Uint8List.view(hash.buffer, 0, 32) : hash; } - BigInt _readBigIntFromBytes(List bytes, int start, int end) { + BigInt _readBigIntFromBytes(Uint8List bytes, int start, int end) { if (end - start <= 4) { int result = 0; for (int i = end - 1; i >= start; i--) { @@ -766,6 +855,24 @@ class PdfEncryptor { (BigInt.one << ((mid - start) * 8)); } + bool _compareByteArrays(Uint8List array1, Uint8List? array2, [int? size]) { + if (array2 == null) { + return false; + } + + final int compareLength = size ?? array1.length; + if (array1.length < compareLength || array2.length < compareLength) { + return false; + } + + for (int i = 0; i < compareLength; i++) { + if (array1[i] != array2[i]) { + return false; + } + } + return true; + } + /// internal method void readFromDictionary(PdfDictionary dictionary) { IPdfPrimitive? obj; @@ -786,7 +893,7 @@ class PdfEncryptor { _updatePermissions(_permissionValue! & ~_permissionSet!); _versionNumberOut = dictionary.getInt(PdfDictionaryProperties.v); _revisionNumberOut = dictionary.getInt(PdfDictionaryProperties.r); - if (_revisionNumberOut != null) { + if (_revisionNumberOut != 0) { _revision = _revisionNumberOut; } int keySize = dictionary.getInt(PdfDictionaryProperties.v); @@ -796,19 +903,27 @@ class PdfEncryptor { ); } if (keySize == 5) { - _userEncryptionKeyOut = - dictionary.getString(PdfDictionaryProperties.ue)!.data; - _ownerEncryptionKeyOut = - dictionary.getString(PdfDictionaryProperties.oe)!.data; - _permissionFlag = - dictionary.getString(PdfDictionaryProperties.perms)!.data; - } - _userPasswordOut = dictionary.getString(PdfDictionaryProperties.u)!.data; - _ownerPasswordOut = dictionary.getString(PdfDictionaryProperties.o)!.data; + _userEncryptionKeyOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.ue)!.data!, + ); + _ownerEncryptionKeyOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.oe)!.data!, + ); + _permissionFlag = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.perms)!.data!, + ); + } + _userPasswordOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.u)!.data!, + ); + _ownerPasswordOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.o)!.data!, + ); keyLength = dictionary.containsKey(PdfDictionaryProperties.length) ? dictionary.getInt(PdfDictionaryProperties.length) : (keySize == 1 ? 40 : (keySize == 2 ? 128 : 256)); + if (keyLength == 128 && _revisionNumberOut! < 4) { keySize = 2; encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; @@ -891,7 +1006,7 @@ class PdfEncryptor { if (value & 0x000800 > 0) { _permissions!.add(PdfPermissionsFlags.fullQualityPrint); } - if (permissions.isEmpty) { + if (_permissions!.isEmpty) { _permissions!.add(PdfPermissionsFlags.none); } } @@ -899,9 +1014,9 @@ class PdfEncryptor { /// internal method bool checkPassword(String password, PdfString key, bool attachEncryption) { bool result = false; - final List? fileId = - _randomBytes != null ? List.from(_randomBytes!) : _randomBytes; - _randomBytes = List.from(key.data!); + final Uint8List? fileId = _randomBytes; + _randomBytes = Uint8List.fromList(key.data!); + if (_authenticateOwnerPassword(password)) { _ownerPassword = password; result = true; @@ -913,6 +1028,7 @@ class PdfEncryptor { } else { _encryptionKey = null; } + if (!result) { _randomBytes = fileId; } @@ -939,17 +1055,17 @@ class PdfEncryptor { return _authenticate256BitOwnerPassword(password); } else { _encryptionKey = _getKeyFromOwnerPassword(password); - List? buff = _ownerPasswordOut; + Uint8List? buff = _ownerPasswordOut; if (revisionNumber == 2) { buff = _encryptDataByCustom( buff!, - _encryptionKey, + _encryptionKey!, _encryptionKey!.length, ); } else if (revisionNumber! > 2) { buff = _ownerPasswordOut; for (int i = 0; i < _ownerLoopNum2!; ++i) { - final List currKey = _getKeyWithOwnerPassword( + final Uint8List currKey = _getKeyWithOwnerPassword( _encryptionKey!, _ownerLoopNum2! - i - 1, ); @@ -968,100 +1084,57 @@ class PdfEncryptor { } } - String _convertToPassword(List array) { - String result; + String _convertToPassword(Uint8List array) { int length = array.length; for (int i = 0; i < length; ++i) { - if (array[i] == paddingBytes![0]) { - if (i < length - 1 && array[i + 1] == paddingBytes![1]) { + if (array[i] == _paddingBytes![0]) { + if (i < length - 1 && array[i + 1] == _paddingBytes![1]) { length = i; break; } } } - result = PdfString.byteToString(array, length); - return result; + return PdfString.byteToString(array, length); } bool _authenticate256BitUserPassword(String password) { - final List userValidationSalt = List.filled(8, 0, growable: true); - final List userKeySalt = List.filled(8, 0, growable: true); - final List hashProvided = List.filled(32, 0, growable: true); - _userRandomBytes = List.filled(16, 0, growable: true); - List hash; - final List userPassword = utf8.encode(password); + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + final Uint8List hashProvided = Uint8List(32); + _userRandomBytes = Uint8List(16); + + final Uint8List userPassword = Uint8List.fromList(utf8.encode(password)); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - List.copyRange(hashProvided, 0, _userPasswordOut!, 0, 32); - List.copyRange(userValidationSalt, 0, _userPasswordOut!, 32, 40); - final List combinedUserpassword = List.filled( - userPassword.length + userValidationSalt.length, - 0, - growable: true, - ); - List.copyRange( - combinedUserpassword, - 0, + hashProvided.setRange(0, 32, _userPasswordOut!); + userValidationSalt.setRange(0, 8, _userPasswordOut!, 32); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(userPassword); + combinedBuilder.add(userValidationSalt); + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), userPassword, - 0, - userPassword.length, - ); - List.copyRange( - combinedUserpassword, - userPassword.length, - userValidationSalt, - 0, - userValidationSalt.length, + null, ); - hash = _acrobatXComputeHash(combinedUserpassword, userPassword, null); _advanceXUserFileEncryptionKey(password); return _compareByteArrays(hash, hashProvided); } else { - List.copyRange( - hashProvided, - 0, - _userPasswordOut!, - 0, - hashProvided.length, - ); - List.copyRange(_userRandomBytes!, 0, _userPasswordOut!, 32, 48); - List.copyRange( - userValidationSalt, - 0, - _userRandomBytes!, - 0, - userValidationSalt.length, - ); - List.copyRange( - userKeySalt, - 0, - _userRandomBytes!, - userValidationSalt.length, - userKeySalt.length + userValidationSalt.length, - ); - hash = List.filled( - userPassword.length + userValidationSalt.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, userPassword, 0, userPassword.length); - List.copyRange( - hash, - userPassword.length, - userValidationSalt, - 0, - userValidationSalt.length, + hashProvided.setRange(0, 32, _userPasswordOut!); + _userRandomBytes!.setRange(0, 16, _userPasswordOut!, 32); + userValidationSalt.setRange(0, 8, _userRandomBytes!); + userKeySalt.setRange(0, 8, _userRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPassword); + hashBuilder.add(userValidationSalt); + + final Uint8List hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, ); - final List hashFound = sha256.convert(hash).bytes; - bool bEqual = false; - if (hashFound.length == hashProvided.length) { - int i = 0; - while ((i < hashFound.length) && (hashFound[i] == hashProvided[i])) { - i += 1; - } - if (i == hashFound.length) { - bEqual = true; - } - } + final bool bEqual = _compareByteArrays(hashFound, hashProvided); + if (bEqual) { _findFileEncryptionKey(password); } @@ -1070,59 +1143,37 @@ class PdfEncryptor { } bool _authenticate256BitOwnerPassword(String password) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerKeySalt = List.filled(8, 0, growable: true); - final List hashProvided = List.filled(32, 0, growable: true); - _ownerRandomBytes = List.filled(16, 0, growable: true); - List hash; - bool oEqual = false; - final List ownerPassword = utf8.encode(password); + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + final Uint8List hashProvided = Uint8List(32); + _ownerRandomBytes = Uint8List(16); + + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - List.copyRange(hashProvided, 0, _ownerPasswordOut!, 0, 32); - List.copyRange(ownerValidationSalt, 0, _ownerPasswordOut!, 32, 40); - int userKeyLength = 48; - if (_userPasswordOut!.length < 48) { - userKeyLength = _userPasswordOut!.length; - } - final List mixedOwnerPassword = List.filled( - ownerPassword.length + ownerValidationSalt.length + userKeyLength, - 0, - growable: true, - ); - List.copyRange( - mixedOwnerPassword, - 0, - ownerPassword, - 0, - ownerPassword.length, - ); - List.copyRange( - mixedOwnerPassword, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - mixedOwnerPassword, - ownerPassword.length + ownerValidationSalt.length, - _userPasswordOut!, - 0, - userKeyLength, + hashProvided.setRange(0, 32, _ownerPasswordOut!); + ownerValidationSalt.setRange(0, 8, _ownerPasswordOut!, 32); + + final int userKeyLength = math.min(48, _userPasswordOut!.length); + + final BytesBuilder mixedBuilder = BytesBuilder(copy: false); + mixedBuilder.add(ownerPassword); + mixedBuilder.add(ownerValidationSalt); + mixedBuilder.add( + Uint8List.view(_userPasswordOut!.buffer, 0, userKeyLength), ); - hash = _acrobatXComputeHash( - mixedOwnerPassword, + + final Uint8List hash = _acrobatXComputeHash( + mixedBuilder.toBytes(), ownerPassword, _userPasswordOut, ); + _acrobatXOwnerFileEncryptionKey(password); - oEqual = _compareByteArrays(hash, hashProvided); - if (oEqual == true) { - final List? ownerRandom = _fileEncryptionKey; + final bool oEqual = _compareByteArrays(hash, hashProvided); + + if (oEqual) { + final Uint8List? ownerRandom = _fileEncryptionKey; final String userPassword = password; _ownerRandomBytes = null; if (_authenticateUserPassword(userPassword)) { @@ -1136,65 +1187,25 @@ class PdfEncryptor { } return oEqual; } else { - final List userPasswordOut = List.filled(48, 0, growable: true); - List.copyRange(userPasswordOut, 0, _userPasswordOut!, 0, 48); - List.copyRange( - hashProvided, - 0, - _ownerPasswordOut!, - 0, - hashProvided.length, + final Uint8List userPasswordOut = Uint8List(48); + userPasswordOut.setRange(0, 48, _userPasswordOut!); + hashProvided.setRange(0, 32, _ownerPasswordOut!); + _ownerRandomBytes!.setRange(0, 16, _ownerPasswordOut!, 32); + ownerValidationSalt.setRange(0, 8, _ownerRandomBytes!); + ownerKeySalt.setRange(0, 8, _ownerRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPassword); + hashBuilder.add(ownerValidationSalt); + hashBuilder.add(userPasswordOut); + + final Uint8List hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, ); - List.copyRange(_ownerRandomBytes!, 0, _ownerPasswordOut!, 32, 48); - List.copyRange( - ownerValidationSalt, - 0, - _ownerRandomBytes!, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - ownerKeySalt, - 0, - _ownerRandomBytes!, - ownerValidationSalt.length, - ownerKeySalt.length, - ); - hash = List.filled( - ownerPassword.length + - ownerValidationSalt.length + - userPasswordOut.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - hash, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - hash, - ownerPassword.length + ownerValidationSalt.length, - userPasswordOut, - 0, - userPasswordOut.length, - ); - final List hashFound = sha256.convert(hash).bytes; - bool bEqual = false; - if (hashFound.length == hashProvided.length) { - int i = 0; - while ((i < hashFound.length) && (hashFound[i] == hashProvided[i])) { - i += 1; - } - if (i == hashFound.length) { - bEqual = true; - } - } + final bool bEqual = _compareByteArrays(hashFound, hashProvided); + _findFileEncryptionKey(password); - if (bEqual == true) { + if (bEqual) { _ownerRandomBytes = null; final String userPassword = password; if (_authenticateUserPassword(userPassword)) { @@ -1209,190 +1220,97 @@ class PdfEncryptor { } void _findFileEncryptionKey(String password) { - List hash; - late List hashFound; - List? forDecryption; + late Uint8List hashFound; + Uint8List? forDecryption; + if (_ownerRandomBytes != null) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerKeySalt = List.filled(8, 0, growable: true); - final List ownerPassword = utf8.encode(password); - final List userPasswordOut = List.filled(48, 0, growable: true); - List.copyRange(userPasswordOut, 0, _userPasswordOut!, 0, 48); - List.copyRange(ownerValidationSalt, 0, _ownerRandomBytes!, 0, 8); - List.copyRange(ownerKeySalt, 0, _ownerRandomBytes!, 8, 16); - hash = List.filled( - ownerPassword.length + - ownerValidationSalt.length + - userPasswordOut.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - hash, - ownerPassword.length, - ownerKeySalt, - 0, - ownerKeySalt.length, + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + final Uint8List userPasswordOut = Uint8List(48); + + userPasswordOut.setRange(0, 48, _userPasswordOut!); + ownerValidationSalt.setRange(0, 8, _ownerRandomBytes!); + ownerKeySalt.setRange(0, 8, _ownerRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPassword); + hashBuilder.add(ownerKeySalt); + hashBuilder.add(userPasswordOut); + + hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, ); - List.copyRange( - hash, - ownerPassword.length + ownerValidationSalt.length, - userPasswordOut, - 0, - userPasswordOut.length, - ); - hashFound = sha256.convert(hash).bytes; forDecryption = _ownerEncryptionKeyOut; } else if (_userRandomBytes != null) { - final List userValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List userKeySalt = List.filled(8, 0, growable: true); - final List userPassword = utf8.encode(password); - List.copyRange(userValidationSalt, 0, _userRandomBytes!, 0, 8); - List.copyRange(userKeySalt, 0, _userRandomBytes!, 8, 16); - hash = List.filled( - userPassword.length + userKeySalt.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, userPassword, 0, userPassword.length); - List.copyRange( - hash, - userPassword.length, - userKeySalt, - 0, - userKeySalt.length, + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + final Uint8List userPassword = Uint8List.fromList(utf8.encode(password)); + + userValidationSalt.setRange(0, 8, _userRandomBytes!); + userKeySalt.setRange(0, 8, _userRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPassword); + hashBuilder.add(userKeySalt); + + hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, ); - hashFound = sha256.convert(hash).bytes; forDecryption = _userEncryptionKeyOut; } + _fileEncryptionKey = AesCipherNoPadding( false, - KeyParameter(Uint8List.fromList(hashFound)), - ).process(Uint8List.fromList(forDecryption!)); - } - - bool _compareByteArrays(List array1, List? array2, [int? size]) { - bool result = true; - if (size == null) { - if (array2 == null) { - result = array1 == array2; - } else if (array1.length != array2.length) { - result = false; - } else { - for (int i = 0; i < array1.length; ++i) { - if (array1[i] != array2[i]) { - result = false; - break; - } - } - } - } else { - if (array2 == null) { - result = array1 == array2; - } else if (array1.length < size || array2.length < size) { - throw ArgumentError.value( - 'Size of one of the arrays are less then requisted size.', - ); - } else if (array1.length != array2.length) { - result = false; - } else { - for (int i = 0; i < size; ++i) { - if (array1[i] != array2[i]) { - result = false; - break; - } - } - } - } - return result; + KeyParameter(hashFound), + ).process(forDecryption!); } void _acrobatXOwnerFileEncryptionKey(String password) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerPassword = utf8.encode(password); - List.copyRange(ownerValidationSalt, 0, _ownerPasswordOut!, 40, 48); - int userKeyLength = 48; - if (_userPasswordOut!.length < 48) { - userKeyLength = _userPasswordOut!.length; - } - final List combinedPassword = List.filled( - ownerPassword.length + ownerValidationSalt.length + userKeyLength, - 0, - growable: true, - ); - List.copyRange(combinedPassword, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - combinedPassword, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - combinedPassword, - ownerPassword.length + ownerValidationSalt.length, - _userPasswordOut!, - 0, - userKeyLength, + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + ownerValidationSalt.setRange(0, 8, _ownerPasswordOut!, 40); + + final int userKeyLength = math.min(48, _userPasswordOut!.length); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(ownerPassword); + combinedBuilder.add(ownerValidationSalt); + combinedBuilder.add( + Uint8List.view(_userPasswordOut!.buffer, 0, userKeyLength), ); - final List hash = _acrobatXComputeHash( - combinedPassword, + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), ownerPassword, _userPasswordOut, ); - final List fileEncryptionKey = List.from(_ownerEncryptionKeyOut!); + _fileEncryptionKey = AesCipherNoPadding( false, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(fileEncryptionKey)); + KeyParameter(hash), + ).process(_ownerEncryptionKeyOut!); } void _advanceXUserFileEncryptionKey(String password) { - final List userKeySalt = List.filled(8, 0, growable: true); - List.copyRange(userKeySalt, 0, _userPasswordOut!, 40, 48); - final List userpassword = utf8.encode(password); - final List combinedUserPassword = List.filled( - userpassword.length + userKeySalt.length, - 0, - growable: true, - ); - List.copyRange( - combinedUserPassword, - 0, - userpassword, - 0, - userpassword.length, - ); - List.copyRange( - combinedUserPassword, - userpassword.length, - userKeySalt, - 0, - userKeySalt.length, - ); - final List hash = _acrobatXComputeHash( - combinedUserPassword, + final Uint8List userKeySalt = Uint8List(8); + userKeySalt.setRange(0, 8, _userPasswordOut!, 40); + final Uint8List userpassword = Uint8List.fromList(utf8.encode(password)); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(userpassword); + combinedBuilder.add(userKeySalt); + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), userpassword, null, ); - final List fileEncryptionKey = List.from(_userEncryptionKeyOut!); + _fileEncryptionKey = AesCipherNoPadding( false, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(fileEncryptionKey)); + KeyParameter(hash), + ).process(_userEncryptionKeyOut!); } /// internal method @@ -1413,12 +1331,14 @@ class PdfEncryptor { dictionary[PdfDictionaryProperties.o] = PdfString.fromBytes( ownerPasswordOut, ); + if (dictionary.containsKey(PdfDictionaryProperties.length)) { keyLength = 0; } dictionary[PdfDictionaryProperties.length] = PdfNumber( _getKeyLength()! * 8, ); + const bool isAes4Dict = false; if (encryptAttachmentOnly! && (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || @@ -1428,6 +1348,7 @@ class PdfEncryptor { 'Encrypt only attachment is supported in AES algorithm with 128, 256 and 256Revision6 encryptions only.', ); } + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { @@ -1440,6 +1361,7 @@ class PdfEncryptor { dictionary[PdfDictionaryProperties.v] = PdfNumber(5); dictionary[PdfDictionaryProperties.r] = PdfNumber(5); } + if (encryptAttachmentOnly!) { dictionary[PdfDictionaryProperties.stmF] = PdfName( PdfDictionaryProperties.identity, @@ -1464,6 +1386,7 @@ class PdfEncryptor { dictionary.remove(PdfDictionaryProperties.eff); } } + if (!encryptOnlyMetadata!) { if (!dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( @@ -1475,6 +1398,7 @@ class PdfEncryptor { dictionary.remove(PdfDictionaryProperties.encryptMetadata); } } + dictionary[PdfDictionaryProperties.cf] = _getCryptFilterDictionary(); if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { @@ -1506,112 +1430,7 @@ class PdfEncryptor { /// internal method Future saveToDictionaryAsync(PdfDictionary dictionary) async { - if (changed!) { - _revisionNumberOut = 0; - _versionNumberOut = 0; - _revision = 0; - keyLength = 0; - } - dictionary[PdfDictionaryProperties.filter] = PdfName( - PdfDictionaryProperties.standard, - ); - dictionary[PdfDictionaryProperties.p] = PdfNumber(_permissionValue!); - dictionary[PdfDictionaryProperties.u] = PdfString.fromBytes( - userPasswordOut, - ); - dictionary[PdfDictionaryProperties.o] = PdfString.fromBytes( - ownerPasswordOut, - ); - if (dictionary.containsKey(PdfDictionaryProperties.length)) { - keyLength = 0; - } - dictionary[PdfDictionaryProperties.length] = PdfNumber( - _getKeyLength()! * 8, - ); - const bool isAes4Dict = false; - if (encryptAttachmentOnly! && - (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit)) { - throw ArgumentError.value( - encryptionAlgorithm, - 'Encrypt only attachment is supported in AES algorithm with 128, 256 and 256Revision6 encryptions only.', - ); - } - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.r] = PdfNumber(_getKeySize() + 3); - dictionary[PdfDictionaryProperties.v] = PdfNumber(_getKeySize() + 3); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(6); - } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(5); - } - if (encryptAttachmentOnly!) { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.eff] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } else { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - if (dictionary.containsKey(PdfDictionaryProperties.eff)) { - dictionary.remove(PdfDictionaryProperties.eff); - } - } - if (!encryptOnlyMetadata!) { - if (!dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } - } else if (!encryptOnlyAttachment) { - if (dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary.remove(PdfDictionaryProperties.encryptMetadata); - } - } - dictionary[PdfDictionaryProperties.cf] = - await _getCryptFilterDictionaryAsync(); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.ue] = PdfString.fromBytes( - _userEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.oe] = PdfString.fromBytes( - _ownerEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.perms] = PdfString.fromBytes( - _permissionFlag, - ); - } - } else { - dictionary[PdfDictionaryProperties.r] = PdfNumber( - (_revisionNumberOut! > 0 && !isAes4Dict) - ? _revisionNumberOut! - : (_getKeySize() + 2), - ); - dictionary[PdfDictionaryProperties.v] = PdfNumber( - (_versionNumberOut! > 0 && !isAes4Dict) - ? _versionNumberOut! - : (_getKeySize() + 1), - ); - } - dictionary.archive = false; - return dictionary; + return saveToDictionary(dictionary); } PdfDictionary _getCryptFilterDictionary() { @@ -1644,54 +1463,12 @@ class PdfEncryptor { ); } standardCryptFilter[PdfDictionaryProperties.length] = PdfNumber( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) + (encryptionAlgorithm! == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm! == + PdfEncryptionAlgorithm.aesx256BitRevision6) ? _key256! - : ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? _key128! - : 128), - ); - final PdfDictionary cryptFilterDictionary = PdfDictionary(); - cryptFilterDictionary[PdfDictionaryProperties.stdCF] = standardCryptFilter; - return cryptFilterDictionary; - } - - Future _getCryptFilterDictionaryAsync() async { - final PdfDictionary standardCryptFilter = PdfDictionary(); - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.cfm)) { - if (encryptAttachmentOnly!) { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - PdfDictionaryProperties.aesv2, - ); - standardCryptFilter[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.cryptFilter, - ); - } else { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6) - ? PdfDictionaryProperties.aesv3 - : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? 'V2' - : PdfDictionaryProperties.aesv2, - ); - } - } - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { - standardCryptFilter[PdfDictionaryProperties.authEvent] = PdfName( - encryptAttachmentOnly! - ? PdfDictionaryProperties.efOpen - : PdfDictionaryProperties.docOpen, - ); - } - standardCryptFilter[PdfDictionaryProperties.length] = PdfNumber( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) - ? _key256! - : ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) + : ((encryptionAlgorithm! == PdfEncryptionAlgorithm.aesx128Bit || + encryptionAlgorithm! == PdfEncryptionAlgorithm.rc4x128Bit) ? _key128! : 128), ); @@ -1702,9 +1479,9 @@ class PdfEncryptor { int _getPermissionValue(List permissionFlags) { int defaultValue = 0; - permissionFlags.toList().forEach((PdfPermissionsFlags flag) { + for (final PdfPermissionsFlags flag in permissionFlags) { defaultValue |= _permissionFlagValues![flag.index]; - }); + } return defaultValue; } @@ -1731,10 +1508,9 @@ class PdfEncryptor { return result; } - /// internal method - List encryptData( + Uint8List encryptData( int? currentObjectNumber, - List data, + Uint8List data, bool isEncryption, ) { if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || @@ -1743,19 +1519,16 @@ class PdfEncryptor { ? _aesEncrypt(data, _fileEncryptionKey!) : _aesDecrypt(data, _fileEncryptionKey); } + _initializeData(); const int genNumber = 0; - int keyLen = 0; - List newKey; + int keyLen; + Uint8List newKey; + if (_encryptionKey!.length == 5) { - newKey = List.filled( - _encryptionKey!.length + _newKeyOffset!, - 0, - growable: true, - ); - for (int i = 0; i < _encryptionKey!.length; ++i) { - newKey[i] = _encryptionKey![i]; - } + newKey = Uint8List(_encryptionKey!.length + _newKeyOffset!); + newKey.setRange(0, _encryptionKey!.length, _encryptionKey!); + int j = _encryptionKey!.length - 1; newKey[++j] = currentObjectNumber!.toUnsigned(8); newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); @@ -1765,47 +1538,50 @@ class PdfEncryptor { keyLen = newKey.length; newKey = _prepareKeyForEncryption(newKey); } else { - newKey = List.filled( - _encryptionKey!.length + - ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6 || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) - ? 9 - : 5), - 0, - growable: true, - ); - List.copyRange(newKey, 0, _encryptionKey!, 0, _encryptionKey!.length); + final int additionalBytes = + (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == + PdfEncryptionAlgorithm.aesx256BitRevision6 || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) + ? 9 + : 5; + + newKey = Uint8List(_encryptionKey!.length + additionalBytes); + newKey.setRange(0, _encryptionKey!.length, _encryptionKey!); + int j = _encryptionKey!.length - 1; newKey[++j] = currentObjectNumber!.toUnsigned(8); newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); newKey[++j] = (currentObjectNumber >> 16).toUnsigned(8); newKey[++j] = genNumber.toUnsigned(8); newKey[++j] = (genNumber >> 8).toUnsigned(8); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { - newKey[++j] = 0x73.toUnsigned(8); - newKey[++j] = 0x41.toUnsigned(8); - newKey[++j] = 0x6c.toUnsigned(8); - newKey[++j] = 0x54.toUnsigned(8); + newKey[++j] = 0x73; + newKey[++j] = 0x41; + newKey[++j] = 0x6c; + newKey[++j] = 0x54; } - newKey = md5.convert(newKey).bytes; + + newKey = Uint8List.fromList(md5.convert(newKey).bytes); keyLen = newKey.length; } - keyLen = min(keyLen, newKey.length); + + keyLen = math.min(keyLen, newKey.length); if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { return isEncryption - ? _aesEncrypt(data, encryptOnlyAttachment ? _encryptionKey! : newKey) - : _aesDecrypt(data, encryptOnlyAttachment ? _encryptionKey : newKey); + ? _aesEncrypt(data, encryptAttachmentOnly! ? _encryptionKey! : newKey) + : _aesDecrypt(data, encryptAttachmentOnly! ? _encryptionKey : newKey); } return _encryptDataByCustom(data, newKey, keyLen); } - List _aesEncrypt(List data, List key) { + Uint8List _aesEncrypt(Uint8List data, Uint8List key) { if (key.isEmpty) { return data; } - final iv = Uint8List(16); + + final Uint8List iv = Uint8List(16); final Random random = Random.secure(); for (int i = 0; i < iv.length; i++) { iv[i] = random.nextInt(256); @@ -1818,30 +1594,29 @@ class PdfEncryptor { final params = BlockCipherPaddedParameters( - InvalidParameter(KeyParameter(Uint8List.fromList(key)), iv), + InvalidParameter(KeyParameter(key), iv), null, ); cipher.initialize(true, params); try { - final encrypted = cipher.process(Uint8List.fromList(data)); - final results = Uint8List(iv.length + encrypted.length); + final Uint8List encrypted = cipher.process(data); + final Uint8List results = Uint8List(iv.length + encrypted.length); results.setRange(0, iv.length, iv); results.setRange(iv.length, results.length, encrypted); - return results; } catch (e) { - return []; + return Uint8List(0); } } - List _aesDecrypt(List data, List? key) { + Uint8List _aesDecrypt(Uint8List data, Uint8List? key) { if (key == null || key.isEmpty || data.length < 16) { return data; } - final ivBytes = Uint8List.fromList(data.take(16).toList()); - final encryptedData = Uint8List.fromList(data.skip(16).toList()); + final Uint8List ivBytes = Uint8List.view(data.buffer, 0, 16); + final Uint8List encryptedData = Uint8List.view(data.buffer, 16); final cipher = PaddedCipherMode( Pkcs7Padding(), @@ -1850,7 +1625,7 @@ class PdfEncryptor { final params = BlockCipherPaddedParameters( - InvalidParameter(KeyParameter(Uint8List.fromList(key)), ivBytes), + InvalidParameter(KeyParameter(key), ivBytes), null, ); @@ -1858,7 +1633,7 @@ class PdfEncryptor { try { return cipher.process(encryptedData); } catch (e) { - return []; + return Uint8List(0); } } @@ -1876,71 +1651,91 @@ class PdfEncryptor { } } - List _prepareKeyForEncryption(List originalKey) { + Uint8List _prepareKeyForEncryption(Uint8List originalKey) { final int keyLen = originalKey.length; - final List newKey = md5.convert(originalKey).bytes; + final Uint8List newKey = Uint8List.fromList(md5.convert(originalKey).bytes); + if (keyLen > _randomBytesAmount!) { - final int newKeyLength = min( + final int newKeyLength = math.min( _getKeyLength()! + _newKeyOffset!, _randomBytesAmount!, ); - final List result = List.filled( - newKeyLength, - 0, - growable: true, - ); - List.copyRange(result, 0, newKey, 0, newKeyLength); + final Uint8List result = Uint8List(newKeyLength); + result.setRange(0, newKeyLength, newKey); return result; } else { return newKey; } } - /// internal method PdfEncryptor clone() { final PdfEncryptor encryptor = PdfEncryptor() - .._stringLength = _cloneInt(_stringLength) - .._revisionNumber40Bit = _cloneInt(_revisionNumber40Bit) - .._revisionNumber128Bit = _cloneInt(_revisionNumber128Bit) - .._ownerLoopNum2 = _cloneInt(_ownerLoopNum2) - .._ownerLoopNum = _cloneInt(_ownerLoopNum) - ..paddingBytes = _cloneList(paddingBytes) - .._bytesAmount = _cloneInt(_bytesAmount) - .._permissionSet = _cloneInt(_permissionSet) - .._permissionCleared = _cloneInt(_permissionCleared) - .._permissionRevisionTwoMask = _cloneInt(_permissionRevisionTwoMask) - .._revisionNumberOut = _cloneInt(_revisionNumberOut) - .._versionNumberOut = _cloneInt(_versionNumberOut) - .._permissionValue = _cloneInt(_permissionValue) - .._randomBytes = _cloneList(_randomBytes) - .._key40 = _cloneInt(_key40) - .._key128 = _cloneInt(_key128) - .._key256 = _cloneInt(_key256) - .._randomBytesAmount = _cloneInt(_randomBytesAmount) - .._newKeyOffset = _cloneInt(_newKeyOffset) - ..isEncrypt = _cloneBool(isEncrypt) - ..changed = _cloneBool(changed) - ..hasComputedPasswordValues = _cloneBool(hasComputedPasswordValues) - .._revision = _cloneInt(_revision) - .._ownerPasswordOut = _cloneList(_ownerPasswordOut) - .._userPasswordOut = _cloneList(_userPasswordOut) - .._encryptionKey = _cloneList(_encryptionKey) - ..keyLength = _cloneInt(keyLength) - ..customArray = _cloneList(customArray) - .._permissionFlagValues = _cloneList(_permissionFlagValues) - .._fileEncryptionKey = _cloneList(_fileEncryptionKey) - .._userEncryptionKeyOut = _cloneList(_userEncryptionKeyOut) - .._ownerEncryptionKeyOut = _cloneList(_ownerEncryptionKeyOut) - .._permissionFlag = _cloneList(_permissionFlag) - .._userRandomBytes = _cloneList(_userRandomBytes) - .._ownerRandomBytes = _cloneList(_ownerRandomBytes) - ..encryptOnlyMetadata = _cloneBool(encryptOnlyMetadata) - ..encryptAttachmentOnly = _cloneBool(encryptAttachmentOnly) + .._stringLength = _stringLength + .._revisionNumber40Bit = _revisionNumber40Bit + .._revisionNumber128Bit = _revisionNumber128Bit + .._ownerLoopNum2 = _ownerLoopNum2 + .._ownerLoopNum = _ownerLoopNum + .._bytesAmount = _bytesAmount + .._permissionSet = _permissionSet + .._permissionCleared = _permissionCleared + .._permissionRevisionTwoMask = _permissionRevisionTwoMask + .._revisionNumberOut = _revisionNumberOut + .._versionNumberOut = _versionNumberOut + .._permissionValue = _permissionValue + .._key40 = _key40 + .._key128 = _key128 + .._key256 = _key256 + .._randomBytesAmount = _randomBytesAmount + .._newKeyOffset = _newKeyOffset + ..isEncrypt = isEncrypt + ..changed = changed + ..hasComputedPasswordValues = hasComputedPasswordValues + .._revision = _revision + ..keyLength = keyLength + ..encryptOnlyMetadata = encryptOnlyMetadata + ..encryptAttachmentOnly = encryptAttachmentOnly ..encryptionAlgorithm = encryptionAlgorithm .._userPassword = _userPassword .._ownerPassword = _ownerPassword - ..encryptionOptions = encryptionOptions; + ..encryptionOptions = encryptionOptions + .._permissionFlagValues = _cloneList(_permissionFlagValues); + + encryptor._paddingBytes = + _paddingBytes != null ? Uint8List.fromList(_paddingBytes!) : null; + encryptor._randomBytes = + _randomBytes != null ? Uint8List.fromList(_randomBytes!) : null; + encryptor._ownerPasswordOut = + _ownerPasswordOut != null + ? Uint8List.fromList(_ownerPasswordOut!) + : null; + encryptor._userPasswordOut = + _userPasswordOut != null ? Uint8List.fromList(_userPasswordOut!) : null; + encryptor._encryptionKey = + _encryptionKey != null ? Uint8List.fromList(_encryptionKey!) : null; + encryptor.customArray = + customArray != null ? Uint8List.fromList(customArray!) : null; + encryptor._fileEncryptionKey = + _fileEncryptionKey != null + ? Uint8List.fromList(_fileEncryptionKey!) + : null; + encryptor._userEncryptionKeyOut = + _userEncryptionKeyOut != null + ? Uint8List.fromList(_userEncryptionKeyOut!) + : null; + encryptor._ownerEncryptionKeyOut = + _ownerEncryptionKeyOut != null + ? Uint8List.fromList(_ownerEncryptionKeyOut!) + : null; + encryptor._permissionFlag = + _permissionFlag != null ? Uint8List.fromList(_permissionFlag!) : null; + encryptor._userRandomBytes = + _userRandomBytes != null ? Uint8List.fromList(_userRandomBytes!) : null; + encryptor._ownerRandomBytes = + _ownerRandomBytes != null + ? Uint8List.fromList(_ownerRandomBytes!) + : null; + encryptor._permissions = _permissions != null ? List.generate( @@ -1948,27 +1743,8 @@ class PdfEncryptor { (int i) => _permissions![i], ) : null; - return encryptor; - } - - bool? _cloneBool(bool? value) { - if (value != null) { - if (value) { - return true; - } else { - return false; - } - } else { - return null; - } - } - int? _cloneInt(int? value) { - if (value != null) { - return value; - } else { - return null; - } + return encryptor; } List? _cloneList(List? value) { diff --git a/packages/syncfusion_flutter_pdf/pubspec.yaml b/packages/syncfusion_flutter_pdf/pubspec.yaml index 827da5db3..9c555ed01 100644 --- a/packages/syncfusion_flutter_pdf/pubspec.yaml +++ b/packages/syncfusion_flutter_pdf/pubspec.yaml @@ -1,22 +1,19 @@ name: syncfusion_flutter_pdf description: The Flutter PDF is a library written natively in Dart for creating, reading, editing, and securing PDF files in Android, iOS, and web platforms. -version: 30.1.37 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_pdf environment: - sdk: ^3.7.0-0 + sdk: ^3.7.0 + flutter: '>=3.35.1' dependencies: flutter: sdk: flutter intl: '>=0.18.0 <0.21.0' xml: ">=6.5.0 <7.0.0" - syncfusion_flutter_core: - path: ../syncfusion_flutter_core - - crypto: ">=3.0.0 <4.0.0" convert: ">=3.0.0 <4.0.0" http: ^1.2.1 - - + syncfusion_flutter_core: + path: ../syncfusion_flutter_core diff --git a/packages/syncfusion_flutter_pdfviewer/CHANGELOG.md b/packages/syncfusion_flutter_pdfviewer/CHANGELOG.md index 7ce0ced74..956801a21 100644 --- a/packages/syncfusion_flutter_pdfviewer/CHANGELOG.md +++ b/packages/syncfusion_flutter_pdfviewer/CHANGELOG.md @@ -1,5 +1,101 @@ ## Unreleased +* No changes. + +## [31.2.15] - 11/25/2025 + +* No changes. + +## [31.2.12] - 11/18/2025 + +* No changes. + +## [31.2.10] - 11/12/2025 + +* No changes. + +## [31.2.5] - 11/04/2025 + +**Bugs** + +* Now, in the `SfPdfViewer` widget, exceptions that occur while switching PDF documents are handled through the `onDocumentLoadFailed` callback. + +## [31.2.4] - 10/28/2025 + +* No changes. + +## [31.2.3] - 10/22/2025 + +**Bugs** + +* Now, in the `SfPdfViewer` widget, sticky note annotations can be added and selected using a stylus on Android devices. + +**General** + +* Updated the Android configuration to support Google Play's 16KB memory page size requirement. + +## [31.2.2] - 10/15/2025 + +**Features** + +* Improved document loading performance across all platforms: 39% on Windows, 35% on Android, 23% on Web platform, 19% on macOS, 34% on iOS and 45% on Linux. + +**General** + +* Updated the Android `compileSdkVersion` to 36. + +## [31.1.23] - 10/07/2025 + +* No changes. + +## [31.1.22] - 10/01/2025 + +**General** + +* Upgraded the [`device_info_plus`](https://pub.dev/packages/device_info_plus) package to the latest version `12.1.0`. + +## [31.1.21] - 09/23/2025 + +* No changes. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter PDF Viewer widget has been updated to Flutter SDK 3.35.0. + +**Bugs** + +* Now, in the `SfPdfViewer` widget, hyperlink and document link navigation are restricted while in annotation modes. + +## [31.1.19] - 09/12/2025 + +* No changes. + +## [31.1.18] - 09/10/2025 + +**Breaking changes** + +* Now, in the `SfPdfViewer` widget, the [page number](https://pub.dev/documentation/syncfusion_flutter_pdfviewer/latest/pdfviewer/PdfViewerController/pageNumber.html) API is updated when the page crosses the center of the viewport instead of the top of the viewport. + +## [31.1.17] - 09/05/2025 + +* No changes. + +## [30.2.40] - 08/07/2025 + +**Features** + +* Added support for free space text selection in the `SfPdfViewer` widget, allowing users to extend text selection by dragging over non-text regions within a PDF page. + +## [30.1.40] - 07/15/2025 + +**Bugs** + +* Now, the `SfPdfViewer` widget will not be disposed when a valid page number is entered in the page navigation dialog, provided it is wrapped in a nested navigator. + +## [30.1.37] - 06/25/2025 + **General** * The compatible version of our Flutter PDF Viewer widget has been updated to Flutter SDK 3.32.0. @@ -7,6 +103,9 @@ **Features** * Linux platform support has been provided. + +## [29.2.10] - 06/10/2025 + * Added support for rendering pages using the open-source PDFium library through an optional package (`syncfusion_pdfviewer_android`). **Bugs** @@ -615,4 +714,4 @@ Initial release. * Page navigation - Navigate to the desired pages instantly. * Bookmark navigation - Bookmarks saved in the document are loaded and made ready for easy navigation. This feature helps navigate the topics bookmarked already within the PDF document. * Themes - Easily switch between light and dark themes. -* Localization - All static text within the PDF Viewer can be localized to any supported language. +* Localization - All static text within the PDF Viewer can be localized to any supported language. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdfviewer/android/build.gradle b/packages/syncfusion_flutter_pdfviewer/android/build.gradle index 4d81f8a15..620908eab 100644 --- a/packages/syncfusion_flutter_pdfviewer/android/build.gradle +++ b/packages/syncfusion_flutter_pdfviewer/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.9.1' } } @@ -25,10 +25,15 @@ android { if (project.android.hasProperty("namespace")) { namespace 'com.syncfusion.flutter.pdfviewer' } - compileSdkVersion 31 + compileSdkVersion 36 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } defaultConfig { - minSdkVersion 16 + minSdkVersion 24 } lintOptions { disable 'InvalidPackage' diff --git a/packages/syncfusion_flutter_pdfviewer/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_pdfviewer/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3c472b99c..000000000 --- a/packages/syncfusion_flutter_pdfviewer/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/packages/syncfusion_flutter_pdfviewer/assets/highlight.png b/packages/syncfusion_flutter_pdfviewer/assets/highlight.png deleted file mode 100644 index 684ebd569..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer/assets/highlight.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer/assets/squiggly.png b/packages/syncfusion_flutter_pdfviewer/assets/squiggly.png deleted file mode 100644 index 1bf662e80..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer/assets/squiggly.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer/assets/strikethrough.png b/packages/syncfusion_flutter_pdfviewer/assets/strikethrough.png deleted file mode 100644 index 97b6eee46..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer/assets/strikethrough.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer/assets/underline.png b/packages/syncfusion_flutter_pdfviewer/assets/underline.png deleted file mode 100644 index 727c3cb72..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer/assets/underline.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer/ios/Assets/.gitkeep b/packages/syncfusion_flutter_pdfviewer/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SwiftSyncfusionFlutterPdfViewerPlugin.swift b/packages/syncfusion_flutter_pdfviewer/ios/Classes/SwiftSyncfusionFlutterPdfViewerPlugin.swift deleted file mode 100644 index adef47ef8..000000000 --- a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SwiftSyncfusionFlutterPdfViewerPlugin.swift +++ /dev/null @@ -1,231 +0,0 @@ -import Flutter -import UIKit - - - -// SyncfusionFlutterPdfViewerPlugin -public class SwiftSyncfusionFlutterPdfViewerPlugin: NSObject, FlutterPlugin { - // Document repository - var documentRepo = [String: CGPDFDocument?]() - - let dispatcher = DispatchQueue(label: "syncfusion_flutter_pdfviewer") - - // Registers the SyncfusionFlutterPdfViewerPlugin - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "syncfusion_flutter_pdfviewer", binaryMessenger: registrar.messenger()) - let instance = SwiftSyncfusionFlutterPdfViewerPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - // Invokes the method call operations. - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - if(call.method == "initializePdfRenderer") - { - initializePdfRenderer(call:call,result:result) - } - else if(call.method == "getPage") - { - dispatcher.async { - self.getPage(call:call,result:result) - } - } - else if(call.method == "getTileImage") - { - dispatcher.async { - self.getTileImage(call:call,result:result) - } - } - else if(call.method == "getPagesWidth") - { - getPagesWidth(call:call,result:result) - } - else if(call.method == "getPagesHeight") - { - getPagesHeight(call:call,result:result) - } - else if(call.method == "closeDocument") - { - closeDocument(call:call,result:result) - } - } - - // Initializes the PDF Renderer and returns the page count. - private func initializePdfRenderer( call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let args = argument as? [String: Any] else {return} - guard let documentBytes = args["documentBytes"] as? FlutterStandardTypedData else {return} - guard let documentID = args["documentID"] as? String else {return} - let byte = [UInt8](documentBytes.data) - guard let cfData = CFDataCreate(nil, byte, byte.count) else {return} - guard let dataProvider = CGDataProvider(data: cfData) else {return} - guard let document = CGPDFDocument(dataProvider) else {return} - self.documentRepo[documentID] = document - let pageCount = NSNumber(value: document.numberOfPages) - result(pageCount.stringValue); - } - - private func closeDocument(call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let documentID = argument as? String else {return} - self.documentRepo[documentID] = nil - self.documentRepo.removeValue(forKey: documentID) - } - - // Returns the width collection of rendered pages. - private func getPagesWidth( call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let documentID = argument as? String else {return} - guard let document = self.documentRepo[documentID] else {return} - let pageCount = NSNumber(value: document!.numberOfPages) - var pagesWidth = Array() - for index in stride(from: 1,to: pageCount.intValue + 1, by: 1){ - guard let page = document!.page(at: Int(index)) else {continue} - var pageRect = page.getBoxRect(.cropBox) - if(page.rotationAngle > 0) - { - let angle = CGFloat(page.rotationAngle) * CGFloat.pi/180 - pageRect = (pageRect.applying(CGAffineTransform(rotationAngle: angle))) - } - pagesWidth.append(Double(pageRect.width)) - } - result(pagesWidth) - } - - // Returns the height collection of rendered pages. - private func getPagesHeight( call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let documentID = argument as? String else {return} - guard let document = self.documentRepo[documentID] else { return } - let pageCount = NSNumber(value: document!.numberOfPages) - var pagesHeight = Array() - for index in stride(from: 1,to: pageCount.intValue + 1, by: 1){ - guard let page = document!.page(at: Int(index)) else {continue} - var pageRect = page.getBoxRect(.cropBox) - if(page.rotationAngle > 0) - { - let angle = CGFloat(page.rotationAngle) * CGFloat.pi/180 - pageRect = (pageRect.applying(CGAffineTransform(rotationAngle: angle))) - } - pagesHeight.append(Double(pageRect.height)) - } - result(pagesHeight) - } - - // Gets the image bytes of the specified page from the document at the specified width and height. - private func getPage( call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let args = argument as? [String: Any] else {return} - guard let index = args["index"] as? Int else {return} - guard let width = args["width"] as? Int else {return} - guard let height = args["height"] as? Int else {return} - guard let documentID = args["documentID"] as? String else {return} - guard let image = getImageForPlugin(index: index, width: width, height: height,documentID: documentID) else { - return - } - result(image) - } - - private func getImageForPlugin(index: Int,width:Int, height:Int,documentID: String) -> FlutterStandardTypedData? - { - guard let document = self.documentRepo[documentID] else {return nil} - guard let page = document!.page(at: Int(index)) else {return nil} - let pageRect = page.getBoxRect(.cropBox) - var pageWidth = pageRect.width - var pageHeight = pageRect.height - if(page.rotationAngle == 90 || page.rotationAngle == 270) { - pageWidth = pageRect.height - pageHeight = pageRect.width - } - let imageRect = CGRect(x: 0,y: 0,width: width,height: height) - let scaleX = Double(width) / Double(pageWidth) - let scaleY = Double(height) / Double(pageHeight) - let stride = width * 4 - let bufSize = stride * height; - let buffer = UnsafeMutablePointer.allocate(capacity: bufSize) - buffer.initialize(repeating: 0, count: bufSize) - var rendered = false - let transform = page.getDrawingTransform(.cropBox, rect: CGRect(origin: CGPoint.zero, size: CGSize(width: pageWidth, height: pageHeight)), rotate: 0, preserveAspectRatio: true) - let rgb = CGColorSpaceCreateDeviceRGB() - let context = CGContext(data: buffer, width: width, height: height, bitsPerComponent: 8, bytesPerRow: stride, space: rgb, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) - if context != nil { - context!.setAllowsAntialiasing(true); - context!.translateBy(x: 0, y: 0) - context!.scaleBy(x: scaleX, y: scaleY) - context!.concatenate(transform) - context!.drawPDFPage(page) - rendered = true - } - if(rendered){ - let data = Data(bytesNoCopy: buffer, count: bufSize, deallocator: .free) - return FlutterStandardTypedData(bytes: data) - }else{ - return nil - } - } - - // Gets the pdf page image from the specified page - private func getTileImage( call: FlutterMethodCall, result: @escaping FlutterResult) - { - guard let argument = call.arguments else {return} - guard let args = argument as? [String: Any] else {return} - guard let pageNumber = args["pageNumber"] as? Int else {return} - guard let scale = args["scale"] as? Double else {return} - guard let width = args["width"] as? Double else {return} - guard let height = args["height"] as? Double else {return} - guard let x = args["x"] as? Double else {return} - guard let y = args["y"] as? Double else {return} - - guard let documentID = args["documentID"] as? String else {return} - guard let tileImage = getTileImageForPlugin(pageNumber: pageNumber, scale: CGFloat(scale), - width: width, height: height, x: x, y: y, documentID: documentID) else { - return - } - result(tileImage) - } - - // Gets the image for plugin - private func getTileImageForPlugin(pageNumber: Int, scale: CGFloat, width: Double, height: Double, x: Double, y: Double, documentID: String) -> FlutterStandardTypedData? - { - guard let document = self.documentRepo[documentID] else {return nil} - guard let page = document!.page(at: Int(pageNumber)) else {return nil} - let pageRect = page.getBoxRect(.cropBox) - var pageWidth = pageRect.width - var pageHeight = pageRect.height - if(page.rotationAngle == 90 || page.rotationAngle == 270) { - pageWidth = pageRect.height - pageHeight = pageRect.width - } - let bounds = CGRect(x: -(pageWidth * scale / 2) + (pageWidth / 2) - CGFloat(x), - y: -(pageHeight * scale / 2) + (pageHeight / 2) + CGFloat(y), - width: pageWidth * scale, height: pageHeight * scale) - - let stride = Int(width) * 4 - let bufSize = stride * Int(height); - let buffer = UnsafeMutablePointer.allocate(capacity: bufSize) - buffer.initialize(repeating: 0, count: bufSize) - var rendered = false - let transform = page.getDrawingTransform(.cropBox, rect: CGRect(origin: CGPoint.zero, size: CGSize(width: pageWidth, height: pageHeight)), rotate: 0, preserveAspectRatio: true) - let rgb = CGColorSpaceCreateDeviceRGB() - let context = CGContext(data: buffer, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: stride, space: rgb, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) - if context != nil { - context!.setAllowsAntialiasing(true); - context!.translateBy(x: CGFloat(-x * scale), y: CGFloat(((y * scale) + height) - bounds.height)) - context!.scaleBy(x: scale, y: scale) - context!.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) - context!.fill(bounds) - context!.concatenate(transform) - context!.drawPDFPage(page) - rendered = true - } - if(rendered){ - let data = Data(bytesNoCopy: buffer, count: bufSize, deallocator: .free) - return FlutterStandardTypedData(bytes: data) - }else{ - return nil - } - } -} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.h b/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.h deleted file mode 100644 index dc399fc00..000000000 --- a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface SyncfusionFlutterPdfViewerPlugin : NSObject -@end diff --git a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.m b/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.m deleted file mode 100644 index 1e5837537..000000000 --- a/packages/syncfusion_flutter_pdfviewer/ios/Classes/SyncfusionFlutterPdfViewerPlugin.m +++ /dev/null @@ -1,15 +0,0 @@ -#import "SyncfusionFlutterPdfViewerPlugin.h" -#if __has_include() -#import -#else -// Support project import fallback if the generated compatibility header -// is not copied when this plugin is created as a library. -// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 -#import "syncfusion_flutter_pdfviewer-Swift.h" -#endif - -@implementation SyncfusionFlutterPdfViewerPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftSyncfusionFlutterPdfViewerPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_container.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_container.dart index b4b842d07..729023422 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_container.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_container.dart @@ -69,6 +69,7 @@ class AnnotationContainer extends StatefulWidget { class _AnnotationContainerState extends State { Annotation? _selectedAnnotation; + Size _viewportSize = Size.zero; @override Widget build(BuildContext context) { _selectedAnnotation = widget.selectedAnnotation; @@ -89,47 +90,55 @@ class _AnnotationContainerState extends State { annotations.sort((Annotation a, Annotation b) { return a.zOrder.compareTo(b.zOrder); }); - return Listener( - onPointerUp: (PointerUpEvent details) { - widget.onTap(details.position); + return LayoutBuilder( + builder: (context, constraints) { + if (_viewportSize != constraints.biggest) { + _viewportSize = constraints.biggest; + } + return Listener( + onPointerUp: (PointerUpEvent details) { + widget.onTap(details.position); + }, + child: Stack( + children: [ + for (final Annotation annotation in annotations) + // Annotations with empty annotation bounds will not be rendered in the view. + if (!annotation.boundingBox.isEmpty) + _getPositionedAnnotationView(annotation), + if (_selectedAnnotation != null && + !_selectedAnnotation!.boundingBox.isEmpty && + widget.pageNumber == widget.selectedAnnotation!.pageNumber) + ListenableBuilder( + listenable: Listenable.merge([ + widget.selectedAnnotation!, + _getTypeSettings(_selectedAnnotation!), + _selectedAnnotation!, + ]), + builder: (BuildContext context, Widget? child) { + return _getPositionedAnnotationView(_selectedAnnotation!); + }, + ), + ], + ), + ); }, - child: Stack( - children: [ - for (final Annotation annotation in annotations) - // Annotations with empty annotation bounds will not be rendered in the view. - if (!annotation.boundingBox.isEmpty) - _getPositionedAnnotationView(annotation), - if (_selectedAnnotation != null && - !_selectedAnnotation!.boundingBox.isEmpty && - widget.pageNumber == widget.selectedAnnotation!.pageNumber) - ListenableBuilder( - listenable: Listenable.merge([ - widget.selectedAnnotation!, - _getTypeSettings(_selectedAnnotation!), - _selectedAnnotation!, - ]), - builder: (BuildContext context, Widget? child) { - return _getPositionedAnnotationView(_selectedAnnotation!); - }, - ), - ], - ), ); } Widget _getPositionedAnnotationView(Annotation annotation) { if (annotation is StickyNoteAnnotation) { + final double scaleFactor = _viewportSize.shortestSide >= 600 ? 2 : 1.25; return ListenableBuilder( listenable: annotation, builder: (BuildContext context, Widget? child) { return Positioned( left: annotation.uiBounds.left / widget.heightPercentage, top: annotation.uiBounds.top / widget.heightPercentage, - width: annotation.uiBounds.width / widget.zoomLevel, - height: annotation.uiBounds.height / widget.zoomLevel, + width: annotation.uiBounds.width * scaleFactor / widget.zoomLevel, + height: annotation.uiBounds.height * scaleFactor / widget.zoomLevel, child: Visibility( visible: !widget.isZooming, - child: _getAnnotationView(annotation), + child: _getAnnotationView(annotation, scaleFactor: scaleFactor), ), ); }, @@ -174,7 +183,7 @@ class _AnnotationContainerState extends State { } } - Widget _getAnnotationView(Annotation annotation) { + Widget _getAnnotationView(Annotation annotation, {double scaleFactor = 1}) { Widget? annotationView; if (annotation is HighlightAnnotation || @@ -198,6 +207,7 @@ class _AnnotationContainerState extends State { annotation: annotation, isSelected: annotation == _selectedAnnotation, zoomLevel: widget.zoomLevel, + scaleFactor: scaleFactor, canEdit: !isLocked, selectorColor: isLocked diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_view.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_view.dart index 39b17c1d2..00b1817b9 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_view.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/annotation_view.dart @@ -131,7 +131,10 @@ class RenderInteractiveGraphicsView extends RenderBox { ..onTap = onTap ..onTapDown = onTapDown ..onTapUp = onTapUp - ..onTapCancel = onTapCancel; + ..onTapCancel = onTapCancel + ..gestureSettings = const DeviceGestureSettings( + touchSlop: kTouchSlop / 3, + ); panGestureRecognizer = PanGestureRecognizer() @@ -140,7 +143,9 @@ class RenderInteractiveGraphicsView extends RenderBox { ..onEnd = onDragEnd ..onUpdate = onDragUpdate ..onCancel = onDragCancel - ..gestureSettings = const DeviceGestureSettings(touchSlop: 0.0); + ..gestureSettings = const DeviceGestureSettings( + touchSlop: kTouchSlop / 3, + ); } late Color _color; diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/sticky_notes.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/sticky_notes.dart index 52e8133ad..a0c292352 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/sticky_notes.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/annotation/sticky_notes.dart @@ -134,6 +134,7 @@ class StickyNoteAnnotationView extends InteractiveGraphicsView Color selectorColor = defaultSelectorColor, double selectorStorkeWidth = 1, double zoomLevel = 1, + double scaleFactor = 1, }) : super( key: key, color: annotation.color, @@ -145,11 +146,15 @@ class StickyNoteAnnotationView extends InteractiveGraphicsView selectorStorkeWidth: selectorStorkeWidth, ) { _zoomLevel = zoomLevel; + _scaleFactor = scaleFactor; } /// Zoom level of the pdf page. late final double _zoomLevel; + /// Scale Factor of the pdf page + late final double _scaleFactor; + /// Called when the annotation is moved. final AnnotationMoveEndedCallback? onAnnotationMoved; @@ -172,6 +177,7 @@ class StickyNoteAnnotationView extends InteractiveGraphicsView selectorColor: selectorColor, selectorStorkeWidth: selectorStorkeWidth, zoomLevel: _zoomLevel, + scaleFactor: _scaleFactor, onAnnotationMoved: onAnnotationMoved, onAnnotationMoving: onAnnotationMoving, onDoubleTap: onDoubleTap, @@ -191,7 +197,8 @@ class StickyNoteAnnotationView extends InteractiveGraphicsView ..onAnnotationMoved = onAnnotationMoved ..onAnnotationMoving = onAnnotationMoving .._onDoubleTap = onDoubleTap - .._onTap = onTap; + .._onTap = onTap + .._scaleFactor = _scaleFactor; } super.updateRenderObject(context, renderObject); } @@ -215,6 +222,7 @@ class RenderStickyNoteAnnotationView extends RenderInteractiveGraphicsView { VoidCallback? onTap, void Function()? onDoubleTap, double zoomLevel = 1, + double scaleFactor = 1, }) : _onDoubleTap = onDoubleTap, super( strokeColor: color, @@ -226,20 +234,17 @@ class RenderStickyNoteAnnotationView extends RenderInteractiveGraphicsView { ) { _onTap = onTap; _zoomLevel = zoomLevel; + _scaleFactor = scaleFactor; _selectorStorkeWidth = selectorStorkeWidth; _doubleTapGestureRecognizer = - DoubleTapGestureRecognizer() - ..onDoubleTap = _onDoubleTap - ..gestureSettings = const DeviceGestureSettings(touchSlop: 0.0); - super.tapGestureRecognizer.gestureSettings = const DeviceGestureSettings( - touchSlop: 0.0, - ); + DoubleTapGestureRecognizer()..onDoubleTap = _onDoubleTap; _strokePath = Path(); _fillPath = Path(); } late double _zoomLevel; + late double _scaleFactor; late DoubleTapGestureRecognizer _doubleTapGestureRecognizer; late Path _fillPath; late Path _strokePath; @@ -298,10 +303,10 @@ class RenderStickyNoteAnnotationView extends RenderInteractiveGraphicsView { Rect _getPaintRect(Rect rect, Offset offset) { final Rect localRect = rect.translate(-_bounds.left, -_bounds.top); final Offset globalOffset = Offset( - offset.dx + (localRect.left / zoomLevel), - offset.dy + (localRect.top / zoomLevel), + offset.dx + (localRect.left * _scaleFactor / zoomLevel), + offset.dy + (localRect.top * _scaleFactor / zoomLevel), ); - return globalOffset & (localRect.size / zoomLevel); + return globalOffset & (localRect.size * _scaleFactor / zoomLevel); } void _applyRotationTransform(Canvas canvas, int rotation, Offset offset) { diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/bookmark/bookmark_item.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/bookmark/bookmark_item.dart index 5c4ae2fad..d3380bcc1 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/bookmark/bookmark_item.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/bookmark/bookmark_item.dart @@ -102,7 +102,7 @@ class BookmarkItem extends StatefulWidget { final TextDirection textDirection; @override - _BookmarkItemState createState() => _BookmarkItemState(); + State createState() => _BookmarkItemState(); } /// State for a [BookmarkItem] diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_provider.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_provider.dart deleted file mode 100644 index 5e033d1f6..000000000 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_provider.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:http/http.dart' as http; -import '../../pdfviewer.dart'; - -/// Represents a base class of PDF document provider. -/// The PDF provider can be from Asset, Memory, File and Network. -abstract class PdfProvider { - /// Abstract const constructor. This constructor enables subclasses to provide - /// const constructors so that they can be used in const expressions. - const PdfProvider(); - - /// Returns the byte information of PDF document. - Future getPdfBytes(BuildContext context); -} - -/// Fetches the given PDF URL from the network. -/// -/// The PDF will be fetched and saved in local temporary directory for PDF -/// manipulation. -/// -/// See also: -/// -/// * [SfPdfViewer.network] for a shorthand of an [SfPdfViewer] widget backed by [NetworkPdf]. -class NetworkPdf extends PdfProvider { - /// Creates an object that fetches the PDF at the given URL. - /// - /// The arguments [url] must not be null. - NetworkPdf(String url, Map? headers) - : assert(url.isNotEmpty) { - _url = url; - _headers = headers; - } - - /// The URL from which the PDF will be fetched. - late String _url; - - /// The document headers - Map? _headers; - - /// The document bytes - Uint8List? _documentBytes; - - @override - Future getPdfBytes(BuildContext context) async { - _documentBytes ??= await http.readBytes(Uri.parse(_url), headers: _headers); - return Future.value(_documentBytes); - } -} - -/// Decodes the given [Uint8List] buffer as an image -/// -/// The provided [bytes] buffer should not be changed after it is provided -/// to a [MemoryPdf]. -/// -/// See also: -/// -/// * [SfPdfViewer.memory] for a shorthand of an [SfPdfViewer] widget backed by [MemoryPdf]. -class MemoryPdf extends PdfProvider { - /// Creates an object that decodes a [Uint8List] buffer as a PDF. - /// - /// The arguments must not be null. - MemoryPdf(Uint8List bytes) { - _pdfBytes = bytes; - } - - late Uint8List _pdfBytes; - - @override - Future getPdfBytes(BuildContext context) async { - return Future.value(_pdfBytes); - } -} - -/// Fetches a PDF from an [AssetBundle] -/// -/// This class behaves like similar to [Image.asset]. -/// -/// See also: -/// -/// * [SfPdfViewer.asset] for a shorthand of an [SfPdfViewer] widget backed by -/// [AssetPdf]. -class AssetPdf extends PdfProvider { - /// Creates an object that fetches the given PDF from an asset bundle. - /// - /// [assetName] must not be null. - AssetPdf(String assetName, AssetBundle? bundle) - : assert(assetName.isNotEmpty) { - _pdfPath = assetName; - _bundle = bundle; - } - - late String _pdfPath; - AssetBundle? _bundle; - Uint8List? _documentBytes; - - @override - Future getPdfBytes(BuildContext context) async { - if (_documentBytes == null) { - final ByteData bytes = await ((_bundle != null) - ? _bundle!.load(_pdfPath) - : DefaultAssetBundle.of(context).load(_pdfPath)); - _documentBytes = bytes.buffer.asUint8List(); - } - return Future.value(_documentBytes); - } -} - -/// Decodes the given [File] object as a PDF. -/// -/// See also: -/// -/// * [SfPdfViewer.file] for a shorthand of an [SfPdfViewer] widget backed by [FilePdf]. -class FilePdf extends PdfProvider { - /// Creates an object that decodes a [File] as a PDF. - /// - /// The [file] must not be null. - FilePdf(File file) { - _file = file; - } - - late File _file; - - /// The document bytes - Uint8List? _documentBytes; - - @override - Future getPdfBytes(BuildContext context) async { - _documentBytes ??= await _file.readAsBytes(); - return Future.value(_documentBytes); - } -} diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_source.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_source.dart index 1c7d4edca..0c48958be 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_source.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/common/pdf_source.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; @@ -36,32 +37,38 @@ abstract class PDFSource { /// /// See also: /// * [SfPdfViewer.network], which provides a convenient way to display a PDF from a URL. +@immutable class URLPDFSource extends PDFSource { /// Creates a [URLPDFSource] that fetches a PDF document from the specified URL. /// /// The [url] parameter must not be null or empty. /// The [headers] parameter can be used to add custom HTTP headers to the request. URLPDFSource(String url, {Map? headers}) - : assert(url.isNotEmpty) { - _url = url; - _headers = headers; - } + : assert(url.isNotEmpty), + _url = url, + _headers = headers; /// The URL from which the PDF will be fetched. - late String _url; + final String _url; /// The document headers - Map? _headers; - - /// The document bytes - Uint8List? _documentBytes; + final Map? _headers; /// Retrieves the bytes of the PDF document from the network. @override Future getBytes(BuildContext context) async { - _documentBytes ??= await http.readBytes(Uri.parse(_url), headers: _headers); - return Future.value(_documentBytes); + return http.readBytes(Uri.parse(_url), headers: _headers); + } + + @override + bool operator ==(Object other) { + return other is URLPDFSource && + _url == other._url && + mapEquals(_headers, other._headers); } + + @override + int get hashCode => Object.hash(_url, _headers); } /// Decodes the given [Uint8List] buffer as a PDF document. @@ -70,13 +77,12 @@ class URLPDFSource extends PDFSource { /// /// See also: /// * [SfPdfViewer.memory], which provides a convenient way to display a PDF using a [Uint8List]. +@immutable class BytePDFSource extends PDFSource { /// Creates a [BytePDFSource] that decodes the specified [Uint8List] as a PDF document. - BytePDFSource(Uint8List bytes) { - _pdfBytes = bytes; - } + const BytePDFSource(this._pdfBytes); - late Uint8List _pdfBytes; + final Uint8List _pdfBytes; /// Retrieves the bytes of the PDF document from memory. @override @@ -92,33 +98,39 @@ class BytePDFSource extends PDFSource { /// /// See also: /// * [SfPdfViewer.asset], which provides a convenient way to display a PDF viewer widget using an asset. +@immutable class AssetPDFSource extends PDFSource { /// Creates an [AssetPDFSource] that fetches the PDF document from the specified asset. /// /// The [assetPath] parameter must not be null or empty. /// The [bundle] parameter is optional. If not provided, the default asset bundle will be used. AssetPDFSource(String assetPath, {AssetBundle? bundle}) - : assert(assetPath.isNotEmpty) { - _pdfPath = assetPath; - _bundle = bundle; - } + : assert(assetPath.isNotEmpty), + _pdfPath = assetPath, + _bundle = bundle; - late String _pdfPath; - AssetBundle? _bundle; - Uint8List? _documentBytes; + final String _pdfPath; + final AssetBundle? _bundle; /// Retrieves the bytes of the PDF document from the asset. @override Future getBytes(BuildContext context) async { - if (_documentBytes == null) { - final ByteData bytes = - await ((_bundle != null) - ? _bundle!.load(_pdfPath) - : DefaultAssetBundle.of(context).load(_pdfPath)); - _documentBytes = bytes.buffer.asUint8List(); - } - return Future.value(_documentBytes); + final ByteData bytes = + await ((_bundle != null) + ? _bundle.load(_pdfPath) + : DefaultAssetBundle.of(context).load(_pdfPath)); + return bytes.buffer.asUint8List(); } + + @override + bool operator ==(Object other) { + return other is AssetPDFSource && + _pdfPath == other._pdfPath && + _bundle == other._bundle; + } + + @override + int get hashCode => Object.hash(_pdfPath, _bundle); } /// Decodes a [File] object as a PDF document. @@ -128,21 +140,24 @@ class AssetPDFSource extends PDFSource { /// See also: /// /// * [SfPdfViewer.file], which provides a convenient way to display a PDF using a file. +@immutable class FilePDFSource extends PDFSource { /// Creates a [FilePDFSource] that decodes the specified [File] as a PDF document. - FilePDFSource(File file) { - _file = file; - } - - late File _file; + const FilePDFSource(this._file); - /// The document bytes - Uint8List? _documentBytes; + final File _file; /// Retrieves the bytes of the PDF document from the file. @override Future getBytes(BuildContext context) async { - _documentBytes ??= await _file.readAsBytes(); - return Future.value(_documentBytes); + return _file.readAsBytes(); } + + @override + bool operator ==(Object other) { + return other is FilePDFSource && _file.path == other._file.path; + } + + @override + int get hashCode => _file.path.hashCode; } diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/desktop_scrollbar.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/desktop_scrollbar.dart index 6fc7f54ec..4267d1eca 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/desktop_scrollbar.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/desktop_scrollbar.dart @@ -249,7 +249,8 @@ class _DesktopScrollbarState extends State // Convert drag delta to content scroll delta final double dx = details.primaryDelta! / _widthRatio; widget.controller.value = - widget.controller.value.clone()..translate(-dx); + widget.controller.value.clone() + ..translateByDouble(-dx, 0.0, 0.0, 1.0); widget.onHorizontalDragUpdate?.call(details); }, child: Container( @@ -308,7 +309,8 @@ class _DesktopScrollbarState extends State // Convert drag delta to content scroll delta final double dy = details.primaryDelta! / _heightRatio; widget.controller.value = - widget.controller.value.clone()..translate(0.0, -dy); + widget.controller.value.clone() + ..translateByDouble(0.0, -dy, 0.0, 1.0); widget.onVerticalDragUpdate?.call(details); }, child: Container( diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdf_scrollable.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdf_scrollable.dart index 873f2ee72..7988e1ae6 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdf_scrollable.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdf_scrollable.dart @@ -33,6 +33,7 @@ class PdfScrollable extends StatefulWidget { this.minScale, this.enableDoubleTapZooming, this.interactionMode, + this.pageSpacing, this.maxPdfPageWidth, this.scaleEnabled, this.maxScrollExtent, @@ -67,6 +68,9 @@ class PdfScrollable extends StatefulWidget { /// Indicates interaction mode of pdfViewer. final PdfInteractionMode interactionMode; + /// Indicates the page spacing between the pages + final double pageSpacing; + /// Indicates whether scroll status must be shown or not. final bool canShowScrollStatus; @@ -317,14 +321,24 @@ class PdfScrollableState extends State { widget.viewportDimension.width.round() > (totalPdfPageWidth * widget.pdfViewerController.zoomLevel) .round()) { - _transformationController.value.translate(currentOffset.dx); + _transformationController.value.translateByDouble( + currentOffset.dx, + 0.0, + 0.0, + 1.0, + ); _isOverFlowed = false; } else { if (widget.scrollDirection == PdfScrollDirection.horizontal && totalPdfPageWidth < widget.viewportDimension.width) { /// Invoked when pdf pages width greater viewport width if (_isOverFlowed == false) { - _transformationController.value.translate(currentOffset.dx); + _transformationController.value.translateByDouble( + currentOffset.dx, + 0.0, + 0.0, + 1.0, + ); _isOverFlowed = true; } } @@ -415,9 +429,11 @@ class PdfScrollableState extends State { final Offset previousOffset = _transformationController.toScene( Offset.zero, ); - _transformationController.value.translate( + _transformationController.value.translateByDouble( previousOffset.dx - offset.dx, previousOffset.dy - offset.dy, + 0.0, + 1.0, ); widget.onPdfOffsetChanged!.call( _transformationController.toScene(Offset.zero), @@ -448,9 +464,11 @@ class PdfScrollableState extends State { final Offset previousOffset = _transformationController.toScene( Offset.zero, ); - _transformationController.value.translate( + _transformationController.value.translateByDouble( previousOffset.dx - offset.dx, previousOffset.dy - offset.dy, + 0.0, + 1.0, ); widget.onPdfOffsetChanged!.call( _transformationController.toScene(Offset.zero), @@ -481,7 +499,12 @@ class PdfScrollableState extends State { final Offset previousOffset = _transformationController.toScene( Offset.zero, ); - _transformationController.value.scale(zoomChangeFactor, zoomChangeFactor); + _transformationController.value.scaleByDouble( + zoomChangeFactor, + zoomChangeFactor, + zoomChangeFactor, + 1.0, + ); if (kIsDesktop && !widget.isMobileWebView && widget.maxPdfPageWidth * zoomLevel < widget.viewportDimension.width) { @@ -496,42 +519,53 @@ class PdfScrollableState extends State { return zoomLevel; } - /// Retrieves the page number based on the offset of the page. - int getPageNumber(double offset) { - int pageNumber = 0; - if (widget.textDirection == TextDirection.rtl && - widget.scrollDirection == PdfScrollDirection.horizontal) { - for (int i = 1; i <= widget.pdfViewerController.pageCount; i++) { - if (i == widget.pdfViewerController.pageCount || offset.round() <= 0) { - pageNumber = widget.pdfViewerController.pageCount; - break; - } else if ((offset.round() + widget.viewportDimension.width.round()) <= - (widget.pdfPages[i]!.pageOffset.round() + - widget.pdfPages[i]!.pageSize.width.round()) && - (offset.round() + widget.viewportDimension.width.round()) > - (widget.pdfPages[i + 1]!.pageOffset.round() + - widget.pdfPages[i + 1]!.pageSize.width.round())) { - pageNumber = i; - break; - } else { - continue; - } - } + /// Retrieves the page number based on the center of the viewport. + int getPageNumber() { + // Calculate the center point of the viewport + Offset centerOffset; + if (widget.scrollDirection == PdfScrollDirection.vertical) { + centerOffset = Offset( + currentOffset.dx, + widget.viewportDimension.height / 2, + ); } else { - for (int i = 1; i <= widget.pdfViewerController.pageCount; i++) { - if (i == widget.pdfViewerController.pageCount || - offset.round() >= widget.maxScrollExtent.round()) { - pageNumber = widget.pdfViewerController.pageCount; - break; - } else if (offset.round() >= widget.pdfPages[i]!.pageOffset.round() && - offset.round() < widget.pdfPages[i + 1]!.pageOffset.round()) { - pageNumber = i; - break; - } else { - continue; + centerOffset = Offset( + widget.viewportDimension.width / 2, + currentOffset.dy, + ); + } + final Offset viewportCenter = _transformationController.toScene( + centerOffset, + ); + + // Loop through all pages to find which one contains the center point + for ( + int pageNumber = 1; + pageNumber <= widget.pdfViewerController.pageCount; + pageNumber++ + ) { + final page = widget.pdfPages[pageNumber]; + if (page != null) { + final Rect pageRect = Rect.fromLTWH( + widget.scrollDirection == PdfScrollDirection.horizontal + ? page.pageOffset + : 0, + widget.scrollDirection == PdfScrollDirection.vertical + ? page.pageOffset + : 0, + widget.scrollDirection == PdfScrollDirection.horizontal + ? page.pageSize.width + widget.pageSpacing + : page.pageSize.width, + widget.scrollDirection == PdfScrollDirection.vertical + ? page.pageSize.height + widget.pageSpacing + : page.pageSize.height, + ); + + if (pageRect.contains(viewportCenter)) { + return pageNumber; } } } - return pageNumber; + return widget.pdfViewerController.pageNumber; } } diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdfviewer_canvas.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdfviewer_canvas.dart index d0d461273..f68bb7c60 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdfviewer_canvas.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/pdfviewer_canvas.dart @@ -183,8 +183,13 @@ class PdfViewerCanvas extends LeafRenderObjectWidget { ..interactionMode = interactionMode ..isMobileWebView = isMobileWebView ..enableTextSelection = enableTextSelection - ..enableDocumentLinkNavigation = enableDocumentLinkNavigation - ..enableHyperlinkNavigation = enableHyperlinkNavigation + // Enables hyperlink and document link navigation only when annotation mode is set to none. + ..enableDocumentLinkNavigation = + (pdfViewerController.annotationMode == PdfAnnotationMode.none) && + enableDocumentLinkNavigation + ..enableHyperlinkNavigation = + (pdfViewerController.annotationMode == PdfAnnotationMode.none) && + enableHyperlinkNavigation ..canShowHyperlinkDialog = canShowHyperlinkDialog ..currentSearchTextHighlightColor = currentSearchTextHighlightColor ..otherSearchTextHighlightColor = otherSearchTextHighlightColor @@ -356,7 +361,9 @@ class CanvasRenderBox extends RenderBox { bool _isHyperLinkTapped = false; bool _isMousePointer = false; double _startBubbleTapX = 0; + double _startBubbleTapY = 0; double _endBubbleTapX = 0; + double _endBubbleTapY = 0; final double _bubbleSize = 16.0; final double _jumpOffset = 10.0; final double _maximumZoomLevel = 2.0; @@ -380,6 +387,7 @@ class CanvasRenderBox extends RenderBox { late final PdfPageRotateAngle _rotatedAngle = pdfDocument!.pages[pageIndex].rotation; bool _isConsecutiveTap = false; + bool _isSelectedTextContainsRotatedGlyph = false; @override void handleEvent(PointerEvent event, BoxHitTestEntry entry) { @@ -1213,6 +1221,7 @@ class CanvasRenderBox extends RenderBox { /// Handles the long press started event.cursorMode void handleLongPressStart(LongPressStartDetails details) { _isConsecutiveTap = false; + _isSelectedTextContainsRotatedGlyph = false; if (kIsDesktop && !isMobileWebView && pdfDocument != null) { clearMouseSelection(); final bool isTOC = findTOC(details.localPosition); @@ -1268,10 +1277,12 @@ class CanvasRenderBox extends RenderBox { _dragDetails = details.localPosition; if (_startBubbleDragging) { _startBubbleTapX = details.localPosition.dx; + _startBubbleTapY = details.localPosition.dy; markNeedsPaint(); triggerNullCallback(); } else if (_endBubbleDragging) { _endBubbleTapX = details.localPosition.dx; + _endBubbleTapY = details.localPosition.dy; markNeedsPaint(); if (onTextSelectionChanged != null) { onTextSelectionChanged!(PdfTextSelectionChangedDetails(null, null)); @@ -1718,11 +1729,22 @@ class CanvasRenderBox extends RenderBox { final double startBubbleY = _textSelectionHelper.startBubbleY! / _textSelectionHelper.heightPercentage!; - if (details.dx >= startBubbleX - (_bubbleSize * _maximumZoomLevel) && - details.dx <= startBubbleX && - details.dy >= startBubbleY - _bubbleSize && - details.dy <= startBubbleY + _bubbleSize) { - return true; + if (_isSelectedTextContainsRotatedGlyph) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (details.dy <= startBubbleY + (_bubbleSize * _maximumZoomLevel) && + details.dy >= startBubbleY && + details.dx >= startBubbleX - _bubbleSize && + details.dx <= startBubbleX + _bubbleSize) { + return true; + } + } + } else { + if (details.dx >= startBubbleX - (_bubbleSize * _maximumZoomLevel) && + details.dx <= startBubbleX && + details.dy >= startBubbleY - _bubbleSize && + details.dy <= startBubbleY + _bubbleSize) { + return true; + } } } return false; @@ -1737,11 +1759,22 @@ class CanvasRenderBox extends RenderBox { final double endBubbleY = _textSelectionHelper.endBubbleY! / _textSelectionHelper.heightPercentage!; - if (details.dx >= endBubbleX && - details.dx <= endBubbleX + (_bubbleSize * _maximumZoomLevel) && - details.dy >= endBubbleY - _bubbleSize && - details.dy <= endBubbleY + _bubbleSize) { - return true; + if (_isSelectedTextContainsRotatedGlyph) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (details.dy <= endBubbleY && + details.dy >= endBubbleY - (_bubbleSize * _maximumZoomLevel) && + details.dx >= endBubbleX - _bubbleSize && + details.dx <= endBubbleX + _bubbleSize) { + return true; + } + } + } else { + if (details.dx >= endBubbleX && + details.dx <= endBubbleX + (_bubbleSize * _maximumZoomLevel) && + details.dy >= endBubbleY - _bubbleSize && + details.dy <= endBubbleY + _bubbleSize) { + return true; + } } } return false; @@ -1881,6 +1914,8 @@ class CanvasRenderBox extends RenderBox { /// clears Text Selection. bool clearSelection() { _isRTLText = false; + _isSelectedTextContainsRotatedGlyph = false; + _isConsecutiveTap = false; clearMouseSelection(); final bool clearTextSelection = !_textSelectionHelper.selectionEnabled; if (_textSelectionHelper.selectionEnabled) { @@ -2022,6 +2057,9 @@ class CanvasRenderBox extends RenderBox { final double glyphCenterY = textGlyph.bounds.center.dy; final double top = startGlyph.bounds.top; final double bottom = startGlyph.bounds.bottom; + final double left = startGlyph.bounds.left; + final double right = startGlyph.bounds.right; + if (isRTLText && !_isConsecutiveTap) { if ((glyphCenterY > top && glyphCenterY < startBubbleDetails.dy) && (glyphCenterX < startGlyph.bounds.right || glyphCenterY > bottom) && @@ -2041,22 +2079,46 @@ class CanvasRenderBox extends RenderBox { } } } else { - if ((glyphCenterY > top && glyphCenterY < endBubbleDetails.dy) && - (glyphCenterX > startGlyph.bounds.left || glyphCenterY > bottom) && - (textGlyph.bounds.bottom < endBubbleDetails.dy || - glyphCenterX < endBubbleDetails.dx)) { - return true; - } - if (endBubbleDetails.dy < top || - (endBubbleDetails.dy < bottom && - endBubbleDetails.dx < startGlyph.bounds.left)) { - if ((glyphCenterY > endBubbleDetails.dy && glyphCenterY < bottom) && - (glyphCenterX > endBubbleDetails.dx || - textGlyph.bounds.top > endBubbleDetails.dy) && - (textGlyph.bounds.bottom < top || - glyphCenterX < startGlyph.bounds.left)) { + if (textGlyph.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if ((glyphCenterX > left && glyphCenterX < endBubbleDetails.dx) && + (glyphCenterY < startGlyph.bounds.bottom || + glyphCenterX > right) && + (textGlyph.bounds.right < endBubbleDetails.dx || + glyphCenterY > endBubbleDetails.dy)) { + return true; + } + + if (endBubbleDetails.dx < left || + (endBubbleDetails.dx < right && + endBubbleDetails.dy > startGlyph.bounds.bottom)) { + if ((glyphCenterX > endBubbleDetails.dx && glyphCenterX < right) && + (glyphCenterY < endBubbleDetails.dy || + textGlyph.bounds.left > endBubbleDetails.dx) && + (textGlyph.bounds.right < left || + glyphCenterY > startGlyph.bounds.top)) { + return true; + } + } + } + } else { + if ((glyphCenterY > top && glyphCenterY < endBubbleDetails.dy) && + (glyphCenterX > startGlyph.bounds.left || glyphCenterY > bottom) && + (textGlyph.bounds.bottom < endBubbleDetails.dy || + glyphCenterX < endBubbleDetails.dx)) { return true; } + if (endBubbleDetails.dy < top || + (endBubbleDetails.dy < bottom && + endBubbleDetails.dx < startGlyph.bounds.left)) { + if ((glyphCenterY > endBubbleDetails.dy && glyphCenterY < bottom) && + (glyphCenterX > endBubbleDetails.dx || + textGlyph.bounds.top > endBubbleDetails.dy) && + (textGlyph.bounds.bottom < top || + glyphCenterX < startGlyph.bounds.left)) { + return true; + } + } } } return false; @@ -2076,19 +2138,35 @@ class CanvasRenderBox extends RenderBox { Paint bubblePaint, Offset startBubbleOffset, ) { - canvas.drawRRect( - RRect.fromLTRBAndCorners( - startBubbleOffset.dx - (_bubbleSize / _zoomPercentage), - startBubbleOffset.dy, - startBubbleOffset.dx, - startBubbleOffset.dy + (_bubbleSize / _zoomPercentage), - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(1.0), - bottomRight: const Radius.circular(10.0), - bottomLeft: const Radius.circular(10.0), - ), - bubblePaint, - ); + if (_isSelectedTextContainsRotatedGlyph) { + canvas.drawRRect( + RRect.fromLTRBAndCorners( + startBubbleOffset.dx, + startBubbleOffset.dy, + startBubbleOffset.dx + (_bubbleSize / _zoomPercentage), + startBubbleOffset.dy + (_bubbleSize / _zoomPercentage), + topLeft: const Radius.circular(1.0), + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0), + ), + bubblePaint, + ); + } else { + canvas.drawRRect( + RRect.fromLTRBAndCorners( + startBubbleOffset.dx - (_bubbleSize / _zoomPercentage), + startBubbleOffset.dy, + startBubbleOffset.dx, + startBubbleOffset.dy + (_bubbleSize / _zoomPercentage), + topLeft: const Radius.circular(10.0), + topRight: const Radius.circular(1.0), + bottomRight: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0), + ), + bubblePaint, + ); + } } /// Draw the end bubble. @@ -2097,19 +2175,35 @@ class CanvasRenderBox extends RenderBox { Paint bubblePaint, Offset endBubbleOffset, ) { - canvas.drawRRect( - RRect.fromLTRBAndCorners( - endBubbleOffset.dx, - endBubbleOffset.dy, - endBubbleOffset.dx + (_bubbleSize / _zoomPercentage), - endBubbleOffset.dy + (_bubbleSize / _zoomPercentage), - topLeft: const Radius.circular(1.0), - topRight: const Radius.circular(10.0), - bottomRight: const Radius.circular(10.0), - bottomLeft: const Radius.circular(10.0), - ), - bubblePaint, - ); + if (_isSelectedTextContainsRotatedGlyph) { + canvas.drawRRect( + RRect.fromLTRBAndCorners( + endBubbleOffset.dx, + endBubbleOffset.dy, + endBubbleOffset.dx + (_bubbleSize / _zoomPercentage), + endBubbleOffset.dy - (_bubbleSize / _zoomPercentage), + topLeft: const Radius.circular(10.0), + bottomLeft: const Radius.circular(1.0), + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0), + ), + bubblePaint, + ); + } else { + canvas.drawRRect( + RRect.fromLTRBAndCorners( + endBubbleOffset.dx, + endBubbleOffset.dy, + endBubbleOffset.dx + (_bubbleSize / _zoomPercentage), + endBubbleOffset.dy + (_bubbleSize / _zoomPercentage), + topLeft: const Radius.circular(1.0), + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0), + ), + bubblePaint, + ); + } } /// Draw the Rect for selected text. @@ -2394,11 +2488,22 @@ class CanvasRenderBox extends RenderBox { maxY / heightPercentage, ); } - if (endBubbleDetails.dy < startGlyph.bounds.top) { - startOffset = Offset( - endBubbleDetails.dx / heightPercentage, - endBubbleDetails.dy / heightPercentage, - ); + if (glyph.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (endBubbleDetails.dx < startGlyph.bounds.left) { + startOffset = Offset( + endBubbleDetails.dx / heightPercentage, + endBubbleDetails.dy / heightPercentage, + ); + } + } + } else { + if (endBubbleDetails.dy < startGlyph.bounds.top) { + startOffset = Offset( + endBubbleDetails.dx / heightPercentage, + endBubbleDetails.dy / heightPercentage, + ); + } } _textSelectionHelper.globalSelectedRegion = Rect.fromPoints( localToGlobal(startOffset), @@ -2498,10 +2603,19 @@ class CanvasRenderBox extends RenderBox { double glyphPosition = 0; if (glyphIndex < textWord.text.length - 1) { final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; - final double currentGlyph = - textGlyph.bounds.width + textGlyph.bounds.left; - final double nextGlyph = textWord.glyphs[glyphIndex + 1].bounds.left; - glyphPosition = (currentGlyph - nextGlyph).abs(); + if (glyph.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + glyphPosition = + (textGlyph.bounds.top - + textWord.glyphs[glyphIndex + 1].bounds.bottom) + .abs(); + } + } else { + final double currentGlyphEnd = textGlyph.bounds.right; + final double nextGlyphStart = + textWord.glyphs[glyphIndex + 1].bounds.left; + glyphPosition = (currentGlyphEnd - nextGlyphStart).abs(); + } } glyphText = (glyphPosition > 1.0) @@ -2534,36 +2648,80 @@ class CanvasRenderBox extends RenderBox { for (int i = 0; i < _textSelectionHelper.textLines!.length; i++) { final TextLine line = _textSelectionHelper.textLines![i]; final bool isRTLText = intl.Bidi.detectRtlDirectionality(line.text); + Rect extendBounds = line.bounds; + final isRotatedGlyph = line.wordCollection.first.glyphs.first.isRotated; + if (isRotatedGlyph) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + extendBounds = Rect.fromLTRB( + line.bounds.left, + 0, + line.bounds.right, + pdfDocument!.pages[_textSelectionHelper.viewId!].size.height, + ); + } + } else { + /// Extends line bounds horizontally to cover full page width, allowing free space for text selection. + extendBounds = Rect.fromLTRB( + 0, + line.bounds.top, + pdfDocument!.pages[_textSelectionHelper.viewId!].size.width, + line.bounds.bottom, + ); + } if (!isMouseSelection) { if (isRTLText) { - if (line.bounds.contains(details * heightPercentage)) { + if (extendBounds.contains(details * heightPercentage)) { if (_startBubbleDragging && i >= _textSelectionHelper.startIndex) { _textSelectionHelper.endIndex = i; } else if (_endBubbleDragging && i <= _textSelectionHelper.endIndex) { _textSelectionHelper.startIndex = i; + break; } } } else { - if (line.bounds.contains(details * heightPercentage)) { + if (extendBounds.contains(details * heightPercentage)) { if (_startBubbleDragging && i <= _textSelectionHelper.endIndex) { _textSelectionHelper.startIndex = i; } else if (_endBubbleDragging && i >= _textSelectionHelper.startIndex) { _textSelectionHelper.endIndex = i; + break; + } + } + } + } else { + if (isRotatedGlyph) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if ((extendBounds.contains(details) || + (_textSelectionHelper.isCursorExit && + details.dx > line.bounds.left / heightPercentage)) && + i <= _textSelectionHelper.endIndex && + (details.dx < startPoint.left)) { + _textSelectionHelper.startIndex = i; + break; + } else if (extendBounds.contains(details) && + i >= _textSelectionHelper.startIndex && + (details.dx > startPoint.left)) { + _textSelectionHelper.endIndex = i; + break; } } + } else { + if ((extendBounds.contains(details) || + (_textSelectionHelper.isCursorExit && + details.dy > line.bounds.top / heightPercentage)) && + i <= _textSelectionHelper.endIndex && + (details.dy < startPoint.top)) { + _textSelectionHelper.startIndex = i; + break; + } else if (extendBounds.contains(details) && + i >= _textSelectionHelper.startIndex && + (details.dy > startPoint.top)) { + _textSelectionHelper.endIndex = i; + break; + } } - } else if ((line.bounds.contains(details) || - (_textSelectionHelper.isCursorExit && - details.dy > line.bounds.top / heightPercentage)) && - i <= _textSelectionHelper.endIndex && - (details.dy < startPoint.top)) { - _textSelectionHelper.startIndex = i; - } else if (line.bounds.contains(details) && - i >= _textSelectionHelper.startIndex && - (details.dy > startPoint.top)) { - _textSelectionHelper.endIndex = i; } } } @@ -2700,11 +2858,30 @@ class CanvasRenderBox extends RenderBox { _textSelectionHelper.endBubbleLine = _textSelectionHelper.textLines![textLineIndex]; _startBubbleTapX = textWord.bounds.bottomLeft.dx / heightPercentage; + _startBubbleTapY = textWord.bounds.bottomLeft.dy / heightPercentage; _textSelectionHelper.startBubbleY = textWord.bounds.bottomLeft.dy; _endBubbleTapX = textWord.bounds.bottomRight.dx / heightPercentage; + _endBubbleTapY = textWord.bounds.bottomRight.dy / heightPercentage; _textSelectionHelper.endBubbleY = textWord.bounds.bottomRight.dy; _textSelectionHelper.startBubbleX = textWord.bounds.bottomLeft.dx; _textSelectionHelper.endBubbleX = textWord.bounds.bottomRight.dx; + if (textWord.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + _isSelectedTextContainsRotatedGlyph = true; + _startBubbleTapX = + textWord.bounds.bottomRight.dx / heightPercentage; + _startBubbleTapY = + textWord.bounds.bottomRight.dy / heightPercentage; + _endBubbleTapX = textWord.bounds.topRight.dx / heightPercentage; + _endBubbleTapY = textWord.bounds.topRight.dy / heightPercentage; + _textSelectionHelper.startBubbleX = + textWord.bounds.bottomRight.dx; + _textSelectionHelper.startBubbleY = + textWord.bounds.bottomRight.dy; + _textSelectionHelper.endBubbleX = textWord.bounds.topRight.dx; + _textSelectionHelper.endBubbleY = textWord.bounds.topRight.dy; + } + } final Rect textRectOffset = offset.translate( textWord.bounds.left / heightPercentage, @@ -2715,14 +2892,26 @@ class CanvasRenderBox extends RenderBox { wordBounds.height / heightPercentage, ); _drawTextRect(canvas, textPaint, textRectOffset); - final Offset startBubbleOffset = offset.translate( + Offset startBubbleOffset = offset.translate( textWord.bounds.bottomLeft.dx / heightPercentage, textWord.bounds.bottomLeft.dy / heightPercentage, ); - final Offset endBubbleOffset = offset.translate( + Offset endBubbleOffset = offset.translate( textWord.bounds.bottomRight.dx / heightPercentage, textWord.bounds.bottomRight.dy / heightPercentage, ); + if (textWord.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + startBubbleOffset = offset.translate( + textWord.bounds.bottomRight.dx / heightPercentage, + textWord.bounds.bottomRight.dy / heightPercentage, + ); + endBubbleOffset = offset.translate( + textWord.bounds.topRight.dx / heightPercentage, + textWord.bounds.topRight.dy / heightPercentage, + ); + } + } _drawStartBubble(canvas, bubblePaint, startBubbleOffset); _drawEndBubble(canvas, bubblePaint, endBubbleOffset); _textSelectionHelper.globalSelectedRegion = Rect.fromPoints( @@ -2776,20 +2965,47 @@ class CanvasRenderBox extends RenderBox { ) { final TextLine line = _textSelectionHelper.textLines![textLineIndex]; if (!_isRTLText) { - if (_dragDetails != null && - _dragDetails!.dy <= - _textSelectionHelper.endBubbleY! / heightPercentage && - _dragDetails!.dy >= (line.bounds.top / heightPercentage)) { - _textSelectionHelper.startBubbleLine = line; - _textSelectionHelper.startBubbleY = line.bounds.bottomLeft.dy; + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + _isSelectedTextContainsRotatedGlyph = true; + if (_dragDetails != null && + _dragDetails!.dx <= + _textSelectionHelper.endBubbleX! / heightPercentage && + _dragDetails!.dx >= (line.bounds.left / heightPercentage)) { + _textSelectionHelper.startBubbleLine = line; + _textSelectionHelper.startBubbleX = line.bounds.right; + } + } + } else { + if (_dragDetails != null && + _dragDetails!.dy <= + _textSelectionHelper.endBubbleY! / heightPercentage && + _dragDetails!.dy >= (line.bounds.top / heightPercentage)) { + _textSelectionHelper.startBubbleLine = line; + _textSelectionHelper.startBubbleY = line.bounds.bottomLeft.dy; + } } - if (_dragDetails != null && - _dragDetails!.dy >= - _textSelectionHelper.endBubbleY! / heightPercentage) { - _textSelectionHelper.startBubbleLine = - _textSelectionHelper.endBubbleLine; - _textSelectionHelper.startBubbleY = - _textSelectionHelper.endBubbleLine!.bounds.bottom; + + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_dragDetails != null && + _dragDetails!.dx >= + _textSelectionHelper.endBubbleX! / heightPercentage) { + _textSelectionHelper.startBubbleLine = + _textSelectionHelper.endBubbleLine; + _textSelectionHelper.startBubbleX = + _textSelectionHelper.endBubbleLine!.bounds.right; + } + } + } else { + if (_dragDetails != null && + _dragDetails!.dy >= + _textSelectionHelper.endBubbleY! / heightPercentage) { + _textSelectionHelper.startBubbleLine = + _textSelectionHelper.endBubbleLine; + _textSelectionHelper.startBubbleY = + _textSelectionHelper.endBubbleLine!.bounds.bottom; + } } } else { if (_dragDetails != null && @@ -2830,87 +3046,190 @@ class CanvasRenderBox extends RenderBox { glyphIndex++ ) { final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; - if (_startBubbleTapX >= - (textGlyph.bounds.bottomLeft.dx / heightPercentage) && - !_isRTLText && - _startBubbleTapX <= - (textGlyph.bounds.bottomRight.dx / heightPercentage)) { - _textSelectionHelper.startBubbleX = - textGlyph.bounds.bottomLeft.dx; - _textSelectionHelper.firstSelectedGlyph = textGlyph; - } else if (_endBubbleTapX >= - (textGlyph.bounds.bottomLeft.dx / heightPercentage) && - _isRTLText && - _endBubbleTapX <= - (textGlyph.bounds.bottomRight.dx / heightPercentage)) { - _textSelectionHelper.endBubbleX = - textGlyph.bounds.bottomRight.dx; - _textSelectionHelper.firstSelectedGlyph = textGlyph; + if (!_isRTLText) { + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_startBubbleTapY <= + (textGlyph.bounds.bottom / heightPercentage) && + _startBubbleTapY >= + (textGlyph.bounds.top / heightPercentage)) { + _textSelectionHelper.startBubbleY = + textGlyph.bounds.bottomRight.dy; + _textSelectionHelper.firstSelectedGlyph = textGlyph; + } + } + } else { + if (_startBubbleTapX >= + (textGlyph.bounds.bottomLeft.dx / heightPercentage) && + _startBubbleTapX <= + (textGlyph.bounds.bottomRight.dx / + heightPercentage)) { + _textSelectionHelper.startBubbleX = + textGlyph.bounds.bottomLeft.dx; + _textSelectionHelper.firstSelectedGlyph = textGlyph; + } + } + } else { + if (_endBubbleTapX >= + (textGlyph.bounds.bottomLeft.dx / heightPercentage) && + _endBubbleTapX <= + (textGlyph.bounds.bottomRight.dx / heightPercentage)) { + _textSelectionHelper.endBubbleX = + textGlyph.bounds.bottomRight.dx; + _textSelectionHelper.firstSelectedGlyph = textGlyph; + } } } } if (!_isRTLText) { - if (_startBubbleTapX < - (_textSelectionHelper.startBubbleLine!.bounds.bottomLeft.dx / - heightPercentage)) { - _textSelectionHelper.startBubbleX = - _textSelectionHelper.startBubbleLine!.bounds.bottomLeft.dx; - _textSelectionHelper.firstSelectedGlyph = - _textSelectionHelper - .startBubbleLine! - .wordCollection - .first - .glyphs - .first; - } - if (_startBubbleTapX >= - (_textSelectionHelper.startBubbleLine!.bounds.bottomRight.dx / - heightPercentage)) { - _textSelectionHelper.startBubbleX = - _textSelectionHelper - .startBubbleLine! - .wordCollection - .last - .glyphs - .last - .bounds - .bottomLeft - .dx; - _textSelectionHelper.firstSelectedGlyph = - _textSelectionHelper - .startBubbleLine! - .wordCollection - .last - .glyphs - .last; + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_startBubbleTapY > + (_textSelectionHelper.startBubbleLine!.bounds.bottom / + heightPercentage)) { + _textSelectionHelper.startBubbleY = + _textSelectionHelper.startBubbleLine!.bounds.bottom; + _textSelectionHelper.firstSelectedGlyph = + _textSelectionHelper + .startBubbleLine! + .wordCollection + .first + .glyphs + .first; + } + } + } else { + if (_startBubbleTapX < + (_textSelectionHelper.startBubbleLine!.bounds.bottomLeft.dx / + heightPercentage)) { + _textSelectionHelper.startBubbleX = + _textSelectionHelper.startBubbleLine!.bounds.bottomLeft.dx; + _textSelectionHelper.firstSelectedGlyph = + _textSelectionHelper + .startBubbleLine! + .wordCollection + .first + .glyphs + .first; + } } - if (_textSelectionHelper.startBubbleLine!.bounds.bottom / - heightPercentage == - _textSelectionHelper.endBubbleLine!.bounds.bottom / - heightPercentage && - _startBubbleTapX >= _endBubbleTapX) { - for ( - int wordIndex = 0; - wordIndex < - _textSelectionHelper.startBubbleLine!.wordCollection.length; - wordIndex++ - ) { - final TextWord textWord = + + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_startBubbleTapY <= + (_textSelectionHelper.startBubbleLine!.bounds.top / + heightPercentage)) { + _textSelectionHelper.startBubbleY = + _textSelectionHelper + .startBubbleLine! + .wordCollection + .last + .glyphs + .last + .bounds + .bottom; + _textSelectionHelper.firstSelectedGlyph = + _textSelectionHelper + .startBubbleLine! + .wordCollection + .last + .glyphs + .last; + } + } + } else { + if (_startBubbleTapX >= + (_textSelectionHelper.startBubbleLine!.bounds.bottomRight.dx / + heightPercentage)) { + _textSelectionHelper.startBubbleX = _textSelectionHelper .startBubbleLine! - .wordCollection[wordIndex]; + .wordCollection + .last + .glyphs + .last + .bounds + .bottomLeft + .dx; + _textSelectionHelper.firstSelectedGlyph = + _textSelectionHelper + .startBubbleLine! + .wordCollection + .last + .glyphs + .last; + } + } + + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_textSelectionHelper.startBubbleLine!.bounds.right / + heightPercentage == + _textSelectionHelper.endBubbleLine!.bounds.right / + heightPercentage && + _startBubbleTapY <= _endBubbleTapY) { + for ( + int wordIndex = 0; + wordIndex < + _textSelectionHelper + .startBubbleLine! + .wordCollection + .length; + wordIndex++ + ) { + final TextWord textWord = + _textSelectionHelper + .startBubbleLine! + .wordCollection[wordIndex]; + for ( + int glyphIndex = 0; + glyphIndex < textWord.glyphs.length; + glyphIndex++ + ) { + final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; + if (textGlyph.bounds.top / heightPercentage == + _textSelectionHelper.endBubbleY! / heightPercentage) { + _textSelectionHelper.startBubbleY = + textGlyph.bounds.bottom; + _textSelectionHelper.firstSelectedGlyph = textGlyph; + break; + } + } + } + } + } + } else { + if (_textSelectionHelper.startBubbleLine!.bounds.bottom / + heightPercentage == + _textSelectionHelper.endBubbleLine!.bounds.bottom / + heightPercentage && + _startBubbleTapX >= _endBubbleTapX) { for ( - int glyphIndex = 0; - glyphIndex < textWord.glyphs.length; - glyphIndex++ + int wordIndex = 0; + wordIndex < + _textSelectionHelper + .startBubbleLine! + .wordCollection + .length; + wordIndex++ ) { - final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; - if (textGlyph.bounds.bottomRight.dx / heightPercentage == - _textSelectionHelper.endBubbleX! / heightPercentage) { - _textSelectionHelper.startBubbleX = - textGlyph.bounds.bottomLeft.dx; - _textSelectionHelper.firstSelectedGlyph = textGlyph; - break; + final TextWord textWord = + _textSelectionHelper + .startBubbleLine! + .wordCollection[wordIndex]; + for ( + int glyphIndex = 0; + glyphIndex < textWord.glyphs.length; + glyphIndex++ + ) { + final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; + if (textGlyph.bounds.bottomRight.dx / heightPercentage == + _textSelectionHelper.endBubbleX! / heightPercentage) { + _textSelectionHelper.startBubbleX = + textGlyph.bounds.bottomLeft.dx; + _textSelectionHelper.firstSelectedGlyph = textGlyph; + break; + } } } } @@ -2970,30 +3289,47 @@ class CanvasRenderBox extends RenderBox { textLineIndex++ ) { final TextLine line = _textSelectionHelper.textLines![textLineIndex]; - if (_dragDetails != null && - !_isRTLText && - _dragDetails!.dy >= - (_textSelectionHelper.startBubbleLine!.bounds.top / - heightPercentage) && - _dragDetails!.dy >= (line.bounds.topLeft.dy / heightPercentage)) { - _textSelectionHelper.endBubbleLine = line; - _textSelectionHelper.endBubbleY = line.bounds.bottomRight.dy; - } - if (_dragDetails != null && - _isRTLText && - _dragDetails!.dy >= - (_textSelectionHelper.startBubbleLine!.bounds.top / - heightPercentage) && - _dragDetails!.dy >= (line.bounds.topLeft.dy / heightPercentage)) { - _textSelectionHelper.startBubbleLine = line; - _textSelectionHelper.startBubbleY = line.bounds.bottomRight.dy; - } else if (_dragDetails != null && - _isRTLText && - _dragDetails!.dy <= - (_textSelectionHelper.startBubbleLine!.bounds.bottom / - heightPercentage)) { - _textSelectionHelper.startBubbleLine = line; - _textSelectionHelper.startBubbleY = line.bounds.bottom; + if (!_isRTLText) { + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + _isSelectedTextContainsRotatedGlyph = true; + if (_dragDetails != null && + _dragDetails!.dx >= + (_textSelectionHelper.startBubbleLine!.bounds.left / + heightPercentage) && + _dragDetails!.dx <= + (line.bounds.right / heightPercentage)) { + _textSelectionHelper.endBubbleLine = line; + _textSelectionHelper.endBubbleX = line.bounds.topRight.dx; + } + } + } else { + if (_dragDetails != null && + _dragDetails!.dy >= + (_textSelectionHelper.startBubbleLine!.bounds.top / + heightPercentage) && + _dragDetails!.dy >= + (line.bounds.topLeft.dy / heightPercentage)) { + _textSelectionHelper.endBubbleLine = line; + _textSelectionHelper.endBubbleY = line.bounds.bottomRight.dy; + } + } + } else { + if (_dragDetails != null && + _dragDetails!.dy >= + (_textSelectionHelper.startBubbleLine!.bounds.top / + heightPercentage) && + _dragDetails!.dy >= + (line.bounds.topLeft.dy / heightPercentage)) { + _textSelectionHelper.startBubbleLine = line; + _textSelectionHelper.startBubbleY = line.bounds.bottomRight.dy; + } else if (_dragDetails != null && + _dragDetails!.dy <= + (_textSelectionHelper.startBubbleLine!.bounds.bottom / + heightPercentage)) { + _textSelectionHelper.startBubbleLine = line; + _textSelectionHelper.startBubbleY = line.bounds.bottom; + } } for ( int wordIndex = 0; @@ -3023,72 +3359,150 @@ class CanvasRenderBox extends RenderBox { glyphIndex++ ) { final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; - if (!_isRTLText && - _endBubbleTapX >= - (textGlyph.bounds.bottomLeft.dx / heightPercentage) && - _endBubbleTapX <= - (textGlyph.bounds.bottomRight.dx / heightPercentage)) { - _textSelectionHelper.endBubbleX = - textGlyph.bounds.bottomRight.dx; - } else if (_isRTLText && - _startBubbleTapX >= - (textGlyph.bounds.bottomLeft.dx / heightPercentage) && - _startBubbleTapX <= - (textGlyph.bounds.bottomRight.dx / heightPercentage)) { - _textSelectionHelper.startBubbleX = - textGlyph.bounds.bottomRight.dx; + if (!_isRTLText) { + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_endBubbleTapY <= + (textGlyph.bounds.bottomRight.dy / + heightPercentage) && + _endBubbleTapY >= + (textGlyph.bounds.topRight.dy / heightPercentage)) { + _textSelectionHelper.endBubbleY = + textGlyph.bounds.topRight.dy; + } + } + } else { + if (_endBubbleTapX >= + (textGlyph.bounds.bottomLeft.dx / heightPercentage) && + _endBubbleTapX <= + (textGlyph.bounds.bottomRight.dx / + heightPercentage)) { + _textSelectionHelper.endBubbleX = + textGlyph.bounds.bottomRight.dx; + } + } + } else { + if (_startBubbleTapX >= + (textGlyph.bounds.bottomLeft.dx / heightPercentage) && + _startBubbleTapX <= + (textGlyph.bounds.bottomRight.dx / heightPercentage)) { + _textSelectionHelper.startBubbleX = + textGlyph.bounds.bottomRight.dx; + } } } } if (!_isRTLText) { - if (_endBubbleTapX.floor() > - (_textSelectionHelper.endBubbleLine!.bounds.bottomRight.dx / - heightPercentage) - .floor()) { - _textSelectionHelper.endBubbleX = - _textSelectionHelper.endBubbleLine!.bounds.bottomRight.dx; - } - if (_endBubbleTapX.floor() <= - (_textSelectionHelper.endBubbleLine!.bounds.bottomLeft.dx / - heightPercentage) - .floor()) { - _textSelectionHelper.endBubbleX = - _textSelectionHelper - .endBubbleLine! - .wordCollection - .first - .glyphs - .first - .bounds - .bottomRight - .dx; - } - if (_textSelectionHelper.endBubbleLine!.bounds.bottom / - heightPercentage == - _textSelectionHelper.startBubbleLine!.bounds.bottom / - heightPercentage && - _endBubbleTapX < _startBubbleTapX) { - for ( - int wordIndex = 0; - wordIndex < - _textSelectionHelper.endBubbleLine!.wordCollection.length; - wordIndex++ - ) { - final TextWord textWord = + if (line.wordCollection.first.glyphs.first.isRotated) { + if (_rotatedAngle == PdfPageRotateAngle.rotateAngle90) { + if (_endBubbleTapY.floor() < + (_textSelectionHelper.endBubbleLine!.bounds.topRight.dy / + heightPercentage) + .floor()) { + _textSelectionHelper.endBubbleY = + _textSelectionHelper.endBubbleLine!.bounds.topRight.dy; + } + if (_endBubbleTapY.floor() >= + (_textSelectionHelper.endBubbleLine!.bounds.bottomRight.dy / + heightPercentage) + .floor()) { + _textSelectionHelper.endBubbleY = + _textSelectionHelper + .endBubbleLine! + .wordCollection + .first + .glyphs + .first + .bounds + .topRight + .dy; + } + + if (_textSelectionHelper.endBubbleLine!.bounds.right / + heightPercentage == + _textSelectionHelper.startBubbleLine!.bounds.right / + heightPercentage && + _endBubbleTapY > _startBubbleTapY) { + for ( + int wordIndex = 0; + wordIndex < + _textSelectionHelper + .endBubbleLine! + .wordCollection + .length; + wordIndex++ + ) { + final TextWord textWord = + _textSelectionHelper + .endBubbleLine! + .wordCollection[wordIndex]; + for ( + int glyphIndex = 0; + glyphIndex < textWord.glyphs.length; + glyphIndex++ + ) { + final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; + if (textGlyph.bounds.bottomRight.dy / heightPercentage == + _textSelectionHelper.startBubbleY! / + heightPercentage) { + _textSelectionHelper.endBubbleY = + textGlyph.bounds.topRight.dy; + break; + } + } + } + } + } + } else { + if (_endBubbleTapX.floor() > + (_textSelectionHelper.endBubbleLine!.bounds.bottomRight.dx / + heightPercentage) + .floor()) { + _textSelectionHelper.endBubbleX = + _textSelectionHelper.endBubbleLine!.bounds.bottomRight.dx; + } + if (_endBubbleTapX.floor() <= + (_textSelectionHelper.endBubbleLine!.bounds.bottomLeft.dx / + heightPercentage) + .floor()) { + _textSelectionHelper.endBubbleX = _textSelectionHelper .endBubbleLine! - .wordCollection[wordIndex]; + .wordCollection + .first + .glyphs + .first + .bounds + .bottomRight + .dx; + } + if (_textSelectionHelper.endBubbleLine!.bounds.bottom / + heightPercentage == + _textSelectionHelper.startBubbleLine!.bounds.bottom / + heightPercentage && + _endBubbleTapX < _startBubbleTapX) { for ( - int glyphIndex = 0; - glyphIndex < textWord.glyphs.length; - glyphIndex++ + int wordIndex = 0; + wordIndex < + _textSelectionHelper.endBubbleLine!.wordCollection.length; + wordIndex++ ) { - final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; - if (textGlyph.bounds.bottomLeft.dx / heightPercentage == - _textSelectionHelper.startBubbleX! / heightPercentage) { - _textSelectionHelper.endBubbleX = - textGlyph.bounds.bottomRight.dx; - break; + final TextWord textWord = + _textSelectionHelper + .endBubbleLine! + .wordCollection[wordIndex]; + for ( + int glyphIndex = 0; + glyphIndex < textWord.glyphs.length; + glyphIndex++ + ) { + final TextGlyph textGlyph = textWord.glyphs[glyphIndex]; + if (textGlyph.bounds.bottomLeft.dx / heightPercentage == + _textSelectionHelper.startBubbleX! / heightPercentage) { + _textSelectionHelper.endBubbleX = + textGlyph.bounds.bottomRight.dx; + break; + } } } } diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head.dart index 2c55bfc67..949de0b82 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head.dart @@ -53,7 +53,7 @@ class ScrollHead extends StatefulWidget { final PdfPageLayoutMode pageLayoutMode; @override - _ScrollHeadState createState() => _ScrollHeadState(); + State createState() => _ScrollHeadState(); } /// State for [ScrollHead] diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head_overlay.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head_overlay.dart index 6e49ca08e..4613667e8 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head_overlay.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_head_overlay.dart @@ -226,24 +226,6 @@ class ScrollHeadOverlayState extends State { // set x offset as zero offset = Offset(0, offset.dy); } - } else { - if (kIsDesktop && !widget.isMobileWebView) { - if (widget.viewportDimension.width < - widget.maxPdfPageWidth * widget.pdfViewerController.zoomLevel) { - final double clampedX = - tapPosition.dx > widget.maxPdfPageWidth - ? ((widget.maxPdfPageWidth * 2) - - widget.viewportDimension.width) / - 2 - : 0; - offset = Offset( - (widget.scrollDirection == PdfScrollDirection.vertical) - ? clampedX - : offset.dx, - offset.dy, - ); - } - } } final double widthFactor = (widget.pdfDimension.width) - @@ -616,7 +598,7 @@ class ScrollHeadOverlayState extends State { ), TextButton( onPressed: () { - _handlePageNumberValidation(); + _handlePageNumberValidation(context); }, style: isMaterial3 @@ -768,9 +750,11 @@ class ScrollHeadOverlayState extends State { enableInteractiveSelection: false, controller: _textFieldController, autofocus: true, - onEditingComplete: _handlePageNumberValidation, + onEditingComplete: () { + _handlePageNumberValidation(context); + }, onFieldSubmitted: (String value) { - _handlePageNumberValidation(); + _handlePageNumberValidation(context); }, validator: (String? value) { try { @@ -794,7 +778,7 @@ class ScrollHeadOverlayState extends State { } /// Validates the page number entered in text field. - void _handlePageNumberValidation() { + void _handlePageNumberValidation(BuildContext context) { if (_formKey.currentState != null && _formKey.currentState!.validate()) { final int index = int.parse(_textFieldController.text); _textFieldController.clear(); diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_status.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_status.dart index 08b3db775..e010074c9 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_status.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/scroll_status.dart @@ -24,7 +24,7 @@ class ScrollStatus extends StatefulWidget { final bool isSinglePageView; @override - _ScrollStatusState createState() => _ScrollStatusState(); + State createState() => _ScrollStatusState(); } /// State for [ScrollStatus] diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/control/single_page_view.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/control/single_page_view.dart index 3c42ec67a..a6c6c510e 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/control/single_page_view.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/control/single_page_view.dart @@ -374,9 +374,11 @@ class SinglePageViewState extends State { final Offset previousOffset = _currentPageTransformationController .toScene(Offset.zero); _currentPageTransformationController.value = - _currentPageTransformationController.value.clone()..translate( + _currentPageTransformationController.value.clone()..translateByDouble( previousOffset.dx - offset.dx, previousOffset.dy - offset.dy, + 0.0, + 1.0, ); } widget.onPdfOffsetChanged!.call( @@ -648,9 +650,11 @@ class SinglePageViewState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { _currentPageTransformationController.value = _currentPageTransformationController.value.clone() - ..translate( + ..translateByDouble( previousOffset.dx - xPosition, previousOffset.dy - yPosition, + 0.0, + 1.0, ); }); } @@ -959,8 +963,12 @@ class SinglePageViewState extends State { final Offset previousOffset = _currentPageTransformationController .toScene(Offset.zero); _currentPageTransformationController.value = - _currentPageTransformationController.value.clone() - ..scale(zoomChangeFactor, zoomChangeFactor); + _currentPageTransformationController.value.clone()..scaleByDouble( + zoomChangeFactor, + zoomChangeFactor, + zoomChangeFactor, + 1.0, + ); final Offset currentOffset = _currentPageTransformationController.toScene( Offset.zero, ); @@ -972,10 +980,13 @@ class SinglePageViewState extends State { zoomLevel < widget.viewportDimension.width)) { _currentPageTransformationController.value = - _currentPageTransformationController.value.clone()..translate( - currentOffset.dx, - currentOffset.dy / widget.pdfViewerController.zoomLevel, - ); + _currentPageTransformationController.value.clone() + ..translateByDouble( + currentOffset.dx, + currentOffset.dy / widget.pdfViewerController.zoomLevel, + 0.0, + 1.0, + ); } else { greyAreaSize = widget.viewportDimension.height - @@ -1050,10 +1061,13 @@ class SinglePageViewState extends State { final Offset previousOffset = _currentPageTransformationController .toScene(Offset.zero); _currentPageTransformationController.value = - _currentPageTransformationController.value.clone()..translate( - previousOffset.dx - offset.dx.clamp(0, widthFactor.abs()), - -(widget.viewportDimension.height - pdfDimension.height) / 2, - ); + _currentPageTransformationController.value.clone() + ..translateByDouble( + previousOffset.dx - offset.dx.clamp(0, widthFactor.abs()), + -(widget.viewportDimension.height - pdfDimension.height) / 2, + 0.0, + 1.0, + ); } else { if (!kIsDesktop || (kIsDesktop && widget.isMobileWebView)) { isJumpOnZoomedDocument = true; @@ -1088,9 +1102,11 @@ class SinglePageViewState extends State { Offset.zero, ); _currentPageTransformationController.value = - _currentPageTransformationController.value.clone()..translate( + _currentPageTransformationController.value.clone()..translateByDouble( previousOffset.dx - offset.dx, previousOffset.dy - offset.dy, + 0.0, + 1.0, ); widget.onPdfOffsetChanged!.call( _currentPageTransformationController.toScene(Offset.zero), @@ -1185,7 +1201,7 @@ class SinglePageViewState extends State { ), ), ), - _paginationTextField(), + _paginationTextField(context), ], ), ), @@ -1222,7 +1238,7 @@ class SinglePageViewState extends State { ), TextButton( onPressed: () { - _handlePageNumberValidation(); + _handlePageNumberValidation(context); }, style: isMaterial3 @@ -1254,7 +1270,7 @@ class SinglePageViewState extends State { } /// A material design Text field for pagination dialog box. - Widget _paginationTextField() { + Widget _paginationTextField(BuildContext context) { final bool isMaterial3 = Theme.of(context).useMaterial3; return Form( key: _formKey, @@ -1373,9 +1389,11 @@ class SinglePageViewState extends State { enableInteractiveSelection: false, controller: _textFieldController, autofocus: true, - onEditingComplete: _handlePageNumberValidation, + onEditingComplete: () { + _handlePageNumberValidation(context); + }, onFieldSubmitted: (String value) { - _handlePageNumberValidation(); + _handlePageNumberValidation(context); }, validator: (String? value) { try { @@ -1399,7 +1417,7 @@ class SinglePageViewState extends State { } /// Validates the page number entered in text field. - void _handlePageNumberValidation() { + void _handlePageNumberValidation(BuildContext context) { if (_formKey.currentState != null && _formKey.currentState!.validate()) { final int index = int.parse(_textFieldController.text); _textFieldController.clear(); diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_checkbox.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_checkbox.dart index 3a91c145d..f9b5e9240 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_checkbox.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_checkbox.dart @@ -235,7 +235,7 @@ class PdfCheckbox extends StatefulWidget { final double borderWidth; @override - _PdfCheckboxState createState() => _PdfCheckboxState(); + State createState() => _PdfCheckboxState(); } class _PdfCheckboxState extends State { diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_list_box.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_list_box.dart index 61f43e642..9c9146c6a 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_list_box.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_list_box.dart @@ -300,47 +300,51 @@ void _showListBoxDialog( return SizedBox( height: 56.0 * listBoxHelper.listBoxFormField._items.length, width: 348, - child: ListView.builder( - padding: EdgeInsets.zero, - itemBuilder: (BuildContext context, int index) { - return listBoxHelper.isMultiSelect - ? CheckboxListTile( - controlAffinity: ListTileControlAffinity.leading, - title: Text( - listBoxHelper.listBoxFormField._items[index], - ), - value: newItems.contains( - listBoxHelper.listBoxFormField._items[index], - ), - shape: - isMaterial3 - ? RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4.0), - ) - : null, - contentPadding: isMaterial3 ? EdgeInsets.zero : null, - onChanged: (bool? value) { - setState(() { - if (value != null) { - if (value) { - newItems.add( - listBoxHelper.listBoxFormField._items[index], - ); - } else { - newItems.remove( - listBoxHelper.listBoxFormField._items[index], - ); - } - } - }); + child: + listBoxHelper.isMultiSelect + ? ListView.builder( + padding: EdgeInsets.zero, + itemBuilder: (BuildContext context, int index) { + return CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + title: Text( + listBoxHelper.listBoxFormField._items[index], + ), + value: newItems.contains( + listBoxHelper.listBoxFormField._items[index], + ), + shape: + isMaterial3 + ? RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4.0), + ) + : null, + contentPadding: + isMaterial3 ? EdgeInsets.zero : null, + onChanged: (bool? value) { + setState(() { + if (value != null) { + if (value) { + newItems.add( + listBoxHelper + .listBoxFormField + ._items[index], + ); + } else { + newItems.remove( + listBoxHelper + .listBoxFormField + ._items[index], + ); + } + } + }); + }, + ); }, + itemCount: listBoxHelper.listBoxFormField._items.length, ) - : RadioListTile( - controlAffinity: ListTileControlAffinity.leading, - title: Text( - listBoxHelper.listBoxFormField._items[index], - ), - value: listBoxHelper.listBoxFormField._items[index], + : RadioGroup( groupValue: newItems.isEmpty ? null : newItems.first, onChanged: (String? value) { setState(() { @@ -349,10 +353,22 @@ void _showListBoxDialog( } }); }, - ); - }, - itemCount: listBoxHelper.listBoxFormField._items.length, - ), + child: ListView.builder( + padding: EdgeInsets.zero, + itemBuilder: (BuildContext context, int index) { + return RadioListTile( + controlAffinity: ListTileControlAffinity.leading, + title: Text( + listBoxHelper.listBoxFormField._items[index], + ), + value: + listBoxHelper.listBoxFormField._items[index], + ); + }, + itemCount: + listBoxHelper.listBoxFormField._items.length, + ), + ), ); }, ), diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_radio_button.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_radio_button.dart index 44501897b..380ca2fbb 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_radio_button.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/form_fields/pdf_radio_button.dart @@ -199,7 +199,7 @@ class PdfRadioButton extends StatefulWidget { final double borderWidth; @override - _PdfRadioButtonState createState() => _PdfRadioButtonState(); + State createState() => _PdfRadioButtonState(); } class _PdfRadioButtonState extends State { diff --git a/packages/syncfusion_flutter_pdfviewer/lib/src/pdfviewer.dart b/packages/syncfusion_flutter_pdfviewer/lib/src/pdfviewer.dart index 2789bc5da..bc664af03 100644 --- a/packages/syncfusion_flutter_pdfviewer/lib/src/pdfviewer.dart +++ b/packages/syncfusion_flutter_pdfviewer/lib/src/pdfviewer.dart @@ -1203,10 +1203,8 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { late PdfViewerController _pdfViewerController; CancelableOperation? _getPdfFileCancellableOperation; CancelableOperation? _pdfDocumentLoadCancellableOperation; - CancelableOperation?>? _getHeightCancellableOperation, - _getWidthCancellableOperation; - List? _originalHeight; - List? _originalWidth; + List? _originalHeight; + List? _originalWidth; double? _viewportHeightInLandscape; double? _otherContextHeight; double _maxPdfPageWidth = 0.0; @@ -1348,6 +1346,9 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { /// Password used to open the encrypted PDF document. String? _password; + /// Caches the original PDF bytes to avoid redundant loading + Uint8List? _originalSourceBytes; + @override void initState() { super.initState(); @@ -1436,11 +1437,7 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { _undoController?.dispose(); _changeTracker.undoController = _effectiveUndoController; } - _compareDocument( - oldWidget._source.getBytes(context), - widget._source.getBytes(context), - oldWidget.password, - ); + _compareDocument(oldWidget, context); if (oldWidget.pageLayoutMode != widget.pageLayoutMode) { _transformationController.value = Matrix4.identity(); // Content size and view size is handled only for single page layout mode @@ -1490,19 +1487,52 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { // Compares the document bytes and load the PDF document if new bytes are provided. Future _compareDocument( - Future oldBytesData, - Future newBytesData, - String? oldPassword, + SfPdfViewer oldWidget, + BuildContext context, ) async { - final Uint8List oldBytes = await oldBytesData; - final Uint8List newBytes = await newBytesData; - if (!listEquals(oldBytes, newBytes) || - (widget.password != null && widget.password != oldPassword)) { - _password = null; - _pdfViewerController.clearSelection(); - // PDF document gets loaded only when the user changes - // the input source of PDF document. - await _loadPdfDocument(true, false); + Uint8List? oldBytes; + Uint8List? newBytes; + if (widget._source != oldWidget._source || + (widget.password != null && widget.password != oldWidget.password)) { + try { + oldBytes = _originalSourceBytes; + newBytes = await widget._source.getBytes(context); + if (!listEquals(oldBytes, newBytes) || + (widget.password != null && + widget.password != oldWidget.password)) { + _password = null; + _originalSourceBytes = newBytes; + _pdfViewerController.clearSelection(); + // PDF document gets loaded only when the user changes + // the input source of PDF document. + await _loadPdfDocument(true, false, newBytes); + } + } catch (e) { + final String errorMessage = e.toString(); + if (errorMessage.contains('Failed to fetch')) { + widget.onDocumentLoadFailed?.call( + PdfDocumentLoadFailedDetails( + 'Error', + 'Unable to load the document because the URL is invalid or the device is disconnected.', + ), + ); + } else if (errorMessage.contains('Unable to load asset') || + errorMessage.contains('FileSystemException: Cannot open file')) { + widget.onDocumentLoadFailed?.call( + PdfDocumentLoadFailedDetails( + 'File Not Found', + 'The document cannot be opened because the provided path or link is invalid.', + ), + ); + } else { + widget.onDocumentLoadFailed?.call( + PdfDocumentLoadFailedDetails( + 'Error', + 'There was an error opening this document.', + ), + ); + } + } } } @@ -1512,8 +1542,6 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { helper.enableDefaultMenu(); _getPdfFileCancellableOperation?.cancel(); _pdfDocumentLoadCancellableOperation?.cancel(); - _getHeightCancellableOperation?.cancel(); - _getWidthCancellableOperation?.cancel(); _matchedTextPageIndices.clear(); _extractedTextCollection.clear(); _pdfViewerThemeData = null; @@ -2235,13 +2263,21 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { } /// Loads a PDF document and gets the page count from Plugin - Future _loadPdfDocument(bool isPdfChanged, bool isDocumentSaved) async { + Future _loadPdfDocument( + bool isPdfChanged, + bool isDocumentSaved, [ + Uint8List? bytes, + ]) async { try { - if (!_isEncrypted && !isDocumentSaved) { - _getPdfFileCancellableOperation = - CancelableOperation.fromFuture( - widget._source.getBytes(context), - ); + if (bytes == null) { + if (!_isEncrypted && !isDocumentSaved) { + _getPdfFileCancellableOperation = + CancelableOperation.fromFuture( + widget._source.getBytes(context), + ); + bytes = await _getPdfFileCancellableOperation?.value; + _originalSourceBytes = bytes; + } } if (_isAndroid) { await _getAndroidDeviceDetails(); @@ -2251,7 +2287,7 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { ? _decryptedBytes : isDocumentSaved ? _pdfBytes - : (await _getPdfFileCancellableOperation?.value)!; + : bytes!; if (isPdfChanged) { _reset(); _plugin = PdfViewerPlugin(); @@ -2278,16 +2314,7 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { } _pdfViewerController.zoomLevel = widget.initialZoomLevel; _setInitialScrollOffset(); - _getHeightCancellableOperation = - CancelableOperation?>.fromFuture( - _plugin.getPagesHeight(), - ); - _originalHeight = await _getHeightCancellableOperation?.value; - _getWidthCancellableOperation = - CancelableOperation?>.fromFuture( - _plugin.getPagesWidth(), - ); - _originalWidth = await _getWidthCancellableOperation?.value; + _getPageSizes(); } catch (e) { _pdfViewerController._reset(); _hasError = true; @@ -3184,7 +3211,7 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { autofocus: true, focusNode: _focusNode, onFieldSubmitted: (String value) { - _handlePasswordValidation(); + _handlePasswordValidation(context); }, onChanged: isMaterial3 @@ -3269,11 +3296,11 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { isMaterial3 ? (_isPasswordDialogOpenButtonEnabled ? () { - _handlePasswordValidation(); + _handlePasswordValidation(context); } : () {}) : () { - _handlePasswordValidation(); + _handlePasswordValidation(context); }, style: isMaterial3 @@ -3331,10 +3358,10 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { } /// Validates the password entered in text field for mobile. - void _handlePasswordValidation() { + void _handlePasswordValidation(BuildContext context) { if (_formKey.currentState != null && _formKey.currentState!.validate()) { _textFieldController.clear(); - Navigator.of(context, rootNavigator: true).pop(); + Navigator.of(context).pop(); } } @@ -3574,7 +3601,9 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { final bool isPdfLoaded = _pdfViewerController.pageCount > 0 && _originalWidth != null && - _originalHeight != null; + _originalHeight != null && + _originalWidth!.length == _pdfViewerController.pageCount && + _originalHeight!.length == _pdfViewerController.pageCount; _pdfDimension = _childKey.currentContext?.findRenderObject()?.paintBounds.size ?? Size.zero; @@ -3672,8 +3701,8 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { final int pageIndex = index + 1; final Size calculatedSize = _calculateSize( BoxConstraints(maxWidth: _viewportConstraints.maxWidth), - _originalWidth![index].toDouble(), - _originalHeight![index].toDouble(), + _originalWidth![index], + _originalHeight![index], _viewportConstraints.maxWidth, viewportDimension.height, ); @@ -3681,9 +3710,8 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { _pdfPagesKey[pageIndex] = GlobalKey(); } if (kIsDesktop && !_isMobileView) { - if (_originalWidth![index].toDouble() > _maxPdfPageWidth != - null) { - _maxPdfPageWidth = _originalWidth![index].toDouble(); + if (_originalWidth![index] > _maxPdfPageWidth) { + _maxPdfPageWidth = _originalWidth![index]; } } @@ -3924,6 +3952,7 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { _minScale, widget.enableDoubleTapZooming, widget.interactionMode, + widget.pageSpacing, _maxPdfPageWidth, _isScaleEnabled, _maxScrollExtent, @@ -4316,6 +4345,12 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { _canInvokeOnTap &= draggedDistance.dx.abs() < kTouchSlop && draggedDistance.dy.abs() < kTouchSlop; + } else if (event.kind == PointerDeviceKind.stylus || + event.kind == PointerDeviceKind.invertedStylus) { + const double kStylusSlop = kTouchSlop / 3; + _canInvokeOnTap &= + draggedDistance.dx.abs() < kStylusSlop && + draggedDistance.dy.abs() < kStylusSlop; } else { _canInvokeOnTap &= draggedDistance.dx.abs() < kPrecisePointerHitSlop && @@ -4946,8 +4981,8 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { void _updateCurrentPageNumber({double currentOffset = 0}) { if (currentOffset > 0) { _pdfViewerController._pageNumber = - _pdfScrollableStateKey.currentState?.getPageNumber(currentOffset) ?? - 0; + _pdfScrollableStateKey.currentState?.getPageNumber() ?? + _pdfViewerController.pageNumber; } else { if (_textDirection == TextDirection.rtl && _scrollDirection == PdfScrollDirection.horizontal) { @@ -6586,6 +6621,24 @@ class SfPdfViewerState extends State with WidgetsBindingObserver { : offset.dx; _pdfViewerController._scrollPositionY = offset.dy; } + + /// Extracts and stores the width and height of each page from the PDF document. + void _getPageSizes() { + _originalWidth = []; + _originalHeight = []; + for (int pageIndex = 0; pageIndex < _document!.pages.count; pageIndex++) { + final PdfPage page = _document!.pages[pageIndex]; + final bool isRotatedTo90or270 = + page.rotation == PdfPageRotateAngle.rotateAngle90 || + page.rotation == PdfPageRotateAngle.rotateAngle270; + final double width = + isRotatedTo90or270 ? page.size.height : page.size.width; + final double height = + isRotatedTo90or270 ? page.size.width : page.size.height; + _originalWidth!.add(width); + _originalHeight!.add(height); + } + } } /// An object that is used to control the navigation and zooming operations diff --git a/packages/syncfusion_flutter_pdfviewer/pubspec.yaml b/packages/syncfusion_flutter_pdfviewer/pubspec.yaml index 70dd92e1f..f56511dc0 100644 --- a/packages/syncfusion_flutter_pdfviewer/pubspec.yaml +++ b/packages/syncfusion_flutter_pdfviewer/pubspec.yaml @@ -1,12 +1,34 @@ name: syncfusion_flutter_pdfviewer description: Flutter PDF Viewer library is used to display a PDF document seamlessly and efficiently. -version: 30.1.37 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_pdfviewer +screenshots: + - description: 'This screenshot shows the PdfViewer widget, which displays a PDF document.' + path: screenshots/flutter-pdf-viewer.png + - description: 'This screenshot shows the password alert dialog in the PdfViewer widget, which is used to enter the password to open the password-protected PDF document.' + path: screenshots/flutter-pdf-viewer-password-protected.png + - description: 'This screenshot shows the page navigation in the PdfViewer widget that is used to navigate to the desired page.' + path: screenshots/flutter-pdf-viewer-page-navigation.png + - description: 'This screenshot shows the bookmark navigation in the PdfViewer widget that is used to navigate to the desired bookmark.' + path: screenshots/flutter-pdf-viewer-bookmark-navigation.png + - description: 'This screenshot shows the selection and copying of text in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-text-selection.png + - description: 'This screenshot shows the text search in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-text-search.png + - description: 'This screenshot shows the text markup annotation support in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-text-markup.png + - description: 'This screenshot shows the form filling support in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-form-filling.gif + - description: 'This screenshot shows theme support in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-dark-theme.png + - description: 'This screenshot shows the localization support in the PdfViewer widget.' + path: screenshots/flutter-pdf-viewer-localization.png + environment: - sdk: ^3.7.0-0 - flutter: '>=1.20.0' + sdk: ^3.7.0 + flutter: '>=3.35.1' flutter: plugin: @@ -24,7 +46,6 @@ flutter: default_package: syncfusion_pdfviewer_windows linux: default_package: syncfusion_pdfviewer_linux - assets: - assets/icons/dark/ - assets/icons/light/ @@ -36,14 +57,14 @@ flutter: dependencies: flutter: sdk: flutter - vector_math: ^2.1.0 web: ^1.0.0 - async: ^2.5.0 http: ^1.0.0 uuid: ^4.1.0 - device_info_plus: ^11.0.0 + async: ^2.5.0 + vector_math: ^2.2.0 + url_launcher: ^6.1.0 intl: '>=0.18.1 <0.21.0' - + device_info_plus: ^12.1.0 syncfusion_pdfviewer_platform_interface: path: ../syncfusion_flutter_pdfviewer_platform_interface @@ -67,29 +88,3 @@ dependencies: syncfusion_flutter_signaturepad: path: ../syncfusion_flutter_signaturepad - - url_launcher: ^6.1.0 - - - -screenshots: - - description: 'This screenshot shows the PdfViewer widget, which displays a PDF document.' - path: screenshots/flutter-pdf-viewer.png - - description: 'This screenshot shows the password alert dialog in the PdfViewer widget, which is used to enter the password to open the password-protected PDF document.' - path: screenshots/flutter-pdf-viewer-password-protected.png - - description: 'This screenshot shows the page navigation in the PdfViewer widget that is used to navigate to the desired page.' - path: screenshots/flutter-pdf-viewer-page-navigation.png - - description: 'This screenshot shows the bookmark navigation in the PdfViewer widget that is used to navigate to the desired bookmark.' - path: screenshots/flutter-pdf-viewer-bookmark-navigation.png - - description: 'This screenshot shows the selection and copying of text in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-text-selection.png - - description: 'This screenshot shows the text search in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-text-search.png - - description: 'This screenshot shows the text markup annotation support in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-text-markup.png - - description: 'This screenshot shows the form filling support in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-form-filling.gif - - description: 'This screenshot shows theme support in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-dark-theme.png - - description: 'This screenshot shows the localization support in the PdfViewer widget.' - path: screenshots/flutter-pdf-viewer-localization.png diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/CHANGELOG.md b/packages/syncfusion_flutter_pdfviewer_platform_interface/CHANGELOG.md index 701f5bf63..f80e10b73 100644 --- a/packages/syncfusion_flutter_pdfviewer_platform_interface/CHANGELOG.md +++ b/packages/syncfusion_flutter_pdfviewer_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ -## [19.1.54-beta] - 03/30/2021 +## Unreleased + +No changes. + +## [20.1.47-beta] - 04/04/2022 * Initial release. diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada472..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f5853..000000000 Binary files a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_pdfviewer_platform_interface/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdfviewer_platform_interface/pubspec.yaml b/packages/syncfusion_flutter_pdfviewer_platform_interface/pubspec.yaml index 4eef9f1f4..9d3f16588 100644 --- a/packages/syncfusion_flutter_pdfviewer_platform_interface/pubspec.yaml +++ b/packages/syncfusion_flutter_pdfviewer_platform_interface/pubspec.yaml @@ -1,12 +1,12 @@ name: syncfusion_pdfviewer_platform_interface description: A common platform interface for the Flutter PDF Viewer library that lets you view the PDF documents seamlessly and efficiently. -version: 30.1.37 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_pdfviewer_platform_interface environment: - sdk: ^3.7.0-0 - flutter: '>=1.20.0' + sdk: ^3.7.0 + flutter: '>=3.35.1' dependencies: flutter: diff --git a/packages/syncfusion_flutter_signaturepad/CHANGELOG.md b/packages/syncfusion_flutter_signaturepad/CHANGELOG.md index 05bc8a0ae..fcac3eb74 100644 --- a/packages/syncfusion_flutter_signaturepad/CHANGELOG.md +++ b/packages/syncfusion_flutter_signaturepad/CHANGELOG.md @@ -1,6 +1,24 @@ ## Unreleased -* No changes. +* No changes. + +## [31.2.16] - 12/06/2025 + +**Enhancements** + +* The [renderToContext2D](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/renderToContext2D.html) method has been updated to improve signature canvas rendering on the Web platform. + +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter signaturepad widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter signaturepad widget has been updated to Flutter SDK 3.35. ## [30.1.37] - 06/25/2025 diff --git a/packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle b/packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle.kts similarity index 76% rename from packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle rename to packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle.kts index 1c380c08f..cc2db03f2 100644 --- a/packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_signaturepad/example/android/app/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { @@ -11,12 +11,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_signaturepad/example/android/app/src/main/kotlin/com/example/signaturepad_example/MainActivity.kt b/packages/syncfusion_flutter_signaturepad/example/android/app/src/main/kotlin/com/example/signaturepad_example/MainActivity.kt index dae47f03d..d3ecbdd10 100644 --- a/packages/syncfusion_flutter_signaturepad/example/android/app/src/main/kotlin/com/example/signaturepad_example/MainActivity.kt +++ b/packages/syncfusion_flutter_signaturepad/example/android/app/src/main/kotlin/com/example/signaturepad_example/MainActivity.kt @@ -2,4 +2,4 @@ package com.example.signaturepad_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/packages/syncfusion_flutter_signaturepad/example/android/build.gradle b/packages/syncfusion_flutter_signaturepad/example/android/build.gradle deleted file mode 100644 index d2ffbffa4..000000000 --- a/packages/syncfusion_flutter_signaturepad/example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/packages/syncfusion_flutter_signaturepad/example/android/build.gradle.kts b/packages/syncfusion_flutter_signaturepad/example/android/build.gradle.kts new file mode 100644 index 000000000..dbee657bb --- /dev/null +++ b/packages/syncfusion_flutter_signaturepad/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_signaturepad/example/android/gradle.properties b/packages/syncfusion_flutter_signaturepad/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_signaturepad/example/android/gradle.properties +++ b/packages/syncfusion_flutter_signaturepad/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_signaturepad/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_signaturepad/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_signaturepad/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_signaturepad/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle b/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle.kts b/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_signaturepad/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_signaturepad/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_signaturepad/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_signaturepad/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_signaturepad/lib/helper/helper.dart b/packages/syncfusion_flutter_signaturepad/lib/helper/helper.dart new file mode 100644 index 000000000..9b9a90c55 --- /dev/null +++ b/packages/syncfusion_flutter_signaturepad/lib/helper/helper.dart @@ -0,0 +1,53 @@ +import 'dart:ui'; + +// lib/helper/helper.dart +// Platform-agnostic canvas shims (non-web). +// On non‑web platforms, these methods intentionally do nothing. +// Purpose: allow signaturepad.dart to make shared calls without importing +// web‑only Canvas 2D APIs. + +/// Set fill style (color/gradient/pattern). No-op on non-web platforms. +/// fillColor expects an 'r,g,b,a' string (same as web helper). +void fillStyle(dynamic context2D, String fillColor) {} + +/// Set stroke style (color/gradient/pattern). No-op on non-web platforms. +/// strokeColor expects an 'r,g,b,a' string (same as web helper). +void strokeStyle(dynamic context2D, String strokeColor) {} + +/// Fill a rectangle that covers the given size. No-op on non-web platforms. +void fillRect(dynamic context2D, Size size) {} + +/// Fill the current subpath(s). No-op on non-web platforms. +void fill(dynamic context2D) {} + +/// Set the line cap style (e.g., 'round', 'butt', 'square'). No-op here. +void lineCap(dynamic context2D, String lineCap) {} + +/// Set the current line width. No-op on non-web platforms. +void lineWidth(dynamic context2D, double lineWidth) {} + +/// Stroke the current subpath(s). No-op on non-web platforms. +void stroke(dynamic context2D) {} + +/// Begin a new path. No-op on non-web platforms. +void beginPath(dynamic context2D) {} + +/// Add an arc to the current path. No-op on non-web platforms. +void drawContext2DArc( + dynamic context2D, + double x, + double y, + double radius, + double startAngle, + double endAngle, + bool counterclockwise, +) {} + +/// Add a straight line to the current path. No-op on non-web platforms. +void drawContext2DLine( + dynamic context2D, + double x, + double y, + double x1, + double y1, +) {} diff --git a/packages/syncfusion_flutter_signaturepad/lib/helper/web_helper.dart b/packages/syncfusion_flutter_signaturepad/lib/helper/web_helper.dart new file mode 100644 index 000000000..a4d6cf139 --- /dev/null +++ b/packages/syncfusion_flutter_signaturepad/lib/helper/web_helper.dart @@ -0,0 +1,93 @@ +import 'dart:js_interop'; +import 'dart:ui'; +import 'package:web/web.dart' as web; + +// lib/helper/web_helper.dart +// Web-specific CanvasRenderingContext2D helpers. +// These functions directly map to HTML Canvas 2D context operations. + +/// Set the fill style using an 'r,g,b,a' string (converted to 'rgba(...)'). +void fillStyle(dynamic context2D, String fillColor) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.fillStyle = 'rgba($fillColor)'.toJS; + } +} + +/// Set the stroke style using an 'r,g,b,a' string (converted to 'rgba(...)'). +void strokeStyle(dynamic context2D, String strokeColor) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.strokeStyle = 'rgba($strokeColor)'.toJS; + } +} + +/// Fill a rectangle from (0,0) to size.width x size.height. +void fillRect(dynamic context2D, Size size) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.fillRect(0, 0, size.width, size.height); + } +} + +/// Fill the current path. +void fill(dynamic context2D) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.fill(); + } +} + +/// Set the line cap style: 'butt', 'round', or 'square'. +void lineCap(dynamic context2D, String lineCap) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.lineCap = lineCap; + } +} + +/// Set the current stroke width in pixels. +void lineWidth(dynamic context2D, double lineWidth) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.lineWidth = lineWidth; + } +} + +/// Stroke the current path. +void stroke(dynamic context2D) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.stroke(); + } +} + +/// Begin a new path. +void beginPath(dynamic context2D) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.beginPath(); + } +} + +/// Add an arc (circle segment) to the current path and move to its start. +void drawContext2DArc( + dynamic context2D, + double x, + double y, + double radius, + double startAngle, + double endAngle, + bool counterclockwise, +) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.moveTo(x, y); + context2D.arc(x, y, radius, startAngle, endAngle, counterclockwise); + } +} + +/// Add a straight line segment to the current path. +void drawContext2DLine( + dynamic context2D, + double x, + double y, + double x1, + double y1, +) { + if (context2D is web.CanvasRenderingContext2D) { + context2D.moveTo(x, y); + context2D.lineTo(x1, y1); + } +} diff --git a/packages/syncfusion_flutter_signaturepad/lib/signaturepad.dart b/packages/syncfusion_flutter_signaturepad/lib/signaturepad.dart index a62052cc4..1e3fb19dd 100644 --- a/packages/syncfusion_flutter_signaturepad/lib/signaturepad.dart +++ b/packages/syncfusion_flutter_signaturepad/lib/signaturepad.dart @@ -14,6 +14,10 @@ import 'package:flutter/gestures.dart' VerticalDragGestureRecognizer; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'helper/helper.dart' + // On web: uses HTML Canvas 2D implementations (web_helper.dart). + // Elsewhere: uses no-op stubs (helper.dart) because there is no HTML canvas. + if (dart.library.js_interop) 'helper/web_helper.dart'; const double _kMinimumStrokeWidth = 0.8; const double _kMaximumStrokeWidth = 5.0; @@ -1063,17 +1067,17 @@ class RenderSignaturePad extends RenderBox { '${(backgroundColor.r * 255).toInt()},${(backgroundColor.g * 255).toInt()},${(backgroundColor.b * 255).toInt()},${backgroundColor.a.toStringAsFixed(2)}'; //Drawing the background of the SignaturePad - context2D.fillStyle = 'rgba($backgroundFillColor)'; - context2D.fillRect(0, 0, size.width, size.height); - context2D.fill(); + fillStyle(context2D, backgroundFillColor); + fillRect(context2D, size); + fill(context2D); - context2D.beginPath(); + beginPath(context2D); if (!_restrictBezierPathCalculation) { for (int i = 0; i < _dotPoints.length; i++) { final Offset point = _dotPoints[i]; - context2D.moveTo(point.dx, point.dy); - context2D.arc( + drawContext2DArc( + context2D, point.dx, point.dy, (_minimumStrokeWidth + _maximumStrokeWidth) / 2, @@ -1084,8 +1088,8 @@ class RenderSignaturePad extends RenderBox { } for (int i = 0; i < _bezierPoints.length; i++) { - context2D.moveTo(_bezierPoints[i].x, _bezierPoints[i].y); - context2D.arc( + drawContext2DArc( + context2D, _bezierPoints[i].x, _bezierPoints[i].y, _bezierPoints[i].width / 2, @@ -1095,14 +1099,14 @@ class RenderSignaturePad extends RenderBox { ); } - context2D.fillStyle = 'rgba($strokePenColor)'; - context2D.fill(); + fillStyle(context2D, strokePenColor); + fill(context2D); } else { for (int i = 0; i < _data.length; i++) { if (_data[i].length == 1) { final _TouchPoint point = _data[i][0]; - context2D.moveTo(point.x, point.y); - context2D.arc( + drawContext2DArc( + context2D, point.x, point.y, (_minimumStrokeWidth + _maximumStrokeWidth) / 2, @@ -1110,21 +1114,26 @@ class RenderSignaturePad extends RenderBox { pi * 2, true, ); - context2D.fillStyle = 'rgba($strokePenColor)'; - context2D.fill(); + fillStyle(context2D, strokePenColor); + fill(context2D); } else { final List<_TouchPoint> drawPath = _data[i]; for (int i = 0; i < drawPath.length; i++) { if (i < drawPath.length - 1) { - context2D.moveTo(drawPath[i].x, drawPath[i].y); - context2D.lineTo(drawPath[i + 1].x, drawPath[i + 1].y); + drawContext2DLine( + context2D, + drawPath[i].x, + drawPath[i].y, + drawPath[i + 1].x, + drawPath[i + 1].y, + ); } } - context2D.lineWidth = _maximumStrokeWidth; - context2D.strokeStyle = 'rgba($strokePenColor)'; - context2D.lineCap = 'round'; - context2D.stroke(); + lineWidth(context2D, _maximumStrokeWidth); + strokeStyle(context2D, strokePenColor); + lineCap(context2D, 'round'); + stroke(context2D); } } } @@ -1193,7 +1202,7 @@ class RenderSignaturePad extends RenderBox { @override void describeSemanticsConfiguration(SemanticsConfiguration config) { super.describeSemanticsConfiguration(config); - config.isFocusable = true; + config.isFocused = true; } } diff --git a/packages/syncfusion_flutter_signaturepad/pubspec.yaml b/packages/syncfusion_flutter_signaturepad/pubspec.yaml index 23e0c02b4..be3784cc8 100644 --- a/packages/syncfusion_flutter_signaturepad/pubspec.yaml +++ b/packages/syncfusion_flutter_signaturepad/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_signaturepad description: The Flutter Signature Pad widget allows you to capture smooth and more realistic signatures through drawn gestures and save it as an image. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_signaturepad screenshots: @@ -9,12 +9,11 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" dependencies: flutter: sdk: flutter + web: ^1.0.0 syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_sliders/CHANGELOG.md b/packages/syncfusion_flutter_sliders/CHANGELOG.md index 0c96d2d2d..19ef8c02b 100644 --- a/packages/syncfusion_flutter_sliders/CHANGELOG.md +++ b/packages/syncfusion_flutter_sliders/CHANGELOG.md @@ -2,6 +2,18 @@ * No changes. +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter sliders widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter sliders widget has been updated to Flutter SDK 3.35. + ## [30.1.37] - 06/25/2025 **General** diff --git a/packages/syncfusion_flutter_sliders/example/android/app/build.gradle b/packages/syncfusion_flutter_sliders/example/android/app/build.gradle.kts similarity index 76% rename from packages/syncfusion_flutter_sliders/example/android/app/build.gradle rename to packages/syncfusion_flutter_sliders/example/android/app/build.gradle.kts index 58e024b5f..0f8a0acf1 100644 --- a/packages/syncfusion_flutter_sliders/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_sliders/example/android/app/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("dev.flutter.flutter-gradle-plugin") } android { @@ -11,12 +11,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { @@ -34,7 +34,7 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/packages/syncfusion_flutter_sliders/example/android/app/src/main/kotlin/com/example/sliders_sample/MainActivity.kt b/packages/syncfusion_flutter_sliders/example/android/app/src/main/kotlin/com/example/sliders_sample/MainActivity.kt index db564c5ca..01bf6e3fa 100644 --- a/packages/syncfusion_flutter_sliders/example/android/app/src/main/kotlin/com/example/sliders_sample/MainActivity.kt +++ b/packages/syncfusion_flutter_sliders/example/android/app/src/main/kotlin/com/example/sliders_sample/MainActivity.kt @@ -2,4 +2,4 @@ package com.example.sliders_sample import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/packages/syncfusion_flutter_sliders/example/android/build.gradle b/packages/syncfusion_flutter_sliders/example/android/build.gradle deleted file mode 100644 index d2ffbffa4..000000000 --- a/packages/syncfusion_flutter_sliders/example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/packages/syncfusion_flutter_sliders/example/android/build.gradle.kts b/packages/syncfusion_flutter_sliders/example/android/build.gradle.kts new file mode 100644 index 000000000..dbee657bb --- /dev/null +++ b/packages/syncfusion_flutter_sliders/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/syncfusion_flutter_sliders/example/android/gradle.properties b/packages/syncfusion_flutter_sliders/example/android/gradle.properties index 259717082..f018a6181 100644 --- a/packages/syncfusion_flutter_sliders/example/android/gradle.properties +++ b/packages/syncfusion_flutter_sliders/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/packages/syncfusion_flutter_sliders/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_sliders/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..ac3b47926 100644 --- a/packages/syncfusion_flutter_sliders/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_sliders/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_sliders/example/android/settings.gradle b/packages/syncfusion_flutter_sliders/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/syncfusion_flutter_sliders/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/syncfusion_flutter_sliders/example/android/settings.gradle.kts b/packages/syncfusion_flutter_sliders/example/android/settings.gradle.kts new file mode 100644 index 000000000..c571d1e63 --- /dev/null +++ b/packages/syncfusion_flutter_sliders/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/packages/syncfusion_flutter_sliders/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_sliders/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_sliders/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_sliders/lib/src/range_selector.dart b/packages/syncfusion_flutter_sliders/lib/src/range_selector.dart index d07161026..2cc97b47f 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/range_selector.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/range_selector.dart @@ -1736,18 +1736,18 @@ class _SfRangeSelectorState extends State } SfRangeSelectorThemeData _getRangeSelectorThemeData(ThemeData themeData) { - SfRangeSelectorThemeData rangeSelectorThemeData = SfRangeSelectorTheme.of( - context, - )!; + SfRangeSelectorThemeData rangeSelectorThemeData = + SfRangeSelectorTheme.of(context)!; final bool isMaterial3 = themeData.useMaterial3; final SfRangeSelectorThemeData effectiveThemeData = RangeSelectorThemeData( context, ); - final Color labelColor = isMaterial3 - ? themeData.colorScheme.onSurfaceVariant - : widget.enabled - ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) - : themeData.colorScheme.onSurface.withValues(alpha: 0.32); + final Color labelColor = + isMaterial3 + ? themeData.colorScheme.onSurfaceVariant + : widget.enabled + ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) + : themeData.colorScheme.onSurface.withValues(alpha: 0.32); final double minTrackHeight = math.min( rangeSelectorThemeData.activeTrackHeight, rangeSelectorThemeData.inactiveTrackHeight, @@ -1774,9 +1774,10 @@ class _SfRangeSelectorState extends State tooltipTextStyle: themeData.textTheme.bodyLarge! .copyWith( fontSize: isMaterial3 ? 12 : 14, - color: isMaterial3 - ? themeData.colorScheme.onPrimary - : themeData.colorScheme.surface, + color: + isMaterial3 + ? themeData.colorScheme.onPrimary + : themeData.colorScheme.surface, ) .merge(rangeSelectorThemeData.tooltipTextStyle), inactiveTrackColor: @@ -1922,9 +1923,8 @@ class _SfRangeSelectorState extends State vsync: this, duration: duration, ); - stateController.value = widget.enabled && (widget.min != widget.max) - ? 1.0 - : 0.0; + stateController.value = + widget.enabled && (widget.min != widget.max) ? 1.0 : 0.0; _keyboardActionMap = >{ SliderKeyIntent: CallbackAction( @@ -2599,8 +2599,10 @@ class _RenderRangeSelector extends RenderBaseRangeSlider { // So we adjust track offset to ignore that gap. double get adjustTrackY => sliderThemeData.activeTrackHeight > sliderThemeData.inactiveTrackHeight - ? sliderThemeData.activeTrackHeight - sliderThemeData.inactiveTrackHeight - : sliderThemeData.inactiveTrackHeight - sliderThemeData.activeTrackHeight; + ? sliderThemeData.activeTrackHeight - + sliderThemeData.inactiveTrackHeight + : sliderThemeData.inactiveTrackHeight - + sliderThemeData.activeTrackHeight; void _updateNewValues(SfRangeValues newValues) { if (_state.widget.onChanged != null) { @@ -2681,9 +2683,10 @@ class _RenderRangeSelector extends RenderBaseRangeSlider { Offset startThumbCenter, Offset endThumbCenter, ) { - final Paint inactivePaint = Paint() - ..isAntiAlias = true - ..color = _inactiveRegionColor; + final Paint inactivePaint = + Paint() + ..isAntiAlias = true + ..color = _inactiveRegionColor; if (child != null && child!.size.height > 1 && child!.size.width > 1) { final double halfActiveTrackHeight = sliderThemeData.activeTrackHeight / 2; @@ -2703,12 +2706,10 @@ class _RenderRangeSelector extends RenderBaseRangeSlider { } //Below values are used to fit active and inactive region into the track. - final double inactiveRegionAdj = isMaxActive - ? halfActiveTrackHeight - halfInactiveTrackHeight - : 0; - final double activeRegionAdj = !isMaxActive - ? halfInactiveTrackHeight - halfActiveTrackHeight - : 0; + final double inactiveRegionAdj = + isMaxActive ? halfActiveTrackHeight - halfInactiveTrackHeight : 0; + final double activeRegionAdj = + !isMaxActive ? halfInactiveTrackHeight - halfActiveTrackHeight : 0; context.canvas.drawRect( Rect.fromLTRB( trackRect.left, @@ -2718,9 +2719,10 @@ class _RenderRangeSelector extends RenderBaseRangeSlider { ), inactivePaint, ); - final Paint activePaint = Paint() - ..isAntiAlias = true - ..color = _activeRegionColor; + final Paint activePaint = + Paint() + ..isAntiAlias = true + ..color = _activeRegionColor; context.canvas.drawRect( Rect.fromLTRB( leftThumbCenter.dx, @@ -2865,9 +2867,10 @@ class _RenderRangeSelector extends RenderBaseRangeSlider { startThumbIcon?.layout(contentConstraints, parentUsesSize: true); endThumbIcon?.layout(contentConstraints, parentUsesSize: true); - final double actualWidth = childWidth > 0.0 - ? (childWidth + 2 * trackOffset.dx) - : minTrackWidth + 2 * trackOffset.dx; + final double actualWidth = + childWidth > 0.0 + ? (childWidth + 2 * trackOffset.dx) + : minTrackWidth + 2 * trackOffset.dx; final double actualHeight = childHeight + elementsHeightAfterRenderedChild; size = Size( diff --git a/packages/syncfusion_flutter_sliders/lib/src/range_slider.dart b/packages/syncfusion_flutter_sliders/lib/src/range_slider.dart index ca148cd2a..98c66ccc0 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/range_slider.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/range_slider.dart @@ -1620,18 +1620,18 @@ class _SfRangeSliderState extends State ThemeData themeData, bool isActive, ) { - SfRangeSliderThemeData rangeSliderThemeData = SfRangeSliderTheme.of( - context, - )!; + SfRangeSliderThemeData rangeSliderThemeData = + SfRangeSliderTheme.of(context)!; final bool isMaterial3 = themeData.useMaterial3; final SfRangeSliderThemeData effectiveThemeData = RangeSliderThemeData( context, ); - final Color labelColor = isMaterial3 - ? themeData.colorScheme.onSurfaceVariant - : isActive - ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) - : themeData.colorScheme.onSurface.withValues(alpha: 0.32); + final Color labelColor = + isMaterial3 + ? themeData.colorScheme.onSurfaceVariant + : isActive + ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) + : themeData.colorScheme.onSurface.withValues(alpha: 0.32); final double minTrackHeight = math.min( rangeSliderThemeData.activeTrackHeight, rangeSliderThemeData.inactiveTrackHeight, @@ -1653,9 +1653,10 @@ class _SfRangeSliderState extends State tooltipTextStyle: themeData.textTheme.bodyLarge! .copyWith( fontSize: isMaterial3 ? 12 : 14, - color: isMaterial3 - ? themeData.colorScheme.onPrimary - : themeData.colorScheme.surface, + color: + isMaterial3 + ? themeData.colorScheme.onPrimary + : themeData.colorScheme.surface, ) .merge(rangeSliderThemeData.tooltipTextStyle), inactiveTrackColor: @@ -2496,21 +2497,22 @@ class _RenderRangeSlider extends RenderBaseRangeSlider { @override void paint(PaintingContext context, Offset offset) { - final Offset actualTrackOffset = sliderType == SliderType.horizontal - ? Offset( - offset.dx, - offset.dy + - (size.height - actualHeight) / 2 + - trackOffset.dy - - maxTrackHeight / 2, - ) - : Offset( - offset.dx + - (size.width - actualHeight) / 2 + - trackOffset.dx - - maxTrackHeight / 2, - offset.dy, - ); + final Offset actualTrackOffset = + sliderType == SliderType.horizontal + ? Offset( + offset.dx, + offset.dy + + (size.height - actualHeight) / 2 + + trackOffset.dy - + maxTrackHeight / 2, + ) + : Offset( + offset.dx + + (size.width - actualHeight) / 2 + + trackOffset.dx - + maxTrackHeight / 2, + offset.dy, + ); drawRangeSliderElements(context, offset, actualTrackOffset); } @@ -2571,12 +2573,14 @@ class _RenderRangeSlider extends RenderBaseRangeSlider { _decreaseEndAction, ); // Split the semantics node area between the start and end nodes. - final Rect startRect = sliderType == SliderType.horizontal - ? Rect.fromPoints(node.rect.topLeft, node.rect.bottomCenter) - : Rect.fromPoints(node.rect.bottomRight, node.rect.centerLeft); - final Rect endRect = sliderType == SliderType.horizontal - ? Rect.fromPoints(node.rect.topCenter, node.rect.bottomRight) - : Rect.fromPoints(node.rect.centerLeft, node.rect.topRight); + final Rect startRect = + sliderType == SliderType.horizontal + ? Rect.fromPoints(node.rect.topLeft, node.rect.bottomCenter) + : Rect.fromPoints(node.rect.bottomRight, node.rect.centerLeft); + final Rect endRect = + sliderType == SliderType.horizontal + ? Rect.fromPoints(node.rect.topCenter, node.rect.bottomRight) + : Rect.fromPoints(node.rect.centerLeft, node.rect.topRight); startSemanticsNode ??= SemanticsNode(); endSemanticsNode ??= SemanticsNode(); if (sliderType == SliderType.vertical || diff --git a/packages/syncfusion_flutter_sliders/lib/src/range_slider_base.dart b/packages/syncfusion_flutter_sliders/lib/src/range_slider_base.dart index 770732764..7ecb5c2ee 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/range_slider_base.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/range_slider_base.dart @@ -99,28 +99,31 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider ) { final GestureArenaTeam team = GestureArenaTeam(); if (sliderType == SliderType.horizontal) { - horizontalDragGestureRecognizer = HorizontalDragGestureRecognizer() - ..team = team - ..onDown = _onDragDown - ..onStart = _onDragStart - ..onUpdate = _onDragUpdate - ..onEnd = _onDragEnd - ..onCancel = _onDragCancel - ..gestureSettings = gestureSettings; + horizontalDragGestureRecognizer = + HorizontalDragGestureRecognizer() + ..team = team + ..onDown = _onDragDown + ..onStart = _onDragStart + ..onUpdate = _onDragUpdate + ..onEnd = _onDragEnd + ..onCancel = _onDragCancel + ..gestureSettings = gestureSettings; } if (sliderType == SliderType.vertical) { - verticalDragGestureRecognizer = VerticalDragGestureRecognizer() - ..team = team - ..onStart = _onVerticalDragStart - ..onUpdate = _onVerticalDragUpdate - ..onEnd = _onVerticalDragEnd - ..onCancel = _onVerticalDragCancel - ..gestureSettings = gestureSettings; + verticalDragGestureRecognizer = + VerticalDragGestureRecognizer() + ..team = team + ..onStart = _onVerticalDragStart + ..onUpdate = _onVerticalDragUpdate + ..onEnd = _onVerticalDragEnd + ..onCancel = _onVerticalDragCancel + ..gestureSettings = gestureSettings; } - tapGestureRecognizer = TapGestureRecognizer() - ..team = team - ..onTapDown = _onTapDown - ..onTapUp = _onTapUp; + tapGestureRecognizer = + TapGestureRecognizer() + ..team = team + ..onTapDown = _onTapDown + ..onTapUp = _onTapUp; _overlayStartAnimation = CurvedAnimation( parent: overlayStartController, @@ -296,12 +299,13 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider if (_values == values) { return; } - _values = isDateTime - ? values - : SfRangeValues( - (values.start as num).toDouble(), - (values.end as num).toDouble(), - ); + _values = + isDateTime + ? values + : SfRangeValues( + (values.start as num).toDouble(), + (values.end as num).toDouble(), + ); if (isDateTime) { _valuesInMilliseconds = SfRangeValues( _values.start.millisecondsSinceEpoch.toDouble(), @@ -390,11 +394,14 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider endPositionController.value = getFactorFromValue(actualValues.end); } - double get minThumbGap => isDiscrete - ? 0 - : sliderType == SliderType.horizontal - ? (actualMax - actualMin) * (8 / actualTrackRect.width).clamp(0.0, 1.0) - : (actualMax - actualMin) * (8 / actualTrackRect.height).clamp(0.0, 1.0); + double get minThumbGap => + isDiscrete + ? 0 + : sliderType == SliderType.horizontal + ? (actualMax - actualMin) * + (8 / actualTrackRect.width).clamp(0.0, 1.0) + : (actualMax - actualMin) * + (8 / actualTrackRect.height).clamp(0.0, 1.0); SfRangeValues get actualValues => isDateTime ? _valuesInMilliseconds : _values; @@ -451,9 +458,10 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider void _onTapDown(TapDownDetails details) { currentPointerType = PointerType.down; - _interactionStartOffset = sliderType == SliderType.horizontal - ? globalToLocal(details.globalPosition).dx - : globalToLocal(details.globalPosition).dy; + _interactionStartOffset = + sliderType == SliderType.horizontal + ? globalToLocal(details.globalPosition).dx + : globalToLocal(details.globalPosition).dy; mainAxisOffset = _interactionStartOffset; _beginInteraction(); } @@ -585,9 +593,9 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider return ((sliderType == SliderType.horizontal && !isInversed) || (sliderType == SliderType.vertical && isInversed)) ? mainAxisOffset > (startPosition + thumbRadius) && - mainAxisOffset < (endPosition - thumbRadius) + mainAxisOffset < (endPosition - thumbRadius) : mainAxisOffset < (startPosition - thumbRadius) && - mainAxisOffset > (endPosition + thumbRadius); + mainAxisOffset > (endPosition + thumbRadius); } void _forwardTooltipAnimation() { @@ -681,8 +689,8 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider ); final double lockedRangeWidth = (!isVertical && isInversed) || (isVertical && !isInversed) - ? startPosition - endPosition - : endPosition - startPosition; + ? startPosition - endPosition + : endPosition - startPosition; startPosition += delta ?? 0.0; endPosition += delta ?? 0.0; final double actualMinInPx = getPositionFromValue(actualMin); @@ -796,9 +804,10 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider break; } } else { - start = isDateTime - ? DateTime.fromMillisecondsSinceEpoch(currentLabel.toInt()) - : currentLabel; + start = + isDateTime + ? DateTime.fromMillisecondsSinceEpoch(currentLabel.toInt()) + : currentLabel; // ignore: unnecessary_this end = this.max; rangeValues = SfRangeValues(start, end); @@ -830,12 +839,14 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider final double endDistanceFactor = (endValueFactor - endPositionController.value).abs(); - startPositionController.duration = startDistanceFactor != 0.0 - ? _positionAnimationDuration * (1.0 / startDistanceFactor) - : Duration.zero; - endPositionController.duration = endDistanceFactor != 0.0 - ? _positionAnimationDuration * (1.0 / endDistanceFactor) - : Duration.zero; + startPositionController.duration = + startDistanceFactor != 0.0 + ? _positionAnimationDuration * (1.0 / startDistanceFactor) + : Duration.zero; + endPositionController.duration = + endDistanceFactor != 0.0 + ? _positionAnimationDuration * (1.0 / endDistanceFactor) + : Duration.zero; startPositionController.animateTo( startValueFactor, curve: Curves.easeInOut, @@ -926,11 +937,12 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider final double endThumbPosition = getPositionFromValue( actualValues.end.toDouble(), ); - cursorPosition = sliderType == SliderType.horizontal - ? details.localPosition.dx - : details.localPosition.dy; - final double startThumbDistance = (cursorPosition - startThumbPosition) - .abs(); + cursorPosition = + sliderType == SliderType.horizontal + ? details.localPosition.dx + : details.localPosition.dy; + final double startThumbDistance = + (cursorPosition - startThumbPosition).abs(); final double endThumbDistance = (cursorPosition - endThumbPosition).abs(); final double thumbRadius = (sliderType == SliderType.horizontal @@ -1019,8 +1031,8 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider _valuesInMilliseconds.start == _valuesInMilliseconds.end) { activeThumb = _valuesInMilliseconds.start == min.millisecondsSinceEpoch.toDouble() - ? SfThumb.end - : SfThumb.start; + ? SfThumb.end + : SfThumb.start; } else if (_values.start == _values.end) { activeThumb = _values.start == min ? SfThumb.end : SfThumb.start; } @@ -1054,9 +1066,8 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider parentBox: this, themeData: sliderThemeData, currentValues: _values, - animation: isStartThumbActive - ? _overlayEndAnimation - : _overlayStartAnimation, + animation: + isStartThumbActive ? _overlayEndAnimation : _overlayStartAnimation, thumb: isStartThumbActive ? SfThumb.end : SfThumb.start, paint: null, ); @@ -1095,9 +1106,8 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider parentBox: this, themeData: sliderThemeData, currentValues: _values, - animation: isStartThumbActive - ? _overlayStartAnimation - : _overlayEndAnimation, + animation: + isStartThumbActive ? _overlayStartAnimation : _overlayEndAnimation, thumb: activeThumb, paint: null, ); @@ -1136,18 +1146,19 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider Rect trackRect, ) { if (willDrawTooltip || shouldAlwaysShowTooltip) { - final Paint paint = Paint() - ..color = sliderThemeData.tooltipBackgroundColor! - ..style = PaintingStyle.fill - ..strokeWidth = 0; + final Paint paint = + Paint() + ..color = sliderThemeData.tooltipBackgroundColor! + ..style = PaintingStyle.fill + ..strokeWidth = 0; final bool isStartThumbActive = activeThumb == SfThumb.start; - Offset thumbCenter = isStartThumbActive - ? endThumbCenter - : startThumbCenter; - dynamic actualText = (sliderType == SliderType.horizontal) - ? getValueFromPosition(thumbCenter.dx - offset.dx) - : getValueFromPosition(trackRect.bottom - thumbCenter.dy); + Offset thumbCenter = + isStartThumbActive ? endThumbCenter : startThumbCenter; + dynamic actualText = + (sliderType == SliderType.horizontal) + ? getValueFromPosition(thumbCenter.dx - offset.dx) + : getValueFromPosition(trackRect.bottom - thumbCenter.dy); String tooltipText = tooltipTextFormatterCallback( actualText, @@ -1190,16 +1201,16 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider parentBox: this, sliderThemeData: sliderThemeData, paint: paint, - animation: isStartThumbActive - ? _tooltipEndAnimation - : _tooltipStartAnimation, + animation: + isStartThumbActive ? _tooltipEndAnimation : _tooltipStartAnimation, trackRect: trackRect, ); thumbCenter = isStartThumbActive ? startThumbCenter : endThumbCenter; - actualText = (sliderType == SliderType.horizontal) - ? getValueFromPosition(thumbCenter.dx - offset.dx) - : getValueFromPosition(trackRect.bottom - thumbCenter.dy); + actualText = + (sliderType == SliderType.horizontal) + ? getValueFromPosition(thumbCenter.dx - offset.dx) + : getValueFromPosition(trackRect.bottom - thumbCenter.dy); tooltipText = tooltipTextFormatterCallback( actualText, @@ -1233,9 +1244,10 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider } if (bottomTooltipRect != null && topTooltipRect != null) { final Rect overlapRect = topTooltipRect.intersect(bottomTooltipRect); - showOverlappingTooltipStroke = sliderType == SliderType.horizontal - ? overlapRect.right > overlapRect.left - : overlapRect.top < overlapRect.bottom; + showOverlappingTooltipStroke = + sliderType == SliderType.horizontal + ? overlapRect.right > overlapRect.left + : overlapRect.top < overlapRect.bottom; } tooltipShape.paint( @@ -1246,9 +1258,8 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider parentBox: this, sliderThemeData: sliderThemeData, paint: paint, - animation: isStartThumbActive - ? _tooltipStartAnimation - : _tooltipEndAnimation, + animation: + isStartThumbActive ? _tooltipStartAnimation : _tooltipEndAnimation, trackRect: trackRect, ); } @@ -1398,12 +1409,14 @@ abstract class RenderBaseRangeSlider extends RenderBaseSlider sliderThemeData, actualTrackOffset, ); - double thumbStartPosition = isIntervalTapped - ? startPositionController.value - : getFactorFromValue(actualValues.start); - double thumbEndPosition = isIntervalTapped - ? endPositionController.value - : getFactorFromValue(actualValues.end); + double thumbStartPosition = + isIntervalTapped + ? startPositionController.value + : getFactorFromValue(actualValues.start); + double thumbEndPosition = + isIntervalTapped + ? endPositionController.value + : getFactorFromValue(actualValues.end); if (sliderType == SliderType.horizontal) { thumbStartPosition = thumbStartPosition * trackRect.width; diff --git a/packages/syncfusion_flutter_sliders/lib/src/slider.dart b/packages/syncfusion_flutter_sliders/lib/src/slider.dart index c396e8751..f1e45c0b8 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/slider.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/slider.dart @@ -1427,11 +1427,12 @@ class _SfSliderState extends State with TickerProviderStateMixin { /// An instance for SlidersThemeData class final SfSliderThemeData effectiveThemeData = SlidersThemeData(context); final bool isMaterial3 = themeData.useMaterial3; - final Color labelColor = isMaterial3 - ? themeData.colorScheme.onSurfaceVariant - : isActive - ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) - : themeData.colorScheme.onSurface.withValues(alpha: 0.32); + final Color labelColor = + isMaterial3 + ? themeData.colorScheme.onSurfaceVariant + : isActive + ? themeData.textTheme.bodyLarge!.color!.withValues(alpha: 0.87) + : themeData.colorScheme.onSurface.withValues(alpha: 0.32); final double minTrackHeight = math.min( sliderThemeData.activeTrackHeight, sliderThemeData.inactiveTrackHeight, @@ -1453,9 +1454,10 @@ class _SfSliderState extends State with TickerProviderStateMixin { tooltipTextStyle: themeData.textTheme.bodyLarge! .copyWith( fontSize: isMaterial3 ? 12 : 14, - color: isMaterial3 - ? themeData.colorScheme.onPrimary - : themeData.colorScheme.surface, + color: + isMaterial3 + ? themeData.colorScheme.onPrimary + : themeData.colorScheme.surface, ) .merge(sliderThemeData.tooltipTextStyle), inactiveTrackColor: @@ -2051,29 +2053,32 @@ class _RenderSlider extends RenderBaseSlider implements MouseTrackerAnnotation { ) { final GestureArenaTeam team = GestureArenaTeam(); if (sliderType == SliderType.horizontal) { - horizontalDragGestureRecognizer = HorizontalDragGestureRecognizer() - ..team = team - ..onStart = _onDragStart - ..onUpdate = _onDragUpdate - ..onEnd = _onDragEnd - ..onCancel = _onDragCancel - ..gestureSettings = gestureSettings; + horizontalDragGestureRecognizer = + HorizontalDragGestureRecognizer() + ..team = team + ..onStart = _onDragStart + ..onUpdate = _onDragUpdate + ..onEnd = _onDragEnd + ..onCancel = _onDragCancel + ..gestureSettings = gestureSettings; } if (sliderType == SliderType.vertical) { - verticalDragGestureRecognizer = VerticalDragGestureRecognizer() - ..team = team - ..onStart = _onVerticalDragStart - ..onUpdate = _onVerticalDragUpdate - ..onEnd = _onVerticalDragEnd - ..onCancel = _onVerticalDragCancel - ..gestureSettings = gestureSettings; + verticalDragGestureRecognizer = + VerticalDragGestureRecognizer() + ..team = team + ..onStart = _onVerticalDragStart + ..onUpdate = _onVerticalDragUpdate + ..onEnd = _onVerticalDragEnd + ..onCancel = _onVerticalDragCancel + ..gestureSettings = gestureSettings; } - tapGestureRecognizer = TapGestureRecognizer() - ..team = team - ..onTapDown = _onTapDown - ..onTapUp = _onTapUp; + tapGestureRecognizer = + TapGestureRecognizer() + ..team = team + ..onTapDown = _onTapDown + ..onTapUp = _onTapUp; _overlayAnimation = CurvedAnimation( parent: _state.overlayController, @@ -2265,9 +2270,10 @@ class _RenderSlider extends RenderBaseSlider implements MouseTrackerAnnotation { void _onTapDown(TapDownDetails details) { currentPointerType = PointerType.down; - mainAxisOffset = sliderType == SliderType.horizontal - ? globalToLocal(details.globalPosition).dx - : globalToLocal(details.globalPosition).dy; + mainAxisOffset = + sliderType == SliderType.horizontal + ? globalToLocal(details.globalPosition).dx + : globalToLocal(details.globalPosition).dy; _beginInteraction(); } @@ -2385,14 +2391,16 @@ class _RenderSlider extends RenderBaseSlider implements MouseTrackerAnnotation { Rect trackRect, ) { if (willDrawTooltip || shouldAlwaysShowTooltip) { - final Paint paint = Paint() - ..color = sliderThemeData.tooltipBackgroundColor! - ..style = PaintingStyle.fill - ..strokeWidth = 0; - - final dynamic actualText = sliderType == SliderType.horizontal - ? getValueFromPosition(thumbCenter.dx - offset.dx) - : getValueFromPosition(trackRect.bottom - thumbCenter.dy); + final Paint paint = + Paint() + ..color = sliderThemeData.tooltipBackgroundColor! + ..style = PaintingStyle.fill + ..strokeWidth = 0; + + final dynamic actualText = + sliderType == SliderType.horizontal + ? getValueFromPosition(thumbCenter.dx - offset.dx) + : getValueFromPosition(trackRect.bottom - thumbCenter.dy); final String tooltipText = tooltipTextFormatterCallback( actualText, getFormattedText(actualText), @@ -2543,21 +2551,22 @@ class _RenderSlider extends RenderBaseSlider implements MouseTrackerAnnotation { @override void paint(PaintingContext context, Offset offset) { - final Offset actualTrackOffset = sliderType == SliderType.horizontal - ? Offset( - offset.dx, - offset.dy + - (size.height - actualHeight) / 2 + - trackOffset.dy - - maxTrackHeight / 2, - ) - : Offset( - offset.dx + - (size.width - actualHeight) / 2 + - trackOffset.dx - - maxTrackHeight / 2, - offset.dy, - ); + final Offset actualTrackOffset = + sliderType == SliderType.horizontal + ? Offset( + offset.dx, + offset.dy + + (size.height - actualHeight) / 2 + + trackOffset.dy - + maxTrackHeight / 2, + ) + : Offset( + offset.dx + + (size.width - actualHeight) / 2 + + trackOffset.dx - + maxTrackHeight / 2, + offset.dy, + ); // Drawing track. final Rect trackRect = trackShape.getPreferredRect( @@ -2570,9 +2579,10 @@ class _RenderSlider extends RenderBaseSlider implements MouseTrackerAnnotation { (sliderType == SliderType.horizontal ? trackRect.width : trackRect.height); - final Offset thumbCenter = sliderType == SliderType.horizontal - ? Offset(trackRect.left + thumbPosition, trackRect.center.dy) - : Offset(trackRect.center.dx, trackRect.bottom - thumbPosition); + final Offset thumbCenter = + sliderType == SliderType.horizontal + ? Offset(trackRect.left + thumbPosition, trackRect.center.dy) + : Offset(trackRect.center.dx, trackRect.bottom - thumbPosition); trackShape.paint( context, diff --git a/packages/syncfusion_flutter_sliders/lib/src/slider_base.dart b/packages/syncfusion_flutter_sliders/lib/src/slider_base.dart index 247a82f18..24c0b0bc6 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/slider_base.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/slider_base.dart @@ -535,20 +535,22 @@ class RenderBaseSlider extends RenderProxyBox Size get actualOverlaySize => _overlayShape.getPreferredSize(_sliderThemeData); - double get actualTickHeight => _showTicks - ? _sliderThemeData.tickSize!.height + - (_sliderThemeData.tickOffset != null - ? _sliderThemeData.tickOffset!.dy - : 0) - : 0; + double get actualTickHeight => + _showTicks + ? _sliderThemeData.tickSize!.height + + (_sliderThemeData.tickOffset != null + ? _sliderThemeData.tickOffset!.dy + : 0) + : 0; // actualTickWidth is applicable only for vertical sliders - double get actualTickWidth => _showTicks - ? _sliderThemeData.tickSize!.width + - (_sliderThemeData.tickOffset != null - ? _sliderThemeData.tickOffset!.dx - : 0) - : 0; + double get actualTickWidth => + _showTicks + ? _sliderThemeData.tickSize!.width + + (_sliderThemeData.tickOffset != null + ? _sliderThemeData.tickOffset!.dx + : 0) + : 0; double get actualMinorTickHeight => _minorTicksPerInterval > 0 ? actualMinorTickSize.height : 0; @@ -557,32 +559,37 @@ class RenderBaseSlider extends RenderProxyBox double get actualMinorTickWidth => _minorTicksPerInterval > 0 ? actualMinorTickSize.width : 0; - double get actualLabelHeight => _showLabels - ? textPainter.textScaler.scale(actualLabelSize.height) + - (_sliderThemeData.labelOffset != null - ? _sliderThemeData.labelOffset!.dy - : 0) - : 0; + double get actualLabelHeight => + _showLabels + ? textPainter.textScaler.scale(actualLabelSize.height) + + (_sliderThemeData.labelOffset != null + ? _sliderThemeData.labelOffset!.dy + : 0) + : 0; // actualLabelOffset is applicable only for vertical sliders - double get actualLabelOffset => _showLabels - ? _sliderThemeData.labelOffset != null - ? (_sliderThemeData.labelOffset!.dx) - : 0 - : 0; + double get actualLabelOffset => + _showLabels + ? _sliderThemeData.labelOffset != null + ? (_sliderThemeData.labelOffset!.dx) + : 0 + : 0; // Here 10 is a gap between tooltip nose and thumb. - double get tooltipStartY => (sliderType == SliderType.horizontal) - ? _tooltipShape is SfPaddleTooltipShape - ? math.max(actualThumbSize.height, actualTrackRect.height) / 2 - : math.max(actualThumbSize.height, actualTrackRect.height) / 2 + 10 - : math.max(actualThumbSize.width, actualTrackRect.width) / 2 + 10; + double get tooltipStartY => + (sliderType == SliderType.horizontal) + ? _tooltipShape is SfPaddleTooltipShape + ? math.max(actualThumbSize.height, actualTrackRect.height) / 2 + : math.max(actualThumbSize.height, actualTrackRect.height) / 2 + + 10 + : math.max(actualThumbSize.width, actualTrackRect.width) / 2 + 10; double get adjustmentUnit => (actualMax - actualMin) / 10; - dynamic get semanticActionUnit => isDateTime - ? _stepDuration ?? adjustmentUnit - : _stepSize ?? adjustmentUnit; + dynamic get semanticActionUnit => + isDateTime + ? _stepDuration ?? adjustmentUnit + : _stepSize ?? adjustmentUnit; void updateTextPainter() { textPainter @@ -632,10 +639,11 @@ class RenderBaseSlider extends RenderProxyBox // If min and max are equal, the result will be NAN. This creates exception // and widget will not rendered. // So we have checked a condition (actualMax <= actualMin). - final double factor = (value == null || actualMax <= actualMin) - ? 0.0 - // ignore: avoid_as - : (value - actualMin) / (actualMax - actualMin) as double; + final double factor = + (value == null || actualMax <= actualMin) + ? 0.0 + // ignore: avoid_as + : (value - actualMin) / (actualMax - actualMin) as double; if (_isInversed) { return 1.0 - factor; } else { @@ -646,9 +654,9 @@ class RenderBaseSlider extends RenderProxyBox double getPositionFromValue(double value) { return sliderType == SliderType.horizontal ? getFactorFromValue(value) * actualTrackRect.width + - actualTrackRect.left + actualTrackRect.left : actualTrackRect.bottom - - getFactorFromValue(value) * actualTrackRect.height; + getFactorFromValue(value) * actualTrackRect.height; } void generateLabelsAndMajorTicks() { @@ -686,9 +694,10 @@ class RenderBaseSlider extends RenderProxyBox getFormattedText(currentValue), ); - final TextStyle themeTextStyle = isActiveLabelValue(currentValue) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + final TextStyle themeTextStyle = + isActiveLabelValue(currentValue) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; labelStyle = _onLabelCreated(currentValue, label, themeTextStyle); if (isDateTime) { @@ -722,9 +731,10 @@ class RenderBaseSlider extends RenderProxyBox if (!_majorTickPositions.contains(labelPosition)) { _majorTickPositions.add(labelPosition); } - currentValue = isDateTime - ? _getNextDate(currentValue, _dateIntervalType, _interval!) - : currentValue + _interval; + currentValue = + isDateTime + ? _getNextDate(currentValue, _dateIntervalType, _interval!) + : currentValue + _interval; } } @@ -733,9 +743,10 @@ class RenderBaseSlider extends RenderProxyBox SliderLabel labelStyle; divisions = 1.0; label = _labelFormatterCallback(_min, getFormattedText(_min)); - TextStyle themeTextStyle = isActiveLabelValue(_min) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + TextStyle themeTextStyle = + isActiveLabelValue(_min) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; labelStyle = _onLabelCreated(_min, label, themeTextStyle); _visibleLabels.add( SliderLabel( @@ -748,9 +759,10 @@ class RenderBaseSlider extends RenderProxyBox isDateTime ? _min.millisecondsSinceEpoch.toDouble() : _min.toDouble(), ); label = _labelFormatterCallback(_max, getFormattedText(_max)); - themeTextStyle = isActiveLabelValue(_max) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + themeTextStyle = + isActiveLabelValue(_max) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; labelStyle = _onLabelCreated(_max, label, themeTextStyle); _visibleLabels.add( SliderLabel( @@ -859,11 +871,11 @@ class RenderBaseSlider extends RenderProxyBox (i + 1 < majorTicksCount ? _majorTickPositions[i + 1] - _majorTickPositions[i] : ((sliderType == SliderType.horizontal - ? actualTrackRect.width - : actualTrackRect.height) - - (isInversed - ? _majorTickPositions[0] - : _majorTickPositions[majorTicksCount - 1]))) / + ? actualTrackRect.width + : actualTrackRect.height) - + (isInversed + ? _majorTickPositions[0] + : _majorTickPositions[majorTicksCount - 1]))) / (_minorTicksPerInterval + 1); for (int j = 1; j <= _minorTicksPerInterval; j++) { _minorTickPositions.add(_majorTickPositions[i] + j * minorPositionDiff); @@ -985,10 +997,10 @@ class RenderBaseSlider extends RenderProxyBox currentDate.second + _stepDuration!.seconds, ); - final double currentDateInms = currentDate.millisecondsSinceEpoch - .toDouble(); - final double nextDateInms = nextDate.millisecondsSinceEpoch - .toDouble(); + final double currentDateInms = + currentDate.millisecondsSinceEpoch.toDouble(); + final double nextDateInms = + nextDate.millisecondsSinceEpoch.toDouble(); if (clampedValue >= currentDateInms && clampedValue <= nextDateInms) { final double dateDiff = (nextDateInms - currentDateInms).abs(); @@ -1014,11 +1026,13 @@ class RenderBaseSlider extends RenderProxyBox } double getFactorFromCurrentPosition() { - final double factor = (sliderType == SliderType.horizontal) - ? ((mainAxisOffset - actualTrackRect.left) / actualTrackRect.width) - .clamp(0.0, 1.0) - : ((actualTrackRect.bottom - mainAxisOffset) / actualTrackRect.height) - .clamp(0.0, 1.0); + final double factor = + (sliderType == SliderType.horizontal) + ? ((mainAxisOffset - actualTrackRect.left) / actualTrackRect.width) + .clamp(0.0, 1.0) + : ((actualTrackRect.bottom - mainAxisOffset) / + actualTrackRect.height) + .clamp(0.0, 1.0); if (_isInversed) { return 1.0 - factor; } else { @@ -1035,22 +1049,25 @@ class RenderBaseSlider extends RenderProxyBox ) { final double rectangularTooltipHeight = textPainter.height + tooltipTextPadding.dy > minTooltipHeight - ? textPainter.height + tooltipTextPadding.dy - : minTooltipHeight; + ? textPainter.height + tooltipTextPadding.dy + : minTooltipHeight; final double halfTextWidth = textPainter.width + tooltipTextPadding.dx > minTooltipWidth - ? (textPainter.width + tooltipTextPadding.dx) / 2 - : minTooltipWidth / 2; - - double rightLineWidth = thumbCenter.dx + halfTextWidth > trackRect.right - ? trackRect.right - thumbCenter.dx - : halfTextWidth; - final double leftLineWidth = thumbCenter.dx - halfTextWidth < trackRect.left - ? thumbCenter.dx - trackRect.left - : (halfTextWidth * 2) - rightLineWidth; - rightLineWidth = leftLineWidth < halfTextWidth - ? halfTextWidth - leftLineWidth + rightLineWidth - : rightLineWidth; + ? (textPainter.width + tooltipTextPadding.dx) / 2 + : minTooltipWidth / 2; + + double rightLineWidth = + thumbCenter.dx + halfTextWidth > trackRect.right + ? trackRect.right - thumbCenter.dx + : halfTextWidth; + final double leftLineWidth = + thumbCenter.dx - halfTextWidth < trackRect.left + ? thumbCenter.dx - trackRect.left + : (halfTextWidth * 2) - rightLineWidth; + rightLineWidth = + leftLineWidth < halfTextWidth + ? halfTextWidth - leftLineWidth + rightLineWidth + : rightLineWidth; final double left = thumbCenter.dx - leftLineWidth; final double right = thumbCenter.dx + rightLineWidth; @@ -1074,17 +1091,18 @@ class RenderBaseSlider extends RenderProxyBox ) { final double paddleTooltipRadius = textPainter.height > minPaddleTopCircleRadius - ? textPainter.height - : minPaddleTopCircleRadius; + ? textPainter.height + : minPaddleTopCircleRadius; final double topNeckRadius = paddleTooltipRadius - neckDifference; final double bottomNeckRadius = thumbRadius > minPaddleTopCircleRadius * moveNeckValue - ? thumbRadius - neckDifference - : 4.0; + ? thumbRadius - neckDifference + : 4.0; final double halfTextWidth = textPainter.width / 2 + textPadding; - final double halfPaddleWidth = halfTextWidth > paddleTooltipRadius - ? halfTextWidth - : paddleTooltipRadius; + final double halfPaddleWidth = + halfTextWidth > paddleTooltipRadius + ? halfTextWidth + : paddleTooltipRadius; final double shift = _getAdjustPaddleWidth( thumbCenter, offset, @@ -1123,12 +1141,12 @@ class RenderBaseSlider extends RenderProxyBox // When the tooltip leaves to the render box. shiftPaddleWidth = thumbCenter.dx + halfTextWidth + paddleTopCircleRadius > - rightEndPosition - ? thumbCenter.dx + - halfTextWidth + - paddleTopCircleRadius - - rightEndPosition - : shiftPaddleWidth; + rightEndPosition + ? thumbCenter.dx + + halfTextWidth + + paddleTopCircleRadius - + rightEndPosition + : shiftPaddleWidth; return shiftPaddleWidth; } @@ -1145,15 +1163,14 @@ class RenderBaseSlider extends RenderProxyBox ) { int dateTimePos = 0; bool isActive; - final double dx = sliderType == SliderType.horizontal - ? trackRect.left - : trackRect.bottom; - final double dy = sliderType == SliderType.horizontal - ? trackRect.top - : trackRect.left; - final double halfTrackHeight = sliderType == SliderType.horizontal - ? trackRect.height / 2 - : trackRect.width / 2; + final double dx = + sliderType == SliderType.horizontal ? trackRect.left : trackRect.bottom; + final double dy = + sliderType == SliderType.horizontal ? trackRect.top : trackRect.left; + final double halfTrackHeight = + sliderType == SliderType.horizontal + ? trackRect.height / 2 + : trackRect.width / 2; if (startThumbCenter != null) { if (sliderType == SliderType.horizontal) { isActive = @@ -1176,9 +1193,10 @@ class RenderBaseSlider extends RenderProxyBox .width / 2; - final double tickRadius = sliderType == SliderType.horizontal - ? _tickShape.getPreferredSize(_sliderThemeData).width / 2 - : _tickShape.getPreferredSize(_sliderThemeData).height / 2; + final double tickRadius = + sliderType == SliderType.horizontal + ? _tickShape.getPreferredSize(_sliderThemeData).width / 2 + : _tickShape.getPreferredSize(_sliderThemeData).height / 2; // ignore: avoid_as double textValue = isDateTime ? 0.0 : _min.toDouble() as double; @@ -1256,13 +1274,15 @@ class RenderBaseSlider extends RenderProxyBox // Drawing labels. if (_showLabels) { - final double dx = sliderType == SliderType.horizontal - ? trackRect.left - : trackRect.bottom; + final double dx = + sliderType == SliderType.horizontal + ? trackRect.left + : trackRect.bottom; - double offsetX = sliderType == SliderType.horizontal - ? dx + tickPosition - : dx - tickPosition; + double offsetX = + sliderType == SliderType.horizontal + ? dx + tickPosition + : dx - tickPosition; if (_labelPlacement == LabelPlacement.betweenTicks) { if (sliderType == SliderType.horizontal) { @@ -1287,11 +1307,12 @@ class RenderBaseSlider extends RenderProxyBox } } - final TextStyle textStyle = hasLabelCreated - ? _visibleLabels[dateTimePos].textStyle - : isInactive - ? _sliderThemeData.inactiveLabelStyle! - : _sliderThemeData.activeLabelStyle!; + final TextStyle textStyle = + hasLabelCreated + ? _visibleLabels[dateTimePos].textStyle + : isInactive + ? _sliderThemeData.inactiveLabelStyle! + : _sliderThemeData.activeLabelStyle!; if (_edgeLabelPlacement == EdgeLabelPlacement.inside && _labelPlacement == LabelPlacement.onTicks) { @@ -1442,11 +1463,12 @@ class RenderBaseSlider extends RenderProxyBox ? trackRect.width : trackRect.height) && currentMinorTickPosition > 0) { - final Offset actualTickOffset = sliderType == SliderType.horizontal - ? Offset(dx + currentMinorTickPosition, dy + trackRect.height) + - (_sliderThemeData.tickOffset ?? Offset.zero) - : Offset(dy + trackRect.width, dx - currentMinorTickPosition) + - (_sliderThemeData.tickOffset ?? Offset.zero); + final Offset actualTickOffset = + sliderType == SliderType.horizontal + ? Offset(dx + currentMinorTickPosition, dy + trackRect.height) + + (_sliderThemeData.tickOffset ?? Offset.zero) + : Offset(dy + trackRect.width, dx - currentMinorTickPosition) + + (_sliderThemeData.tickOffset ?? Offset.zero); _minorTickShape.paint( context, actualTickOffset, @@ -1559,15 +1581,15 @@ class RenderBaseSlider extends RenderProxyBox double offsetX, TextStyle labelStyle, ) { - final double dy = sliderType == SliderType.horizontal - ? trackRect.top - : trackRect.left; + final double dy = + sliderType == SliderType.horizontal ? trackRect.top : trackRect.left; final String labelText = _visibleLabels[_dateTimePos].text; - final Offset actualLabelOffset = sliderType == SliderType.horizontal - ? Offset(offsetX, dy + trackRect.height + actualTickHeight) + - (_sliderThemeData.labelOffset ?? Offset.zero) - : Offset(dy + trackRect.width + actualTickWidth, offsetX) + - (_sliderThemeData.labelOffset ?? Offset.zero); + final Offset actualLabelOffset = + sliderType == SliderType.horizontal + ? Offset(offsetX, dy + trackRect.height + actualTickHeight) + + (_sliderThemeData.labelOffset ?? Offset.zero) + : Offset(dy + trackRect.width + actualTickWidth, offsetX) + + (_sliderThemeData.labelOffset ?? Offset.zero); _drawText( context, @@ -1641,11 +1663,12 @@ class RenderBaseSlider extends RenderProxyBox } } - final TextStyle labelTextStyle = hasLabelCreated - ? textStyle - : isInactive - ? themeData.inactiveLabelStyle! - : themeData.activeLabelStyle!; + final TextStyle labelTextStyle = + hasLabelCreated + ? textStyle + : isInactive + ? themeData.inactiveLabelStyle! + : themeData.activeLabelStyle!; final TextSpan textSpan = TextSpan(text: text, style: labelTextStyle); @@ -1736,10 +1759,7 @@ class RenderBaseSlider extends RenderProxyBox // This method is only applicable for vertical sliders Size _textSize(String text, double fontSize) { final TextPainter textPainter = TextPainter( - text: TextSpan( - text: text, - style: TextStyle(fontSize: fontSize), - ), + text: TextSpan(text: text, style: TextStyle(fontSize: fontSize)), maxLines: 1, textDirection: TextDirection.ltr, )..layout(); @@ -1757,10 +1777,10 @@ class RenderBaseSlider extends RenderProxyBox divisions = (isDateTime ? _getDateTimeDifference( - _min, - _max, - _dateIntervalType, - ) + _min, + _max, + _dateIntervalType, + ) : _max - _min) .toDouble() / // ignore: avoid_as @@ -1771,9 +1791,10 @@ class RenderBaseSlider extends RenderProxyBox currentValue, getFormattedText(currentValue), ); - final TextStyle themeTextStyle = isActiveLabelValue(currentValue) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + final TextStyle themeTextStyle = + isActiveLabelValue(currentValue) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; labelStyle = _onLabelCreated(currentValue, label, themeTextStyle); final double maximumLabelFontSize = math.max( @@ -1785,9 +1806,10 @@ class RenderBaseSlider extends RenderProxyBox if (maxLabelWidth < labelLength) { maxLabelWidth = labelLength; } - currentValue = isDateTime - ? _getNextDate(currentValue, _dateIntervalType, _interval!) - : currentValue + _interval; + currentValue = + isDateTime + ? _getNextDate(currentValue, _dateIntervalType, _interval!) + : currentValue + _interval; } } else if (_showLabels) { maxLabelWidth = _edgeLabelWidth(); @@ -1803,32 +1825,30 @@ class RenderBaseSlider extends RenderProxyBox SliderLabel maxLabelStyle; double maxLabelWidth; minLabel = _labelFormatterCallback(_min, getFormattedText(_min)); - TextStyle themeTextStyle = isActiveLabelValue(_min) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + TextStyle themeTextStyle = + isActiveLabelValue(_min) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; minLabelStyle = _onLabelCreated(_min, minLabel, themeTextStyle); maxLabel = _labelFormatterCallback(_max, getFormattedText(_max)); - themeTextStyle = isActiveLabelValue(_max) - ? _sliderThemeData.activeLabelStyle! - : _sliderThemeData.inactiveLabelStyle!; + themeTextStyle = + isActiveLabelValue(_max) + ? _sliderThemeData.activeLabelStyle! + : _sliderThemeData.inactiveLabelStyle!; maxLabelStyle = _onLabelCreated(_max, maxLabel, themeTextStyle); double maxFontFize = math.max( maximumFontSize, maxLabelStyle.textStyle.fontSize ?? 0, ); - final double minLabelLength = _textSize( - minLabelStyle.text, - maxFontFize, - ).width; + final double minLabelLength = + _textSize(minLabelStyle.text, maxFontFize).width; maxFontFize = math.max( maximumFontSize, minLabelStyle.textStyle.fontSize ?? 0, ); - final double maxLabelLength = _textSize( - maxLabelStyle.text, - maxFontFize, - ).width; + final double maxLabelLength = + _textSize(maxLabelStyle.text, maxFontFize).width; maxLabelWidth = math.max(minLabelLength, maxLabelLength); return maxLabelWidth; } diff --git a/packages/syncfusion_flutter_sliders/lib/src/slider_shapes.dart b/packages/syncfusion_flutter_sliders/lib/src/slider_shapes.dart index 2b7bea724..49ea9dc35 100644 --- a/packages/syncfusion_flutter_sliders/lib/src/slider_shapes.dart +++ b/packages/syncfusion_flutter_sliders/lib/src/slider_shapes.dart @@ -53,17 +53,18 @@ class SfTrackShape { if (_isVertical(parentBox)) { double left = offset.dx; if (isActive != null) { - left += isActive - ? (maxTrackHeight - themeData.activeTrackHeight) / 2 - : (maxTrackHeight - themeData.inactiveTrackHeight) / 2; + left += + isActive + ? (maxTrackHeight - themeData.activeTrackHeight) / 2 + : (maxTrackHeight - themeData.inactiveTrackHeight) / 2; } final double right = left + (isActive == null ? maxTrackHeight : (isActive - ? themeData.activeTrackHeight - : themeData.inactiveTrackHeight)); + ? themeData.activeTrackHeight + : themeData.inactiveTrackHeight)); final double top = offset.dy + maxRadius; final double bottom = top + parentBox.size.height - (2 * maxRadius); return Rect.fromLTRB( @@ -76,9 +77,10 @@ class SfTrackShape { final double left = offset.dx + maxRadius; double top = offset.dy; if (isActive != null) { - top += isActive - ? (maxTrackHeight - themeData.activeTrackHeight) / 2 - : (maxTrackHeight - themeData.inactiveTrackHeight) / 2; + top += + isActive + ? (maxTrackHeight - themeData.activeTrackHeight) / 2 + : (maxTrackHeight - themeData.inactiveTrackHeight) / 2; } final double right = left + parentBox.size.width - (2 * maxRadius); final double bottom = @@ -86,8 +88,8 @@ class SfTrackShape { (isActive == null ? maxTrackHeight : (isActive - ? themeData.activeTrackHeight - : themeData.inactiveTrackHeight)); + ? themeData.activeTrackHeight + : themeData.inactiveTrackHeight)); return Rect.fromLTRB( math.min(left, right), top, @@ -442,9 +444,10 @@ class SfThumbShape { parentRenderBox.currentPointerType != null && parentRenderBox.currentPointerType != PointerType.up; path.addOval(Rect.fromCircle(center: center, radius: radius)); - final double thumbElevation = isThumbActive - ? parentRenderBox.thumbElevationTween.evaluate(enableAnimation) - : defaultElevation; + final double thumbElevation = + isThumbActive + ? parentRenderBox.thumbElevationTween.evaluate(enableAnimation) + : defaultElevation; context.canvas.drawShadow(path, shadowColor, thumbElevation, true); } @@ -468,10 +471,11 @@ class SfThumbShape { if (paint == null) { paint = Paint(); paint.isAntiAlias = true; - paint.color = ColorTween( - begin: themeData.disabledThumbColor, - end: themeData.thumbColor, - ).evaluate(enableAnimation)!; + paint.color = + ColorTween( + begin: themeData.disabledThumbColor, + end: themeData.thumbColor, + ).evaluate(enableAnimation)!; } context.canvas.drawCircle(center, radius, paint); @@ -488,12 +492,14 @@ class SfThumbShape { if (themeData.thumbStrokeColor != null && themeData.thumbStrokeWidth != null && themeData.thumbStrokeWidth! > 0) { - final Paint strokePaint = Paint() - ..color = themeData.thumbStrokeColor! - ..style = PaintingStyle.stroke - ..strokeWidth = themeData.thumbStrokeWidth! > radius - ? radius - : themeData.thumbStrokeWidth!; + final Paint strokePaint = + Paint() + ..color = themeData.thumbStrokeColor! + ..style = PaintingStyle.stroke + ..strokeWidth = + themeData.thumbStrokeWidth! > radius + ? radius + : themeData.thumbStrokeWidth!; context.canvas.drawCircle( center, themeData.thumbStrokeWidth! > radius @@ -520,8 +526,8 @@ class SfDividerShape { return Size.fromRadius( isActive != null ? (isActive - ? themeData.activeDividerRadius! - : themeData.inactiveDividerRadius!) + ? themeData.activeDividerRadius! + : themeData.inactiveDividerRadius!) : 0, ); } @@ -588,29 +594,31 @@ class SfDividerShape { if (paint == null) { paint = Paint(); - final Color begin = isActive - ? themeData.disabledActiveDividerColor! - : themeData.disabledInactiveDividerColor!; - final Color end = isActive - ? themeData.activeDividerColor! - : themeData.inactiveDividerColor!; - - paint.color = ColorTween( - begin: begin, - end: end, - ).evaluate(enableAnimation)!; + final Color begin = + isActive + ? themeData.disabledActiveDividerColor! + : themeData.disabledInactiveDividerColor!; + final Color end = + isActive + ? themeData.activeDividerColor! + : themeData.inactiveDividerColor!; + + paint.color = + ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; } final double dividerRadius = getPreferredSize(themeData, isActive: isActive).width / 2; context.canvas.drawCircle(center, dividerRadius, paint); - final double? dividerStrokeWidth = isActive - ? themeData.activeDividerStrokeWidth - : themeData.inactiveDividerStrokeWidth; - final Color? dividerStrokeColor = isActive - ? themeData.activeDividerStrokeColor - : themeData.inactiveDividerStrokeColor; + final double? dividerStrokeWidth = + isActive + ? themeData.activeDividerStrokeWidth + : themeData.inactiveDividerStrokeWidth; + final Color? dividerStrokeColor = + isActive + ? themeData.activeDividerStrokeColor + : themeData.inactiveDividerStrokeColor; if (dividerStrokeColor != null && dividerStrokeWidth != null && @@ -624,9 +632,10 @@ class SfDividerShape { paint ..color = dividerStrokeColor ..style = PaintingStyle.stroke - ..strokeWidth = dividerStrokeWidth > dividerRadius - ? dividerRadius - : dividerStrokeWidth, + ..strokeWidth = + dividerStrokeWidth > dividerRadius + ? dividerRadius + : dividerStrokeWidth, ); } } @@ -737,16 +746,19 @@ class SfTickShape { } } - final Color begin = isInactive - ? themeData.disabledInactiveTickColor! - : themeData.disabledActiveTickColor!; - final Color end = isInactive - ? themeData.inactiveTickColor! - : themeData.activeTickColor!; - final Paint paint = Paint() - ..isAntiAlias = true - ..strokeWidth = _isVertical(parentBox) ? tickSize.height : tickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; + final Color begin = + isInactive + ? themeData.disabledInactiveTickColor! + : themeData.disabledActiveTickColor!; + final Color end = + isInactive ? themeData.inactiveTickColor! : themeData.activeTickColor!; + final Paint paint = + Paint() + ..isAntiAlias = true + ..strokeWidth = + _isVertical(parentBox) ? tickSize.height : tickSize.width + ..color = + ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; if (_isVertical(parentBox)) { context.canvas.drawLine( offset, @@ -848,18 +860,23 @@ class SfMinorTickShape extends SfTickShape { } } - final Color begin = isInactive - ? themeData.disabledInactiveMinorTickColor! - : themeData.disabledActiveMinorTickColor!; - final Color end = isInactive - ? themeData.inactiveMinorTickColor! - : themeData.activeMinorTickColor!; - final Paint paint = Paint() - ..isAntiAlias = true - ..strokeWidth = _isVertical(parentBox) - ? minorTickSize.height - : minorTickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; + final Color begin = + isInactive + ? themeData.disabledInactiveMinorTickColor! + : themeData.disabledActiveMinorTickColor!; + final Color end = + isInactive + ? themeData.inactiveMinorTickColor! + : themeData.activeMinorTickColor!; + final Paint paint = + Paint() + ..isAntiAlias = true + ..strokeWidth = + _isVertical(parentBox) + ? minorTickSize.height + : minorTickSize.width + ..color = + ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; if (_isVertical(parentBox)) { context.canvas.drawLine( offset, @@ -910,16 +927,18 @@ class SfPaddleTooltipShape extends SfTooltipShape { 2; final double paddleTopCircleRadius = textPainter.height > minPaddleTopCircleRadius - ? textPainter.height - : minPaddleTopCircleRadius; + ? textPainter.height + : minPaddleTopCircleRadius; final double topNeckRadius = paddleTopCircleRadius - neckDifference; - final double bottomNeckRadius = thumbRadius > defaultThumbRadius - ? thumbRadius - neckDifference * 2 - : minBottomNeckRadius; + final double bottomNeckRadius = + thumbRadius > defaultThumbRadius + ? thumbRadius - neckDifference * 2 + : minBottomNeckRadius; final double halfTextWidth = textPainter.width / 2 + textPadding; - final double paddleTopCircleX = halfTextWidth > paddleTopCircleRadius - ? halfTextWidth - paddleTopCircleRadius - : 0; + final double paddleTopCircleX = + halfTextWidth > paddleTopCircleRadius + ? halfTextWidth - paddleTopCircleRadius + : 0; final double minPaddleWidth = paddleTopCircleRadius + topNeckRadius + neckDifference / 2; final Offset topNeckCenter = Offset( @@ -938,52 +957,57 @@ class SfPaddleTooltipShape extends SfTooltipShape { -thumbRadius - bottomNeckRadius * (1.0 - moveNeckValue), ); final double leftShiftWidth = thumbCenter.dx - halfTextWidth; - double shiftPaddleWidth = leftShiftWidth < trackRect.left - ? leftShiftWidth - : 0; + double shiftPaddleWidth = + leftShiftWidth < trackRect.left ? leftShiftWidth : 0; final double rightShiftWidth = thumbCenter.dx + halfTextWidth; - shiftPaddleWidth = rightShiftWidth > trackRect.right - ? rightShiftWidth - trackRect.right - : shiftPaddleWidth; + shiftPaddleWidth = + rightShiftWidth > trackRect.right + ? rightShiftWidth - trackRect.right + : shiftPaddleWidth; final double leftPaddleWidth = paddleTopCircleRadius + paddleTopCircleCenter.dx + shiftPaddleWidth; final double rightPaddleWidth = paddleTopCircleRadius + paddleTopCircleCenter.dx - shiftPaddleWidth; - final double moveLeftTopNeckY = leftPaddleWidth > paddleTopCircleRadius - ? leftPaddleWidth < minPaddleWidth - ? (leftPaddleWidth - topNeckRadius) * moveNeckValue - : paddleTopCircleRadius * moveNeckValue - : 0; - final double moveLeftTopNeckAngle = leftPaddleWidth > paddleTopCircleRadius - ? leftPaddleWidth < minPaddleWidth - ? moveLeftTopNeckY * math.pi / 180 - : 30 * math.pi / 180 - : 0; - final double moveRightTopNeckY = rightPaddleWidth > paddleTopCircleRadius - ? rightPaddleWidth < minPaddleWidth - ? (rightPaddleWidth - topNeckRadius) * moveNeckValue - : paddleTopCircleRadius * moveNeckValue - : 0; + final double moveLeftTopNeckY = + leftPaddleWidth > paddleTopCircleRadius + ? leftPaddleWidth < minPaddleWidth + ? (leftPaddleWidth - topNeckRadius) * moveNeckValue + : paddleTopCircleRadius * moveNeckValue + : 0; + final double moveLeftTopNeckAngle = + leftPaddleWidth > paddleTopCircleRadius + ? leftPaddleWidth < minPaddleWidth + ? moveLeftTopNeckY * math.pi / 180 + : 30 * math.pi / 180 + : 0; + final double moveRightTopNeckY = + rightPaddleWidth > paddleTopCircleRadius + ? rightPaddleWidth < minPaddleWidth + ? (rightPaddleWidth - topNeckRadius) * moveNeckValue + : paddleTopCircleRadius * moveNeckValue + : 0; final double moveRightTopNeckAngle = rightPaddleWidth > paddleTopCircleRadius - ? rightPaddleWidth < minPaddleWidth - ? moveRightTopNeckY * math.pi / 180 - : 30 * math.pi / 180 - : 0; - final double leftNeckStretchValue = leftPaddleWidth < minPaddleWidth - ? (1.0 - (leftPaddleWidth / minPaddleWidth)) - : 0; - final double rightNeckStretchValue = rightPaddleWidth < minPaddleWidth - ? (1.0 - (rightPaddleWidth / minPaddleWidth)) - : 0; + ? rightPaddleWidth < minPaddleWidth + ? moveRightTopNeckY * math.pi / 180 + : 30 * math.pi / 180 + : 0; + final double leftNeckStretchValue = + leftPaddleWidth < minPaddleWidth + ? (1.0 - (leftPaddleWidth / minPaddleWidth)) + : 0; + final double rightNeckStretchValue = + rightPaddleWidth < minPaddleWidth + ? (1.0 - (rightPaddleWidth / minPaddleWidth)) + : 0; final double adjustPaddleCircleLeftArcAngle = shiftPaddleWidth < 0 && leftPaddleWidth < minPaddleWidth - ? (leftNeckStretchValue * (math.pi / 2 + moveLeftTopNeckAngle)) - : 0; + ? (leftNeckStretchValue * (math.pi / 2 + moveLeftTopNeckAngle)) + : 0; final double adjustPaddleCircleRightArcAngle = shiftPaddleWidth > 0 && rightPaddleWidth < minPaddleWidth - ? (rightNeckStretchValue * (math.pi / 2 + moveRightTopNeckAngle)) - : 0.0; + ? (rightNeckStretchValue * (math.pi / 2 + moveRightTopNeckAngle)) + : 0.0; final double adjustLeftNeckArcAngle = adjustPaddleCircleLeftArcAngle * (1.0 - moveNeckValue); final double adjustRightNeckArcAngle = @@ -1201,27 +1225,27 @@ class SfRectangularTooltipShape extends SfTooltipShape { bool? isLeftTooltip, }) { final double dy = tooltipStartY + tooltipTriangleHeight; - final double tooltipWidth = textSize.width < minTooltipWidth - ? minTooltipWidth - : textSize.width; - final double tooltipHeight = textSize.height < minTooltipHeight - ? minTooltipHeight - : textSize.height; + final double tooltipWidth = + textSize.width < minTooltipWidth ? minTooltipWidth : textSize.width; + final double tooltipHeight = + textSize.height < minTooltipHeight ? minTooltipHeight : textSize.height; final double halfTooltipWidth = tooltipWidth / 2; final double halfTooltipHeight = tooltipHeight / 2; const double halfTooltipTriangleWidth = tooltipTriangleWidth / 2; if (isVertical) { if (isLeftTooltip!) { - double topLineHeight = dx - halfTooltipHeight < trackRect.top - ? dx - trackRect.top - : halfTooltipHeight; + double topLineHeight = + dx - halfTooltipHeight < trackRect.top + ? dx - trackRect.top + : halfTooltipHeight; final double bottomLineHeight = dx + halfTooltipHeight > trackRect.bottom - ? trackRect.bottom - dx - : tooltipHeight - topLineHeight; - topLineHeight = bottomLineHeight < halfTooltipHeight - ? halfTooltipHeight - bottomLineHeight + topLineHeight - : topLineHeight; + ? trackRect.bottom - dx + : tooltipHeight - topLineHeight; + topLineHeight = + bottomLineHeight < halfTooltipHeight + ? halfTooltipHeight - bottomLineHeight + topLineHeight + : topLineHeight; return _getRectangularPath( tooltipStartY, topLineHeight, @@ -1234,16 +1258,18 @@ class SfRectangularTooltipShape extends SfTooltipShape { isLeftTooltip: isLeftTooltip, ); } else { - double topLineHeight = dx - halfTooltipHeight < trackRect.top - ? dx - trackRect.top - : halfTooltipHeight; + double topLineHeight = + dx - halfTooltipHeight < trackRect.top + ? dx - trackRect.top + : halfTooltipHeight; final double bottomLineHeight = dx + halfTooltipHeight > trackRect.bottom - ? trackRect.bottom - dx - : tooltipHeight - topLineHeight; - topLineHeight = bottomLineHeight < halfTooltipHeight - ? halfTooltipHeight - bottomLineHeight + topLineHeight - : topLineHeight; + ? trackRect.bottom - dx + : tooltipHeight - topLineHeight; + topLineHeight = + bottomLineHeight < halfTooltipHeight + ? halfTooltipHeight - bottomLineHeight + topLineHeight + : topLineHeight; return _getRectangularPath( tooltipStartY, topLineHeight, @@ -1257,18 +1283,21 @@ class SfRectangularTooltipShape extends SfTooltipShape { ); } } else { - double rightLineWidth = dx + halfTooltipWidth > trackRect.right - ? trackRect.right - dx - : halfTooltipWidth; - final double leftLineWidth = isVertical - ? tooltipWidth - rightLineWidth - : dx - halfTooltipWidth < trackRect.left - ? dx - trackRect.left - : tooltipWidth - rightLineWidth; + double rightLineWidth = + dx + halfTooltipWidth > trackRect.right + ? trackRect.right - dx + : halfTooltipWidth; + final double leftLineWidth = + isVertical + ? tooltipWidth - rightLineWidth + : dx - halfTooltipWidth < trackRect.left + ? dx - trackRect.left + : tooltipWidth - rightLineWidth; if (!isVertical) { - rightLineWidth = leftLineWidth < halfTooltipWidth - ? halfTooltipWidth - leftLineWidth + rightLineWidth - : rightLineWidth; + rightLineWidth = + leftLineWidth < halfTooltipWidth + ? halfTooltipWidth - leftLineWidth + rightLineWidth + : rightLineWidth; } return _getRectangularPath( tooltipStartY, @@ -1509,22 +1538,23 @@ class SfRectangularTooltipShape extends SfTooltipShape { final double leftPadding = tooltipTextPadding.dx / 2; final double minLeftX = trackRect.left; // ignore: avoid_as - final Path path = (_isVertical(parentBox as RenderBaseSlider)) - ? _updateRectangularTooltipWidth( - textPainter.size + tooltipTextPadding, - offset.dy, - trackRect, - thumbCenter.dy, - isVertical: _isVertical(parentBox), - isLeftTooltip: _isLeftTooltip(parentBox), - ) - : _updateRectangularTooltipWidth( - textPainter.size + tooltipTextPadding, - offset.dy, - trackRect, - thumbCenter.dx, - isVertical: _isVertical(parentBox), - ); + final Path path = + (_isVertical(parentBox as RenderBaseSlider)) + ? _updateRectangularTooltipWidth( + textPainter.size + tooltipTextPadding, + offset.dy, + trackRect, + thumbCenter.dy, + isVertical: _isVertical(parentBox), + isLeftTooltip: _isLeftTooltip(parentBox), + ) + : _updateRectangularTooltipWidth( + textPainter.size + tooltipTextPadding, + offset.dy, + trackRect, + thumbCenter.dx, + isVertical: _isVertical(parentBox), + ); context.canvas.save(); context.canvas.translate(thumbCenter.dx, thumbCenter.dy); @@ -1566,17 +1596,18 @@ class SfRectangularTooltipShape extends SfTooltipShape { tooltipTriangleHeight - (pathRect.size.width - tooltipTriangleHeight) / 2 - textPainter.width / 2; - final double dy = rectTopPosition >= trackRect.top - ? thumbCenter.dy + halfPathHeight >= trackRect.bottom - ? -halfTextPainterHeight - + final double dy = + rectTopPosition >= trackRect.top + ? thumbCenter.dy + halfPathHeight >= trackRect.bottom + ? -halfTextPainterHeight - halfPathHeight - thumbCenter.dy + trackRect.bottom - : -halfTextPainterHeight - : -halfTextPainterHeight + - halfPathHeight - - thumbCenter.dy + - trackRect.top; + : -halfTextPainterHeight + : -halfTextPainterHeight + + halfPathHeight - + thumbCenter.dy + + trackRect.top; textPainter.paint(context.canvas, Offset(dx, dy)); } else { final double dx = @@ -1584,32 +1615,34 @@ class SfRectangularTooltipShape extends SfTooltipShape { tooltipTriangleHeight + (pathRect.size.width - tooltipTriangleHeight) / 2 - textPainter.width / 2; - final double dy = rectTopPosition >= trackRect.top - ? thumbCenter.dy + halfPathHeight >= trackRect.bottom - ? -halfTextPainterHeight - + final double dy = + rectTopPosition >= trackRect.top + ? thumbCenter.dy + halfPathHeight >= trackRect.bottom + ? -halfTextPainterHeight - halfPathHeight - thumbCenter.dy + trackRect.bottom - : -halfTextPainterHeight - : -halfTextPainterHeight + - halfPathHeight - - thumbCenter.dy + - trackRect.top; + : -halfTextPainterHeight + : -halfTextPainterHeight + + halfPathHeight - + thumbCenter.dy + + trackRect.top; textPainter.paint(context.canvas, Offset(dx, dy)); } } else { - final double dx = rectLeftPosition >= minLeftX - ? thumbCenter.dx + halfTextPainterWidth + leftPadding > - trackRect.right - ? -halfTextPainterWidth - + final double dx = + rectLeftPosition >= minLeftX + ? thumbCenter.dx + halfTextPainterWidth + leftPadding > + trackRect.right + ? -halfTextPainterWidth - halfPathWidth + trackRect.right - thumbCenter.dx - : -halfTextPainterWidth - : -halfTextPainterWidth + - halfPathWidth + - trackRect.left - - thumbCenter.dx; + : -halfTextPainterWidth + : -halfTextPainterWidth + + halfPathWidth + + trackRect.left - + thumbCenter.dx; final double dy = offset.dy + tooltipTriangleHeight + diff --git a/packages/syncfusion_flutter_sliders/pubspec.yaml b/packages/syncfusion_flutter_sliders/pubspec.yaml index 032aacda1..d69904b95 100644 --- a/packages/syncfusion_flutter_sliders/pubspec.yaml +++ b/packages/syncfusion_flutter_sliders/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_sliders description: A Flutter Sliders library for creating highly customizable and UI-rich slider, range slider, and range selector widgets for filtering purposes. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_sliders screenshots: @@ -15,7 +15,7 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" dependencies: flutter: @@ -23,5 +23,3 @@ dependencies: intl: '>=0.18.1 <0.21.0' syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_treemap/CHANGELOG.md b/packages/syncfusion_flutter_treemap/CHANGELOG.md index 224ef2f7e..e5949b775 100644 --- a/packages/syncfusion_flutter_treemap/CHANGELOG.md +++ b/packages/syncfusion_flutter_treemap/CHANGELOG.md @@ -1,6 +1,18 @@ ## Unreleased -* No changes. +* No changes. + +## [31.2.15] - 11/25/2025 + +**General** + +* The compatible version of our Flutter treemap widget has been updated to Flutter SDK 3.38. + +## [31.1.20] - 09/17/2025 + +**General** + +* The compatible version of our Flutter treemap widget has been updated to Flutter SDK 3.35. ## [30.1.37] - 06/25/2025 diff --git a/packages/syncfusion_flutter_treemap/example/android/build.gradle.kts b/packages/syncfusion_flutter_treemap/example/android/build.gradle.kts index 89176ef44..dbee657bb 100644 --- a/packages/syncfusion_flutter_treemap/example/android/build.gradle.kts +++ b/packages/syncfusion_flutter_treemap/example/android/build.gradle.kts @@ -5,7 +5,10 @@ allprojects { } } -val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { diff --git a/packages/syncfusion_flutter_treemap/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_treemap/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0..ac3b47926 100644 --- a/packages/syncfusion_flutter_treemap/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_treemap/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_treemap/example/android/settings.gradle.kts b/packages/syncfusion_flutter_treemap/example/android/settings.gradle.kts index a439442c2..c571d1e63 100644 --- a/packages/syncfusion_flutter_treemap/example/android/settings.gradle.kts +++ b/packages/syncfusion_flutter_treemap/example/android/settings.gradle.kts @@ -1,11 +1,12 @@ pluginManagement { - val flutterSdkPath = run { - val properties = java.util.Properties() - file("local.properties").inputStream().use { properties.load(it) } - val flutterSdkPath = properties.getProperty("flutter.sdk") - require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } - flutterSdkPath - } + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") @@ -18,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/syncfusion_flutter_treemap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_treemap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_treemap/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_treemap/lib/src/layouts.dart b/packages/syncfusion_flutter_treemap/lib/src/layouts.dart index 209425c82..4487f86c7 100644 --- a/packages/syncfusion_flutter_treemap/lib/src/layouts.dart +++ b/packages/syncfusion_flutter_treemap/lib/src/layouts.dart @@ -54,8 +54,10 @@ Widget _buildAnimatedBuilder( ); } + final double tx = 1.0 / scale.width; + final double ty = 1.0 / scale.height; child = Transform( - transform: Matrix4.identity()..scale(1.0 / scale.width, 1.0 / scale.height), + transform: Matrix4.identity()..scaleByDouble(tx, ty, tx, 1.0), child: child, ); @@ -452,8 +454,18 @@ mixin _TreemapMixin { alignment: _getEffectiveAlignment(direction), transform: Matrix4.identity() - ..scale(scaleSize.width, scaleSize.height) - ..leftTranslate(translation.dx, translation.dy), + ..scaleByDouble( + scaleSize.width, + scaleSize.height, + scaleSize.width, + 1.0, + ) + ..leftTranslateByDouble( + translation.dx, + translation.dy, + 0.0, + 1.0, + ), child: Stack( clipBehavior: Clip.none, children: _buildTiles( @@ -511,8 +523,18 @@ mixin _TreemapMixin { alignment: _getEffectiveAlignment(direction), transform: Matrix4.identity() - ..scale(scaleSize.width, scaleSize.height) - ..leftTranslate(translation.dx, translation.dy), + ..scaleByDouble( + scaleSize.width, + scaleSize.height, + scaleSize.width, + 1.0, + ) + ..leftTranslateByDouble( + translation.dx, + translation.dy, + 0.0, + 1.0, + ), child: Stack( clipBehavior: Clip.none, children: _buildTiles( @@ -527,10 +549,17 @@ mixin _TreemapMixin { alignment: _getEffectiveAlignment(direction), transform: Matrix4.identity() - ..scale(descendantsScaleSize.width, descendantsScaleSize.height) - ..leftTranslate( + ..scaleByDouble( + descendantsScaleSize.width, + descendantsScaleSize.height, + descendantsScaleSize.width, + 1.0, + ) + ..leftTranslateByDouble( descendantsTranslation.dx, descendantsTranslation.dy, + 0.0, + 0.0, ), child: Opacity( opacity: 1.0 - _tileOpacity.evaluate(_opacityAnimation), diff --git a/packages/syncfusion_flutter_treemap/pubspec.yaml b/packages/syncfusion_flutter_treemap/pubspec.yaml index 99d08dc7e..f754212e3 100644 --- a/packages/syncfusion_flutter_treemap/pubspec.yaml +++ b/packages/syncfusion_flutter_treemap/pubspec.yaml @@ -1,6 +1,6 @@ name: syncfusion_flutter_treemap description: A Flutter Treemap library for creating interactive treemap to visualize flat and hierarchical data based on squarified, slice, and dice algorithms. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_treemap screenshots: @@ -15,7 +15,7 @@ screenshots: environment: sdk: ^3.7.0 - flutter: ">=3.29.0" + flutter: ">=3.35.1" flutter: uses-material-design: true @@ -25,5 +25,3 @@ dependencies: sdk: flutter syncfusion_flutter_core: path: ../syncfusion_flutter_core - - diff --git a/packages/syncfusion_flutter_xlsio/example/android/app/build.gradle b/packages/syncfusion_flutter_xlsio/example/android/app/build.gradle deleted file mode 100644 index 5fe3c929f..000000000 --- a/packages/syncfusion_flutter_xlsio/example/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion flutter.compileSdkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/packages/syncfusion_flutter_xlsio/example/android/build.gradle b/packages/syncfusion_flutter_xlsio/example/android/build.gradle deleted file mode 100644 index 4256f9173..000000000 --- a/packages/syncfusion_flutter_xlsio/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.6.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/syncfusion_flutter_xlsio/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_xlsio/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8eb0..ac3b47926 100644 --- a/packages/syncfusion_flutter_xlsio/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_xlsio/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_xlsio/example/android/settings.gradle b/packages/syncfusion_flutter_xlsio/example/android/settings.gradle deleted file mode 100644 index 44e62bcf0..000000000 --- a/packages/syncfusion_flutter_xlsio/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/syncfusion_flutter_xlsio/example/android/settings.gradle.kts b/packages/syncfusion_flutter_xlsio/example/android/settings.gradle.kts index a439442c2..9cd63b101 100644 --- a/packages/syncfusion_flutter_xlsio/example/android/settings.gradle.kts +++ b/packages/syncfusion_flutter_xlsio/example/android/settings.gradle.kts @@ -18,8 +18,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/packages/syncfusion_flutter_xlsio/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_xlsio/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/syncfusion_flutter_xlsio/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/packages/syncfusion_flutter_xlsio/example/pubspec.yaml b/packages/syncfusion_flutter_xlsio/example/pubspec.yaml index 60ff00bd2..34c4598e4 100644 --- a/packages/syncfusion_flutter_xlsio/example/pubspec.yaml +++ b/packages/syncfusion_flutter_xlsio/example/pubspec.yaml @@ -2,8 +2,11 @@ name: xlsio_example description: Demo for creating a Excel file using syncfusion_flutter_xlsio package. environment: - sdk: ^3.7.0-0 - + sdk: ^3.7.0 + +flutter: + uses-material-design: true + dependencies: flutter: sdk: flutter @@ -11,7 +14,3 @@ dependencies: open_file: ^3.0.1 syncfusion_flutter_xlsio: path: ../ - -# The following section is specific to Flutter. -flutter: - uses-material-design: true diff --git a/packages/syncfusion_flutter_xlsio/lib/src/test/async.dart b/packages/syncfusion_flutter_xlsio/lib/src/test/async.dart deleted file mode 100644 index 29069fe0a..000000000 --- a/packages/syncfusion_flutter_xlsio/lib/src/test/async.dart +++ /dev/null @@ -1,3035 +0,0 @@ -import 'dart:ui'; - -// ignore: depend_on_referenced_packages -import 'package:flutter_test/flutter_test.dart'; -import 'package:intl/intl.dart'; - -import '../../xlsio.dart'; -import 'xlsio_workbook.dart'; - -// ignore: public_member_api_docs -void xlsioAsync() { - group('Excel Async', () { - test('AutoFilter Async', () async { - final Workbook workbook = Workbook(4); - final Worksheet sheet = workbook.worksheets[0]; - - ///Loading data for text filter - sheet.getRangeByName('A1').setText('Angela Davis'); - sheet.getRangeByName('A2').setText('aNgeLa DaViS.'); - sheet.getRangeByName('A3').setText('Enoch Powell'); - sheet.getRangeByName('A4').setText('Al-Biruni'); - sheet.getRangeByName('A5').setText('ANgeLa DAViS'); - sheet.getRangeByName('A6').setText('Will Roscoe'); - sheet.getRangeByName('A7').setText('al-biruNi'); - sheet.getRangeByName('A8').setText('Christopher Hogwood'); - sheet.getRangeByName('A9').setText('Al-BirUni'); - sheet.getRangeByName('A10').setText('KarlMarx'); - - sheet.getRangeByName('B1').setText('India'); - sheet.getRangeByName('B2').setText('America'); - sheet.getRangeByName('B3').setText('Australia'); - sheet.getRangeByName('B4').setText('Russia'); - sheet.getRangeByName('B5').setText('Canada'); - sheet.getRangeByName('B6').setText('Japan'); - sheet.getRangeByName('B7').setText('China'); - sheet.getRangeByName('B8').setText('Srilanka'); - sheet.getRangeByName('B9').setText('Africa'); - sheet.getRangeByName('B10').setText('France'); - - //Intialize text filter - sheet.autoFilters.filterRange = sheet.getRangeByName('A1:B10'); - final AutoFilter autofilter = sheet.autoFilters[0]; - autofilter.addTextFilter({'Angela Davis', 'Al-BirUni'}); - - final Worksheet sheet2 = workbook.worksheets[1]; - - ///Loading data for color filter - sheet2.getRangeByName('E1').setText('Title'); - sheet2.getRangeByName('E2').setText('Sales Representative'); - sheet2.getRangeByName('E3').setText('Owner'); - sheet2.getRangeByName('E4').setText('Owner'); - sheet2.getRangeByName('E5').setText('Sales Representative'); - sheet2.getRangeByName('E6').setText('Order Administrator'); - sheet2.getRangeByName('E7').setText('Sales Representative'); - sheet2.getRangeByName('E8').setText('Marketing Manager'); - sheet2.getRangeByName('E9').setText('Owner'); - sheet2.getRangeByName('E10').setText('Owner'); - - sheet2.getRangeByName('F1').setText('DOJ'); - sheet2.getRangeByName('F2').dateTime = DateTime(2006, 9, 10); - sheet2.getRangeByName('F3').dateTime = DateTime(2000, 6, 10); - sheet2.getRangeByName('F4').dateTime = DateTime(2002, 9, 18); - sheet2.getRangeByName('F5').dateTime = DateTime(2009, 5, 23); - sheet2.getRangeByName('F6').dateTime = DateTime(2012, 1, 6); - sheet2.getRangeByName('F7').dateTime = DateTime(2007, 7, 19); - sheet2.getRangeByName('F8').dateTime = DateTime(2008, 6, 30); - sheet2.getRangeByName('F9').dateTime = DateTime(2002, 4, 16); - sheet2.getRangeByName('F10').dateTime = DateTime(2008, 11, 29); - - sheet2.getRangeByName('G1').setText('City'); - sheet2.getRangeByName('G2').setText('Berlin'); - sheet2.getRangeByName('G3').setText('México D.F.'); - sheet2.getRangeByName('G4').setText('México D.F.'); - sheet2.getRangeByName('G5').setText('London'); - sheet2.getRangeByName('G6').setText('Luleå'); - sheet2.getRangeByName('G7').setText('Mannheim'); - sheet2.getRangeByName('G8').setText('Strasbourg'); - sheet2.getRangeByName('G9').setText('Madrid'); - sheet2.getRangeByName('G10').setText('Marseille'); - - sheet2.getRangeByName('E2').cellStyle.backColor = '#008000'; - sheet2.getRangeByName('E3').cellStyle.backColor = '#0000FF'; - sheet2.getRangeByName('E4').cellStyle.backColor = '#FF0000'; - sheet2.getRangeByName('E5').cellStyle.backColor = '#FF0000'; - sheet2.getRangeByName('E6').cellStyle.backColor = '#FFFFFF'; - sheet2.getRangeByName('E7').cellStyle.backColor = '#FF0000'; - sheet2.getRangeByName('E8').cellStyle.backColor = '#FFFFFF'; - sheet2.getRangeByName('E9').cellStyle.backColor = '#0000FF'; - sheet2.getRangeByName('E10').cellStyle.backColor = '#008000'; - - sheet2.getRangeByName('G2').cellStyle.fontColor = '#FF0000'; - sheet2.getRangeByName('G3').cellStyle.fontColor = '#008000'; - sheet2.getRangeByName('G4').cellStyle.fontColor = '#0000FF'; - sheet2.getRangeByName('G5').cellStyle.fontColor = '#000000'; - sheet2.getRangeByName('G6').cellStyle.fontColor = '#FF0000'; - sheet2.getRangeByName('G7').cellStyle.fontColor = '#008000'; - sheet2.getRangeByName('G8').cellStyle.fontColor = '#0000FF'; - sheet2.getRangeByName('G9').cellStyle.fontColor = '#000000'; - sheet2.getRangeByName('G10').cellStyle.fontColor = '#FF0000'; - - //Intialize Filter Range - sheet2.autoFilters.filterRange = sheet2.getRangeByName('E1:G10'); - final AutoFilter autofilter2 = sheet2.autoFilters[2]; - autofilter2.addColorFilter('#0000FF', ExcelColorFilterType.fontColor); - sheet2.getRangeByName('E1:G10').autoFitColumns(); - - ///Loading data for number fulter - final Worksheet sheet3 = workbook.worksheets[2]; - - sheet3.getRangeByName('A1').setNumber(10); - sheet3.getRangeByName('A2').setNumber(15); - sheet3.getRangeByName('A3').setNumber(15.4); - sheet3.getRangeByName('A4').setNumber(20.4567678); - sheet3.getRangeByName('A5').setNumber(10); - sheet3.getRangeByName('A6').setNumber(20.00087788767667657577557007); - sheet3.getRangeByName('A7').setNumber(233); - sheet3.getRangeByName('A8').setNumber(10); - sheet3.getRangeByName('A9').setNumber(10.01); - sheet3.getRangeByName('A10').setNumber(9.99); - - sheet3.getRangeByName('B1').setText('Angela Davis'); - sheet3.getRangeByName('B2').setText('Sigmund Freud.'); - sheet3.getRangeByName('B3').setText('Enoch Powell'); - sheet3.getRangeByName('B4').setText('Al-Biruni'); - sheet3.getRangeByName('B5').setText('Joseph Campbell'); - sheet3.getRangeByName('B6').setText('Will Roscoe'); - sheet3.getRangeByName('B7').setText('Barry Bishop'); - sheet3.getRangeByName('B8').setText('Christopher Hogwood'); - sheet3.getRangeByName('B9').setText('Cornel West'); - sheet3.getRangeByName('B10').setText('KarlMarx'); - - //Intialize Filter Range - sheet3.autoFilters.filterRange = sheet3.getRangeByName('A1:C10'); - final AutoFilter filter = sheet3.autoFilters[0]; - final AutoFilterCondition firstCondition = filter.firstCondition; - firstCondition.conditionOperator = ExcelFilterCondition.equal; - firstCondition.numberValue = 10; - - //Loading data for datetime fulter - final Worksheet sheet4 = workbook.worksheets[3]; - - sheet4.getRangeByName('A1').setText('Title'); - sheet4.getRangeByName('A2').setText('Sales Representative'); - sheet4.getRangeByName('A3').setText('Owner'); - sheet4.getRangeByName('A4').setText('Owner'); - sheet4.getRangeByName('A5').setText('Sales Representative'); - sheet4.getRangeByName('A6').setText('Order Administrator'); - sheet4.getRangeByName('A7').setText('Sales Representative'); - sheet4.getRangeByName('A8').setText('Marketing Manager'); - sheet4.getRangeByName('A9').setText('Owner'); - sheet4.getRangeByName('A10').setText('Owner'); - - sheet4.getRangeByName('B1').setText('DOJ'); - sheet4.getRangeByName('B2').dateTime = DateTime(2006, 9, 10); - sheet4.getRangeByName('B3').dateTime = DateTime(2000, 6, 10); - sheet4.getRangeByName('B4').dateTime = DateTime(2002, 9, 18); - sheet4.getRangeByName('B5').dateTime = DateTime(2009, 5, 23); - sheet4.getRangeByName('B6').dateTime = DateTime(2012, 1, 6); - sheet4.getRangeByName('B7').dateTime = DateTime(2007, 7, 19); - sheet4.getRangeByName('B8').dateTime = DateTime(2008, 6, 30); - sheet4.getRangeByName('B9').dateTime = DateTime(2002, 4, 16); - sheet4.getRangeByName('B10').dateTime = DateTime(2008, 11, 29); - - sheet4.getRangeByName('C1').setText('City'); - sheet4.getRangeByName('C2').setText('Berlin'); - sheet4.getRangeByName('C3').setText('México D.F.'); - sheet4.getRangeByName('C4').setText('México D.F.'); - sheet4.getRangeByName('C5').setText('London'); - sheet4.getRangeByName('C6').setText('Luleå'); - sheet4.getRangeByName('C7').setText('Mannheim'); - sheet4.getRangeByName('C8').setText('Strasbourg'); - sheet4.getRangeByName('C9').setText('Madrid'); - sheet4.getRangeByName('C10').setText('Marseille'); - - //Intialize Filter Range - sheet4.autoFilters.filterRange = sheet4.getRangeByName('A1:C10'); - final AutoFilter autofilter3 = sheet4.autoFilters[1]; - autofilter3.addDateFilter(DateTime(2002), DateTimeFilterType.year); - - //saving Sheet - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'AutoFilterAsync.xlsx'); - workbook.dispose(); - }); - test('ConditionalFormats Async', () async { - final Workbook workbook = Workbook(3); - - // Conditional Formats for data bar - final Worksheet sheet = workbook.worksheets[0]; - - sheet.getRangeByName('A1').number = 1277; - sheet.getRangeByName('A2').number = 1003; - sheet.getRangeByName('A3').number = 1105; - sheet.getRangeByName('A4').number = 952; - sheet.getRangeByName('A5').number = 770; - sheet.getRangeByName('A6').number = 621; - sheet.getRangeByName('A7').number = 1311; - sheet.getRangeByName('A8').number = 730; - - final ConditionalFormats conditionalFormats = - sheet.getRangeByName('A1:A8').conditionalFormats; - final ConditionalFormat conditionalFormat = - conditionalFormats.addCondition(); - - conditionalFormat.formatType = ExcelCFType.dataBar; - final DataBar dataBar = conditionalFormat.dataBar!; - - dataBar.minPoint.type = ConditionValueType.lowestValue; - dataBar.maxPoint.type = ConditionValueType.highestValue; - - dataBar.barColor = '#9CD0F3'; - - dataBar.showValue = false; - - // Conditional Formats for color scale - final Worksheet sheet2 = workbook.worksheets[1]; - - sheet2.getRangeByName('A1').number = 12; - sheet2.getRangeByName('A2').number = 29; - sheet2.getRangeByName('A3').number = 41; - sheet2.getRangeByName('A4').number = 84; - sheet2.getRangeByName('A5').number = 90; - sheet2.getRangeByName('A6').number = 112; - sheet2.getRangeByName('A7').number = 131; - sheet2.getRangeByName('A8').number = 20; - sheet2.getRangeByName('A9').number = 54; - sheet2.getRangeByName('A10').number = 63; - - final ConditionalFormats conditionalFormats2 = - sheet2.getRangeByName('A1:A10').conditionalFormats; - final ConditionalFormat conditionalFormat2 = - conditionalFormats2.addCondition(); - - conditionalFormat2.formatType = ExcelCFType.colorScale; - final ColorScale colorScale = conditionalFormat2.colorScale!; - - colorScale.setConditionCount(2); - colorScale.criteria[0].formatColor = '#63BE7B'; - colorScale.criteria[0].type = ConditionValueType.lowestValue; - - colorScale.criteria[1].formatColor = '#FFEF9C'; - colorScale.criteria[1].type = ConditionValueType.highestValue; - - // Conditional Formats for icon set - final Worksheet sheet3 = workbook.worksheets[2]; - - sheet3.getRangeByName('A1').number = 98; - sheet3.getRangeByName('A2').number = 89; - sheet3.getRangeByName('A3').number = 13; - sheet3.getRangeByName('A4').number = 78; - sheet3.getRangeByName('A5').number = 68; - sheet3.getRangeByName('A6').number = 47; - sheet3.getRangeByName('A7').number = 34; - sheet3.getRangeByName('A8').number = 21; - sheet3.getRangeByName('A9').number = 53; - sheet3.getRangeByName('A10').number = 08; - - final ConditionalFormats conditions = - sheet3.getRangeByName('A1:A10').conditionalFormats; - final ConditionalFormat condition = conditions.addCondition(); - - condition.formatType = ExcelCFType.iconSet; - final IconSet iconSet = condition.iconSet!; - iconSet.iconSet = ExcelIconSetType.fourRating; - iconSet.iconCriteria[1].type = ConditionValueType.percent; - iconSet.iconCriteria[1].value = '40'; - iconSet.iconCriteria[2].type = ConditionValueType.percent; - iconSet.iconCriteria[2].value = '60'; - iconSet.iconCriteria[3].type = ConditionValueType.percent; - iconSet.iconCriteria[3].value = '80'; - iconSet.showIconOnly = true; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ConditionalFormatsAsync.xlsx'); - workbook.dispose(); - }); - test('Excel BuildInStyle Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - // Good, Bad, and Neutral - final Range range1 = sheet.getRangeByIndex(1, 1); - range1.number = 4; - range1.builtInStyle = BuiltInStyles.bad; - - final Range range2 = sheet.getRangeByName('A2'); - range2.text = 'M'; - range2.builtInStyle = BuiltInStyles.good; - - final Range range3 = sheet.getRangeByName('A3'); - range3.text = 'Zee'; - range3.builtInStyle = BuiltInStyles.neutral; - // Excel BuildInStyle NumberFormat - final Range range4 = sheet.getRangeByName('B1'); - range4.number = 44; - range4.builtInStyle = BuiltInStyles.comma0; - - final Range range5 = sheet.getRangeByName('B2'); - range5.number = 444; - range5.builtInStyle = BuiltInStyles.currency; - - final Range range6 = sheet.getRangeByName('B3'); - range6.number = 4444; - range6.builtInStyle = BuiltInStyles.currency0; - - final Range range7 = sheet.getRangeByName('B4'); - range7.number = 4; - range7.builtInStyle = BuiltInStyles.percent; - // Data and Model - final Range range8 = sheet.getRangeByIndex(1, 3); - range8.number = 22; - range8.builtInStyle = BuiltInStyles.calculation; - - final Range range9 = sheet.getRangeByName('C2'); - range9.text = 'Hai'; - range9.builtInStyle = BuiltInStyles.checkCell; - - final Range range10 = sheet.getRangeByName('C3'); - range10.text = 'Jumbo'; - range10.builtInStyle = BuiltInStyles.explanatoryText; - - final Range range11 = sheet.getRangeByIndex(4, 3); - range11.number = 44; - range11.builtInStyle = BuiltInStyles.input; - - final Range range12 = sheet.getRangeByIndex(5, 3); - range12.text = 'MJ'; - range12.builtInStyle = BuiltInStyles.linkedCell; - - final Range range13 = sheet.getRangeByIndex(6, 3); - range13.setNumber(-40); - range13.builtInStyle = BuiltInStyles.note; - - final Range range14 = sheet.getRangeByIndex(7, 3); - range14.setText('zeee'); - range14.builtInStyle = BuiltInStyles.output; - - final Range range15 = sheet.getRangeByIndex(8, 3); - range15.text = 'Wrong!'; - range15.builtInStyle = BuiltInStyles.warningText; - // Titles and Heading - final Range range16 = sheet.getRangeByIndex(1, 4); - range16.text = 'Time'; - range16.builtInStyle = BuiltInStyles.heading1; - - final Range range17 = sheet.getRangeByName('D2'); - range17.text = 'POWER'; - range17.builtInStyle = BuiltInStyles.heading2; - - final Range range18 = sheet.getRangeByName('D3'); - range18.text = 'TriAngle'; - range18.builtInStyle = BuiltInStyles.heading3; - - final Range range19 = sheet.getRangeByIndex(4, 4); - range19.number = 1000; - range19.builtInStyle = BuiltInStyles.heading4; - - final Range range20 = sheet.getRangeByIndex(5, 4); - range20.text = 'Man'; - range20.builtInStyle = BuiltInStyles.title; - - final Range range21 = sheet.getRangeByIndex(6, 4); - range21.setNumber(200); - range21.builtInStyle = BuiltInStyles.total; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelBuildInStyleAsync.xlsx'); - workbook.dispose(); - }); - test('Freezepane Async', () async { - //Creating a workbook. - final Workbook workbook = Workbook(0); - //Adding a Sheet with name to workbook. - final Worksheet sheet = workbook.worksheets.addWithName('Table'); - - //Load data - sheet.getRangeByName('A1').setText('Products'); - sheet.getRangeByName('B1').setText('Qtr1'); - sheet.getRangeByName('C1').setText('Qtr2'); - sheet.getRangeByName('D1').setText('Qtr3'); - sheet.getRangeByName('E1').setText('Qtr4'); - - sheet.getRangeByName('A2').setText('Phone Holder'); - sheet.getRangeByName('B2').setNumber(744.6); - sheet.getRangeByName('C2').setNumber(162.56); - sheet.getRangeByName('D2').setNumber(5079.6); - sheet.getRangeByName('E2').setNumber(1249.2); - - sheet.getRangeByName('A3').setText('Digital Picture Frame'); - sheet.getRangeByName('B3').setNumber(5079.6); - sheet.getRangeByName('C3').setNumber(1249.2); - sheet.getRangeByName('D3').setNumber(943.89); - sheet.getRangeByName('E3').setNumber(349.6); - - sheet.getRangeByName('A4').setText('USB Charging Cable'); - sheet.getRangeByName('B4').setNumber(1267.5); - sheet.getRangeByName('C4').setNumber(1062.5); - sheet.getRangeByName('D4').setNumber(744.6); - sheet.getRangeByName('E4').setNumber(162.56); - - sheet.getRangeByName('A5').setText('Selfie Stick Tripod'); - sheet.getRangeByName('B5').setNumber(1418); - sheet.getRangeByName('C5').setNumber(756); - sheet.getRangeByName('D5').setNumber(1267.5); - sheet.getRangeByName('E5').setNumber(1062.5); - - sheet.getRangeByName('A6').setText('MicroSD Card'); - sheet.getRangeByName('B6').setNumber(4728); - sheet.getRangeByName('C6').setNumber(4547.92); - sheet.getRangeByName('D6').setNumber(1418); - sheet.getRangeByName('E6').setNumber(756); - - sheet.getRangeByName('A7').setText('HDMI Cable'); - sheet.getRangeByName('B7').setNumber(943.89); - sheet.getRangeByName('C7').setNumber(349.6); - sheet.getRangeByName('D7').setNumber(4728); - sheet.getRangeByName('E7').setNumber(4547.92); - - sheet.getRangeByName('A8').setText('Key Finder'); - sheet.getRangeByName('B8').setNumber(149.33); - sheet.getRangeByName('C8').setNumber(642.04); - sheet.getRangeByName('D8').setNumber(1249.83); - sheet.getRangeByName('E8').setNumber(7850.1); - - sheet.getRangeByName('A9').setText('Light Stand'); - sheet.getRangeByName('B9').setNumber(6534.22); - sheet.getRangeByName('C9').setNumber(3201.95); - sheet.getRangeByName('D9').setNumber(1002.25); - sheet.getRangeByName('E9').setNumber(124.60); - - sheet.getRangeByName('A10').setText('External Hard Drive'); - sheet.getRangeByName('B10').setNumber(245.45); - sheet.getRangeByName('C10').setNumber(955.2); - sheet.getRangeByName('D10').setNumber(4655.99); - sheet.getRangeByName('E10').setNumber(8745.45); - - sheet.getRangeByName('A11').setText('Laptop'); - sheet.getRangeByName('B11').setNumber(450.105); - sheet.getRangeByName('C11').setNumber(1049.54); - sheet.getRangeByName('D11').setNumber(1248.35); - sheet.getRangeByName('E11').setNumber(204.1); - - sheet.getRangeByName('A12').setText('Graphic Card'); - sheet.getRangeByName('B12').setNumber(764.77); - sheet.getRangeByName('C12').setNumber(955.2); - sheet.getRangeByName('D12').setNumber(100.4); - sheet.getRangeByName('E12').setNumber(8383.9); - - sheet.getRangeByName('A13').setText('Keyboard'); - sheet.getRangeByName('B13').setNumber(943.89); - sheet.getRangeByName('C13').setNumber(349.6); - sheet.getRangeByName('D13').setNumber(4728); - sheet.getRangeByName('E13').setNumber(4547.92); - - sheet.getRangeByName('A14').setText('Mouse'); - sheet.getRangeByName('B14').setNumber(234.33); - sheet.getRangeByName('C14').setNumber(982.6); - sheet.getRangeByName('D14').setNumber(719.7); - sheet.getRangeByName('E14').setNumber(7249); - - sheet.getRangeByName('A15').setText('Webcam'); - sheet.getRangeByName('B15').setNumber(749.11); - sheet.getRangeByName('C15').setNumber(349.2); - sheet.getRangeByName('D15').setNumber(743.09); - sheet.getRangeByName('E15').setNumber(564.97); - - sheet.getRangeByName('A16').setText('eBook Reader'); - sheet.getRangeByName('B16').setNumber(3217.04); - sheet.getRangeByName('C16').setNumber(652.5); - sheet.getRangeByName('D16').setNumber(842.6); - sheet.getRangeByName('E16').setNumber(242.56); - - sheet.getRangeByName('A17').setText('GPS Navigator'); - sheet.getRangeByName('B17').setNumber(843.5); - sheet.getRangeByName('C17').setNumber(619.3); - sheet.getRangeByName('D17').setNumber(167.56); - sheet.getRangeByName('E17').setNumber(189.5); - - sheet.getRangeByName('A18').setText('Monitor'); - sheet.getRangeByName('B18').setNumber(952.8); - sheet.getRangeByName('C18').setNumber(4547); - sheet.getRangeByName('D18').setNumber(1418); - sheet.getRangeByName('E18').setNumber(756); - - sheet.getRangeByName('A19').setText('Laptop Stand'); - sheet.getRangeByName('B19').setNumber(413.89); - sheet.getRangeByName('C19').setNumber(349.6); - sheet.getRangeByName('D19').setNumber(4728); - sheet.getRangeByName('E19').setNumber(4547.92); - - sheet.getRangeByName('A20').setText('Smartwatch'); - sheet.getRangeByName('B20').setNumber(948.07); - sheet.getRangeByName('C20').setNumber(642.04); - sheet.getRangeByName('D20').setNumber(1249.83); - sheet.getRangeByName('E20').setNumber(7850.1); - - sheet.getRangeByName('A21').setText('Bluetooth Earphones'); - sheet.getRangeByName('B21').setNumber(1134); - sheet.getRangeByName('C21').setNumber(3201.95); - sheet.getRangeByName('D21').setNumber(1002.25); - sheet.getRangeByName('E21').setNumber(124.60); - - sheet.getRangeByName('A22').setText('Reader Case'); - sheet.getRangeByName('B22').setNumber(865.76); - sheet.getRangeByName('C22').setNumber(955.2); - sheet.getRangeByName('D22').setNumber(4655.99); - sheet.getRangeByName('E22').setNumber(8745.45); - - sheet.getRangeByName('A23').setText('Smart Glass'); - sheet.getRangeByName('B23').setNumber(1450.5); - sheet.getRangeByName('C23').setNumber(1049.54); - sheet.getRangeByName('D23').setNumber(1248.35); - sheet.getRangeByName('E23').setNumber(204.1); - - sheet.getRangeByName('A24').setText('Remote Controller'); - sheet.getRangeByName('B24').setNumber(877.75); - sheet.getRangeByName('C24').setNumber(955.2); - sheet.getRangeByName('D24').setNumber(100.4); - sheet.getRangeByName('E24').setNumber(8383.9); - - sheet.getRangeByName('A25').setText('Game Console'); - sheet.getRangeByName('B25').setNumber(343.89); - sheet.getRangeByName('C25').setNumber(349.6); - sheet.getRangeByName('D25').setNumber(4728); - sheet.getRangeByName('E25').setNumber(447.92); - - ///Create a table with the data in a range - final ExcelTable table = sheet.tableCollection - .create('Table1', sheet.getRangeByName('A1:E25')); - - ///Formatting table with a built-in style - table.builtInTableStyle = ExcelTableBuiltInStyle.tableStyleMedium9; - - table.showTotalRow = true; - table.showFirstColumn = true; - table.showBandedColumns = true; - table.showBandedRows = true; - table.columns[0].totalRowLabel = 'Total'; - table.columns[1].totalFormula = ExcelTableTotalFormula.sum; - table.columns[2].totalFormula = ExcelTableTotalFormula.sum; - table.columns[3].totalFormula = ExcelTableTotalFormula.sum; - table.columns[4].totalFormula = ExcelTableTotalFormula.sum; - - final Range range = sheet.getRangeByName('B2:E26'); - range.numberFormat = r'_($* #,##0.00_)'; - - sheet.getRangeByName('A1:E25').autoFitColumns(); - //Freezepane - sheet.getRangeByName('A2').freezePanes(); - - //Save and dispose Workbook - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'FreezepaneAsync.xlsx'); - workbook.dispose(); - }); - test('Excel PageSetup Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - - final Style style = workbook.styles.add('style'); - style.fontColor = '#C67878'; - final Range range = sheet.getRangeByName('A1:D4'); - range.text = 'BlackWhite'; - range.cellStyle = style; - // Blackandwhite - sheet.pageSetup.isBlackAndWhite = true; - // grid line - sheet.pageSetup.showGridlines = true; - // Print headings - sheet.pageSetup.showHeadings = true; - // Center Horizontally and center Vertically - sheet.pageSetup.isCenterHorizontally = true; - sheet.pageSetup.isCenterVertically = true; - // landscape - sheet.pageSetup.orientation = ExcelPageOrientation.landscape; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'PageSetupAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Named range Async', () async { - final Workbook workbook = Workbook(2); - final Worksheet sheet1 = workbook.worksheets[0]; - final Worksheet sheet2 = workbook.worksheets[1]; - sheet1.getRangeByName('A1:G1').number = 10; - sheet1.getRangeByName('A2:G2').number = 20; - sheet1.getRangeByName('A3:G3').number = 25; - final Range range1 = sheet1.getRangeByName('A1'); - final Range range2 = sheet1.getRangeByName('A2'); - final Range range3 = sheet1.getRangeByName('A3'); - workbook.names.add('NumberOne', range1); - workbook.names.add('NumberTwo', range2); - workbook.names.add('NumberThree', range3); - final Range range4 = sheet1.getRangeByName('B1:B3'); - workbook.names.add('namedRange', range4); - final Range range5 = sheet1.getRangeByName('C1'); - final Range range6 = sheet1.getRangeByName('C2'); - workbook.names.add('FirstNumber', range5); - workbook.names.add('SecondNumber', range6); - // Formula - final Range rangeFormula1 = sheet1.getRangeByIndex(4, 1); - rangeFormula1.formula = '=NumberOne-NumberTwo+NumberThree'; - final Range rangeFormula2 = sheet1.getRangeByIndex(4, 2); - rangeFormula2.formula = '=SUM(namedRange)'; - final Range rangeFormula3 = sheet1.getRangeByIndex(4, 3); - rangeFormula3.formula = '=FirstNumber>SecondNumber'; - final Range rangeFormula4 = sheet1.getRangeByIndex(4, 4); - rangeFormula4.formula = '=IF(FirstNumber bytes = await workbook.save(); - saveAsExcel(bytes, 'NamedRangeAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Text async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - final Range range = sheet.getRangeByIndex(1, 1); - range.text = 'M\nM'; - final Range range1 = sheet.getRangeByName('A2'); - range1.text = 'M\tJ'; - final Range range2 = sheet.getRangeByIndex(3, 1); - range2.text = '--'; - final Range range3 = sheet.getRangeByName('A4'); - range3.text = '#'; - final Range range4 = sheet.getRangeByName('A5'); - range4.text = '|'; - final Range range5 = sheet.getRangeByIndex(6, 1); - range5.text = r'\\'; - final Range range6 = sheet.getRangeByIndex(7, 1); - range6.text = "'"; - final Range range7 = sheet.getRangeByName('A8'); - range7.text = '@'; - final Range range8 = sheet.getRangeByIndex(9, 1); - range8.text = '!'; - final Range range9 = sheet.getRangeByName('A10'); - range9.text = r'$'; - final Range range10 = sheet.getRangeByName('A11'); - range10.text = '%'; - final Range range11 = sheet.getRangeByIndex(12, 1); - range11.text = '^'; - final Range range12 = sheet.getRangeByName('A13'); - range12.text = '&'; - final Range range13 = sheet.getRangeByIndex(14, 1); - range13.text = '*'; - final Range range14 = sheet.getRangeByName('A15'); - range14.text = '('; - final Range range15 = sheet.getRangeByIndex(16, 1); - range15.text = ')'; - final Range range16 = sheet.getRangeByIndex(17, 1); - range16.text = '+'; - final Range range17 = sheet.getRangeByName('A18'); - range17.text = '}'; - final Range range18 = sheet.getRangeByIndex(19, 1); - range18.text = ']'; - final Range range19 = sheet.getRangeByName('A20'); - range19.text = '{'; - final Range range20 = sheet.getRangeByName('A21'); - range20.text = '['; - final Range range21 = sheet.getRangeByIndex(22, 1); - range21.text = '"'; - final Range range22 = sheet.getRangeByName('A23'); - range22.text = ':'; - final Range range23 = sheet.getRangeByIndex(24, 1); - range23.text = ';'; - final Range range24 = sheet.getRangeByName('A25'); - range24.text = '?'; - final Range range25 = sheet.getRangeByIndex(26, 1); - range25.text = '/'; - final Range range26 = sheet.getRangeByIndex(27, 1); - range26.text = '>'; - final Range range27 = sheet.getRangeByName('A28'); - range27.text = '.'; - final Range range28 = sheet.getRangeByIndex(29, 1); - range28.text = '<'; - final Range range29 = sheet.getRangeByName('A30'); - range29.text = ','; - final Range range30 = sheet.getRangeByName('A31'); - range30.text = '`'; - final Range range31 = sheet.getRangeByName('A32'); - range31.text = '~'; - final Range range32 = sheet.getRangeByIndex(33, 1); - range32.text = '='; - final Range range33 = sheet.getRangeByName('A34'); - range33.text = '_'; - final Range range34 = sheet.getRangeByName('A35'); - range34.text = '0'; - final Range range35 = sheet.getRangeByIndex(36, 1); - range35.text = '4'; - final Range range36 = sheet.getRangeByIndex(37, 1); - range36.text = '44'; - final Range range37 = sheet.getRangeByName('A38'); - range37.text = '444'; - final Range range38 = sheet.getRangeByIndex(39, 1); - range38.text = 'a'; - final Range range39 = sheet.getRangeByName('A40'); - range39.text = 'b'; - final Range range40 = sheet.getRangeByName('A41'); - range40.text = 'c'; - final Range range41 = sheet.getRangeByName('A42'); - range41.text = 'd'; - final Range range42 = sheet.getRangeByIndex(43, 1); - range42.text = 'e'; - final Range range43 = sheet.getRangeByName('A44'); - range43.text = 'f'; - final Range range44 = sheet.getRangeByName('A45'); - range44.text = 'g'; - final Range range45 = sheet.getRangeByIndex(46, 1); - range45.text = 'h'; - final Range range46 = sheet.getRangeByIndex(47, 1); - range46.text = 'i'; - final Range range47 = sheet.getRangeByName('A48'); - range47.text = 'j'; - final Range range48 = sheet.getRangeByIndex(49, 1); - range48.text = 'k'; - final Range range49 = sheet.getRangeByName('A50'); - range49.text = 'l'; - final Range range50 = sheet.getRangeByName('A51'); - range50.text = 'm'; - final Range range51 = sheet.getRangeByName('A52'); - range51.text = 'n'; - final Range range52 = sheet.getRangeByIndex(53, 1); - range52.text = 'o'; - final Range range53 = sheet.getRangeByName('A54'); - range53.text = 'p'; - final Range range54 = sheet.getRangeByName('A55'); - range54.text = 'q'; - final Range range55 = sheet.getRangeByIndex(56, 1); - range55.text = 'r'; - final Range range56 = sheet.getRangeByIndex(57, 1); - range56.text = 's'; - final Range range57 = sheet.getRangeByName('A58'); - range57.text = 't'; - final Range range58 = sheet.getRangeByIndex(59, 1); - range58.text = 'u'; - final Range range59 = sheet.getRangeByName('A60'); - range59.text = 'v'; - final Range range60 = sheet.getRangeByName('A61'); - range60.text = 'w'; - final Range range61 = sheet.getRangeByName('A62'); - range61.text = 'x'; - final Range range62 = sheet.getRangeByIndex(63, 1); - range62.text = 'y'; - final Range range63 = sheet.getRangeByName('A64'); - range63.text = 'z'; - final Range range64 = sheet.getRangeByName('A65'); - range64.text = 'A'; - final Range range65 = sheet.getRangeByIndex(66, 1); - range65.text = 'B'; - final Range range66 = sheet.getRangeByIndex(67, 1); - range66.text = 'C'; - final Range range67 = sheet.getRangeByName('A68'); - range67.text = 'D'; - final Range range68 = sheet.getRangeByIndex(69, 1); - range68.text = 'E'; - final Range range69 = sheet.getRangeByName('A70'); - range69.text = 'F'; - final Range range70 = sheet.getRangeByName('A71'); - range70.text = 'G'; - final Range range71 = sheet.getRangeByName('A72'); - range71.text = 'H'; - final Range range72 = sheet.getRangeByIndex(73, 1); - range72.text = 'I'; - final Range range73 = sheet.getRangeByName('A74'); - range73.text = 'J'; - final Range range74 = sheet.getRangeByName('A75'); - range74.text = 'K'; - final Range range75 = sheet.getRangeByIndex(76, 1); - range75.text = 'L'; - final Range range76 = sheet.getRangeByIndex(77, 1); - range76.text = 'M'; - final Range range77 = sheet.getRangeByName('A78'); - range77.text = 'N'; - final Range range78 = sheet.getRangeByIndex(79, 1); - range78.text = 'O'; - final Range range79 = sheet.getRangeByName('A80'); - range79.text = 'P'; - final Range range80 = sheet.getRangeByName('A81'); - range80.text = 'Q'; - final Range range81 = sheet.getRangeByName('A82'); - range81.text = 'R'; - final Range range82 = sheet.getRangeByIndex(83, 1); - range82.text = 'S'; - final Range range83 = sheet.getRangeByName('A84'); - range83.text = 'T'; - final Range range84 = sheet.getRangeByName('A85'); - range84.text = 'U'; - final Range range85 = sheet.getRangeByIndex(86, 1); - range85.text = 'V'; - final Range range86 = sheet.getRangeByIndex(87, 1); - range86.text = 'W'; - final Range range87 = sheet.getRangeByName('A88'); - range87.text = 'X'; - final Range range88 = sheet.getRangeByIndex(89, 1); - range88.text = 'Y'; - final Range range89 = sheet.getRangeByName('A90'); - range89.text = 'Z'; - final Range range90 = sheet.getRangeByName('A91'); - range90.text = '0'; - final Range range91 = sheet.getRangeByName('A92'); - range91.text = '1'; - final Range range92 = sheet.getRangeByIndex(93, 1); - range92.text = '2'; - final Range range93 = sheet.getRangeByName('A94'); - range93.text = '3'; - final Range range94 = sheet.getRangeByName('A95'); - range94.text = '4'; - final Range range95 = sheet.getRangeByIndex(96, 1); - range95.text = '5'; - final Range range96 = sheet.getRangeByIndex(97, 1); - range96.text = '6'; - final Range range97 = sheet.getRangeByName('A98'); - range97.text = '7'; - final Range range98 = sheet.getRangeByIndex(99, 1); - range98.text = '8'; - final Range range99 = sheet.getRangeByName('A100'); - range99.text = '9'; - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'TextAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Number Async', () async { - final Workbook workbook = Workbook(2); - final Worksheet sheet = workbook.worksheets[1]; - // number for single range - final Range range = sheet.getRangeByIndex(1, 1); - range.number = -100; - // number for multiple range - final Range range1 = sheet.getRangeByIndex(2, 1, 2, 2); - range1.number = 26; - // number with Name Index - final Range range2 = sheet.getRangeByName('A3'); - range2.number = 100000; - // number for Multiple final Range with Name Index - final Range range3 = sheet.getRangeByName('A4:C4'); - range3.number = -1000; - // number for single range - final Range range4 = sheet.getRangeByIndex(1, 1); - range4.setNumber(-10); - // number for multiple range - final Range range5 = sheet.getRangeByIndex(2, 1, 2, 2); - range5.setNumber(26); - // number with Name Index - final Range range6 = sheet.getRangeByName('A3'); - range6.setNumber(100000); - // number for Multiple final Range with Name Index - final Range range7 = sheet.getRangeByName('A4:C4'); - range7.setNumber(-1000); - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'NumberAsync.xlsx'); - workbook.dispose(); - }); - test('Excel DateTime Async', () async { - final Workbook workbook = Workbook(2); - final Worksheet sheet = workbook.worksheets[0]; - // setDateTime() for single and Multiple Range - final Range range = sheet.getRangeByIndex(1, 1); - range.setDateTime(DateTime(2004, 12, 24, 18, 30, 50)); - final Range range1 = sheet.getRangeByIndex(4, 1, 4, 4); - range1.setDateTime(DateTime(1990, 3, 25, 16, 50, 40)); - final Range range2 = sheet.getRangeByName('J15:M20'); - range2.setDateTime(DateTime.now()); - final Range range3 = sheet.getRangeByName('O2:R6'); - range3.setDateTime(DateTime(2002, 5, 5, 22, 49, 20)); - // dateTime() for single and Multiple Range - final Range range4 = sheet.getRangeByIndex(2, 1); - range4.dateTime = DateTime(2011, 1, 20, 20, 37, 80); - final Range range5 = sheet.getRangeByIndex(3, 1, 3, 4); - range5.dateTime = DateTime(1999, 6, 5, 6, 0, 40); - final Range range6 = sheet.getRangeByName('K20:N30'); - range6.dateTime = DateTime.now(); - final Range range7 = sheet.getRangeByName('S12:V16'); - range7.dateTime = DateTime(2323, 10, 15, 2, 9); - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelDateTimeAsync.xlsx'); - workbook.dispose(); - }); - test('Excel DisplayText Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - final Range range = sheet.getRangeByIndex(1, 1); - range.numberFormat = 'h:mm:ss AM/PM'; - range.setDateTime(DateTime(2020, 8, 23, 10, 15, 20)); - // ignore: unused_local_variable - String text = range.displayText; - final Range range1 = sheet.getRangeByIndex(1, 2); - range1.numberFormat = 'h:mm'; - range1.setDateTime(DateTime(2020, 08, 23, 8, 15, 20)); - text = range1.displayText; - final Range range2 = sheet.getRangeByIndex(1, 3); - range2.numberFormat = 'mm:ss.0'; - range2.setDateTime(DateTime(2020, 08, 23, 8, 15, 20)); - text = range2.displayText; - final Range range3 = sheet.getRangeByIndex(1, 4); - range3.numberFormat = '[h]:mm:ss'; - range3.setDateTime(DateTime(2020, 08, 23, 8, 15, 20)); - text = range3.displayText; - final Range range4 = sheet.getRangeByIndex(1, 5); - range4.numberFormat = 'h.mm'; - range4.setDateTime(DateTime(2011, 04, 04, 12, 47, 6)); - text = range4.displayText; - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'DisplayTextAsync.xlsx'); - workbook.dispose(); - }); - test('Excel NumberFormat Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - - final Range range1 = sheet.getRangeByName('A1'); - range1.number = 100; - range1.numberFormat = '0'; - - final Range range2 = sheet.getRangeByIndex(3, 1); - range2.number = 10; - range2.numberFormat = '0.00'; - - final Range range3 = sheet.getRangeByName('A5'); - range3.number = 44; - range3.numberFormat = '#,##0'; - - final Range range4 = sheet.getRangeByIndex(17, 1); - range4.number = 1; - range4.numberFormat = '#,##0.00'; - - final Range range5 = sheet.getRangeByName('A7'); - range5.number = 4.00; - range5.numberFormat = '#,##0'; - - final Range range6 = sheet.getRangeByIndex(9, 1); - range6.number = 16; - range6.numberFormat = r"'$'#,##0_)"; - - final Range range7 = sheet.getRangeByName('A11'); - range7.number = 22; - range7.numberFormat = r"\('$'#,##0\)"; - - final Range range8 = sheet.getRangeByIndex(13, 1); - range8.number = -33; - range8.numberFormat = r"'$'#,##0_)"; - - final Range range9 = sheet.getRangeByName('A15'); - range9.number = 2.20; - range9.numberFormat = r"[Red]\('$'#,##0\)"; - - final Range range10 = sheet.getRangeByIndex(1, 3); - range10.number = -64; - range10.numberFormat = r"'$'#,##0.00_)"; - - final Range range11 = sheet.getRangeByName('C3'); - range11.number = 25; - range11.numberFormat = r"\('$'#,##0.00\)"; - - final Range range12 = sheet.getRangeByIndex(5, 3); - range12.number = 55; - range12.numberFormat = r"'$'#,##0.00_)"; - - final Range range13 = sheet.getRangeByName('C7'); - range13.number = 30; - range13.numberFormat = r"[Red]\('$'#,##0.00\)"; - - final Range range14 = sheet.getRangeByIndex(9, 3); - range14.number = 11; - range14.numberFormat = '0%'; - - final Range range15 = sheet.getRangeByName('C11'); - range15.number = 4; - range15.numberFormat = '0.00%'; - - final Range range16 = sheet.getRangeByIndex(13, 3); - range16.number = 432561; - range16.numberFormat = '0.00E+00'; - - final Range range17 = sheet.getRangeByName('C15'); - range17.number = 38.00; - range17.numberFormat = '# ?/?'; - - final Range range18 = sheet.getRangeByIndex(1, 5); - range18.number = -33; - range18.numberFormat = '# ??/??'; - - final Range range19 = sheet.getRangeByName('E3'); - range19.dateTime = DateTime(2022, 08, 23, 8, 15, 20); - range19.numberFormat = r'm/d/yyyy'; - - final Range range20 = sheet.getRangeByIndex(5, 5); - range20.dateTime = DateTime(2024, 01, 03, 18, 45, 60); - range20.numberFormat = r'd\-mmm\-yy'; - - final Range range21 = sheet.getRangeByName('E7'); - range21.dateTime = DateTime(2000, 12, 12); - range21.numberFormat = r'd\-mmm'; - - final Range range22 = sheet.getRangeByIndex(9, 5); - range22.dateTime = DateTime(2011, 11, 11); - range22.numberFormat = r'mmm\-yy'; - - final Range range23 = sheet.getRangeByName('E11'); - range23.dateTime = DateTime(2120, 08, 09, 10, 11, 12); - range23.numberFormat = r'h:mm\\ AM/PM'; - - final Range range24 = sheet.getRangeByIndex(13, 5); - range24.dateTime = DateTime(1997, 09, 10, 11, 12, 13); - range24.numberFormat = r'h:mm:ss\\ AM/PM'; - - final Range range25 = sheet.getRangeByName('E15'); - range25.dateTime = DateTime.now(); - range25.numberFormat = 'h:mm'; - - final Range range26 = sheet.getRangeByIndex(1, 7); - range26.dateTime = DateTime(2021, 11, 07, 20, 40, 19); - range26.numberFormat = 'h:mm:ss'; - - final Range range27 = sheet.getRangeByName('G3'); - range27.dateTime = DateTime(2024, 03, 07, 2, 4, 6); - range27.numberFormat = r'm/d/yyyy\\ h:mm'; - - final Range range28 = sheet.getRangeByIndex(5, 7); - range28.number = -11; - range28.numberFormat = '#,##0_)'; - - final Range range29 = sheet.getRangeByName('G7'); - range29.number = 2.59; - range29.numberFormat = '(#,##0)'; - - final Range range30 = sheet.getRangeByIndex(9, 7); - range30.number = -39; - range30.numberFormat = '#,##0_)'; - - final Range range31 = sheet.getRangeByName('G11'); - range31.number = 194; - range31.numberFormat = '[Red](#,##0)'; - - final Range range32 = sheet.getRangeByIndex(13, 7); - range32.number = -10; - range32.numberFormat = '#,##0.00_)'; - - final Range range33 = sheet.getRangeByName('G15'); - range33.number = 54; - range33.numberFormat = '(#,##0.00)'; - - final Range range34 = sheet.getRangeByIndex(1, 9); - range34.number = 60; - range34.numberFormat = '#,##0.00_)'; - - final Range range35 = sheet.getRangeByName('I3'); - range35.number = 99.9; - range35.numberFormat = '[Red](#,##0.00)'; - - final Range range36 = sheet.getRangeByIndex(5, 9); - range36.number = 160; - range36.numberFormat = r'_(* #,##0_)'; - - final Range range37 = sheet.getRangeByName('I7'); - range37.number = 37.00; - range37.numberFormat = r'_(* \\(#,##0\\)'; - - final Range range38 = sheet.getRangeByIndex(9, 9); - range38.number = -3.3; - range38.numberFormat = r"_(* '-'_)"; - - final Range range39 = sheet.getRangeByName('I11'); - range39.number = 763; - range39.numberFormat = r'_(@_)'; - - final Range range40 = sheet.getRangeByIndex(13, 9); - range40.number = 3828; - range40.numberFormat = r"_('$'* #,##0_)"; - - final Range range41 = sheet.getRangeByName('I15'); - range41.number = 4.40; - range41.numberFormat = r"_('$'* \(#,##0\)"; - - final Range range42 = sheet.getRangeByIndex(1, 11); - range42.number = 112; - range42.numberFormat = r"_('$'* '-'_)"; - - final Range range43 = sheet.getRangeByName('K3'); - range43.number = 44; - range43.numberFormat = r'_(@_)'; - - final Range range44 = sheet.getRangeByIndex(5, 11); - range44.number = 29; - range44.numberFormat = '_(* #,##0.00_)'; - - final Range range45 = sheet.getRangeByName('K7'); - range45.number = -231.9; - range45.numberFormat = r'_(* \\(#,##0.00\\)'; - - final Range range46 = sheet.getRangeByIndex(9, 11); - range46.number = 134; - range46.numberFormat = r"_(* '-'??_)"; - - final Range range47 = sheet.getRangeByName('K11'); - range47.number = 2212; - range47.numberFormat = r'_(@_)'; - - final Range range48 = sheet.getRangeByIndex(13, 11); - range48.number = -33.6; - range48.numberFormat = r"_('$'* #,##0.00_)"; - - final Range range49 = sheet.getRangeByName('K15'); - range49.number = 25.8; - range49.numberFormat = r"_('$'* \(#,##0.00\)"; - - final Range range50 = sheet.getRangeByIndex(1, 13); - range50.number = -64.2; - range50.numberFormat = r"_('$'* '-'??_)"; - - final Range range51 = sheet.getRangeByName('M3'); - range51.number = 100; - range51.numberFormat = r'_(@_)'; - - final Range range52 = sheet.getRangeByIndex(5, 13); - range52.dateTime = DateTime(2008, 08, 08, 8, 8, 8); - range52.numberFormat = 'mm:ss'; - - final Range range53 = sheet.getRangeByName('M7'); - range53.dateTime = DateTime(2019, 09, 09, 9, 19, 9); - range53.numberFormat = '[h]:mm:ss'; - - final Range range54 = sheet.getRangeByIndex(9, 13); - range54.dateTime = DateTime(2007, 07, 07, 7, 7, 7); - range54.numberFormat = 'mm:ss.0'; - - final Range range55 = sheet.getRangeByName('M11'); - range55.number = 567; - range55.numberFormat = '##0.0E+0'; - - final Range range56 = sheet.getRangeByIndex(13, 13); - range56.number = 1622; - range56.numberFormat = '@'; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelNumberFormatAsync.xlsx'); - workbook.dispose(); - }); - test('Excel MergeCells Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - // Merge row - final Range range1 = sheet.getRangeByName('A1:D1'); - range1.number = 10; - range1.merge(); - // Unmerge row - final Range range2 = sheet.getRangeByName('E4:H4'); - range2.text = 'M'; - range2.merge(); - range2.unmerge(); - // Merge column - final Range range3 = sheet.getRangeByIndex(4, 2, 7, 2); - range3.dateTime = DateTime(1997, 11, 22); - range3.merge(); - // Unmerge column - final Range range4 = sheet.getRangeByName('P8:P40'); - range4.number = 55; - range4.merge(); - range4.unmerge(); - // Merge Rows and columns - final Range range5 = sheet.getRangeByIndex(1, 7, 8, 10); - range5.text = 'Helloo'; - range5.merge(); - // Unmerge Rows and columns - final Range range6 = sheet.getRangeByName('G15:I20'); - range6.dateTime = DateTime(2222, 10, 10); - range6.merge(); - range6.unmerge(); - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelMergeCellAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Cell style async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - // number formate - final CellStyle cellStyle1 = CellStyle(workbook); - cellStyle1.name = 'Style1'; - cellStyle1.numberFormat = '#,##0.00'; - workbook.styles.addStyle(cellStyle1); - final Range range = sheet.getRangeByName('A1'); - range.number = 10; - range.cellStyle = cellStyle1; - // border - final CellStyle cellStyle2 = CellStyle(workbook); - cellStyle2.name = 'Style1'; - cellStyle2.borders.all.lineStyle = LineStyle.double; - cellStyle2.borders.all.color = '#111111'; - workbook.styles.addStyle(cellStyle2); - final Range range1 = sheet.getRangeByName('A2'); - range1.cellStyle = cellStyle2; - // font - final CellStyle cellStyle3 = CellStyle(workbook); - cellStyle3.name = 'Style1'; - cellStyle3.fontName = 'Comic Sans MS'; - cellStyle3.fontColor = '#839202'; - cellStyle3.fontSize = 11; - cellStyle3.bold = true; - cellStyle3.italic = true; - cellStyle3.underline = true; - workbook.styles.addStyle(cellStyle3); - final Range range2 = sheet.getRangeByName('A3'); - range2.text = 'Hello'; - range2.cellStyle = cellStyle3; - final Range range3 = sheet.getRangeByName('A4'); - range3.number = 1000; - range3.cellStyle = cellStyle3; - // alignment - final CellStyle cellStyle4 = CellStyle(workbook); - cellStyle4.name = 'Style1'; - cellStyle4.hAlign = HAlignType.center; - workbook.styles.addStyle(cellStyle4); - final Range range4 = sheet.getRangeByName('A5'); - range4.text = 'Hi'; - range4.cellStyle = cellStyle4; - final Range range5 = sheet.getRangeByName('A6'); - range5.number = 10; - range5.cellStyle = cellStyle4; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'CellStylesAsync.xlsx'); - workbook.dispose(); - }); - test('Excel tables Async', () async { - // Create a new Excel Document. - final Workbook workbook = Workbook(2); - - // Accessing sheet via index. - final Worksheet sheet = workbook.worksheets[0]; - final Worksheet sheet1 = workbook.worksheets[1]; - - // Load data - sheet.getRangeByName('A1').setText('Fruits'); - sheet.getRangeByName('A2').setText('banana'); - sheet.getRangeByName('A3').setText('Cherry'); - sheet.getRangeByName('A4').setText('Banana'); - - sheet.getRangeByName('B1').setText('CostA'); - sheet.getRangeByName('B2').setNumber(744.6); - sheet.getRangeByName('B3').setNumber(5079.6); - sheet.getRangeByName('B4').setNumber(1267.5); - - sheet.getRangeByName('C1').setText('CostB'); - sheet.getRangeByName('C2').setNumber(162.56); - sheet.getRangeByName('C3').setNumber(1249.2); - sheet.getRangeByName('C4').setNumber(1062.5); - - sheet.getRangeByName('J8').setText('Name'); - sheet.getRangeByName('J9').setText('Rahul'); - sheet.getRangeByName('J10').setText('Mark'); - sheet.getRangeByName('J11').setText('Levi'); - - sheet.getRangeByName('K8').setText('SubjectA'); - sheet.getRangeByName('K9').setNumber(80); - sheet.getRangeByName('K10').setNumber(90); - sheet.getRangeByName('K11').setNumber(92); - - sheet.getRangeByName('L8').setText('SubjectB'); - sheet.getRangeByName('L9').setNumber(76); - sheet.getRangeByName('L10').setNumber(71); - sheet.getRangeByName('L11').setNumber(89); - - sheet1.getRangeByName('F1').setText('Vegetables'); - sheet1.getRangeByName('F2').setText('Egg Plant'); - sheet1.getRangeByName('F3').setText('DrumStick'); - sheet1.getRangeByName('F4').setText('Tomato'); - - sheet1.getRangeByName('G1').setText('CostA1'); - sheet1.getRangeByName('G2').setNumber(744.6); - sheet1.getRangeByName('G3').setNumber(5079.6); - sheet1.getRangeByName('G4').setNumber(1267.5); - - sheet1.getRangeByName('H1').setText('CostB1'); - sheet1.getRangeByName('H2').setNumber(162.56); - sheet1.getRangeByName('H3').setNumber(1249.2); - sheet1.getRangeByName('H4').setNumber(1062.5); - - sheet1.getRangeByName('A6').setText('Product A'); - sheet1.getRangeByName('A7').setText('shirt'); - sheet1.getRangeByName('A8').setText('bags'); - sheet1.getRangeByName('A9').setText('Trousers'); - - sheet1.getRangeByName('B6').setText('Cost1'); - sheet1.getRangeByName('B7').setNumber(654); - sheet1.getRangeByName('B8').setNumber(745); - sheet1.getRangeByName('B9').setNumber(187); - - sheet1.getRangeByName('C6').setText('Cost2'); - sheet1.getRangeByName('C7').setNumber(967); - sheet1.getRangeByName('C8').setNumber(543); - sheet1.getRangeByName('C9').setNumber(864); - - /// Create table with the data in given range - final ExcelTable table = - sheet.tableCollection.create('Table1', sheet.getRangeByName('A1:C4')); - - final ExcelTable table1 = sheet1.tableCollection - .create('Table2', sheet1.getRangeByName('F1:H4')); - - final ExcelTable table2 = sheet.tableCollection - .create('Table3', sheet.getRangeByName('J8:L11')); - - final ExcelTable table3 = sheet1.tableCollection - .create('Table4', sheet1.getRangeByName('A6:C9')); - - /// Multiple Sheet with Multiple Table - /// Formatting table with a built-in style - table.builtInTableStyle = ExcelTableBuiltInStyle.tableStyleMedium15; - table1.builtInTableStyle = ExcelTableBuiltInStyle.tableStyleDark10; - table2.builtInTableStyle = ExcelTableBuiltInStyle.tableStyleDark5; - table3.builtInTableStyle = ExcelTableBuiltInStyle.tableStyleLight9; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'TablesAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Formula Async', () async { - final Workbook workbook = Workbook(1); - // Accessing sheet via index. - final Worksheet sheet = workbook.worksheets[0]; - - // set the value to the cell. - sheet.getRangeByName('A1').setText('Apple'); - sheet.getRangeByName('A2').setText('Grapes'); - sheet.getRangeByName('A3').setText('Banana'); - sheet.getRangeByName('A4').setText('Grapes'); - sheet.getRangeByName('A5').setText('Grapes'); - sheet.getRangeByName('A6').setText('Banana'); - sheet.getRangeByName('A7').setText('Apple'); - sheet.getRangeByName('A8').setText('Banana'); - sheet.getRangeByName('A9').setText('Apple'); - sheet.getRangeByName('A10').setText('Grapes'); - sheet.getRangeByName('B1').setText('red'); - sheet.getRangeByName('B2').setText('blue'); - sheet.getRangeByName('B3').setText('yellow'); - sheet.getRangeByName('B4').setText('blue1'); - sheet.getRangeByName('B5').setText('blue'); - sheet.getRangeByName('B6').setText('yellow'); - sheet.getRangeByName('B7').setText('red1'); - sheet.getRangeByName('B8').setText('yellow'); - sheet.getRangeByName('B9').setText('red1'); - sheet.getRangeByName('B10').setText('blue1'); - sheet.getRangeByName('C1').setNumber(58); - sheet.getRangeByName('C2').setNumber(1200); - sheet.getRangeByName('C3').setNumber(300); - sheet.getRangeByName('C4').setNumber(500); - sheet.getRangeByName('C5').setNumber(1000); - sheet.getRangeByName('C6').setNumber(600); - sheet.getRangeByName('C7').setNumber(200); - sheet.getRangeByName('C8').setNumber(339); - sheet.getRangeByName('C9').setNumber(400); - sheet.getRangeByName('C10').setNumber(100); - sheet.getRangeByName('D1').setNumber(2); - sheet.getRangeByName('D2').setNumber(3); - sheet.getRangeByName('D3').setNumber(4); - sheet.getRangeByName('D4').setNumber(2); - sheet.getRangeByName('D5').setNumber(1); - sheet.getRangeByName('D6').setNumber(4); - sheet.getRangeByName('D7').setNumber(3); - sheet.getRangeByName('D8').setNumber(2); - sheet.getRangeByName('D9').setNumber(1); - sheet.getRangeByName('D10').setNumber(2); - - // Formula calculation is enabled for the sheet. - sheet.enableSheetCalculations(); - - // Setting formula in the cell. - Range range = sheet.getRangeByName('D12'); - range.setFormula('=AVERAGEIFS(C1:C10,D1:D10,">2")'); - range.calculatedValue; - range = sheet.getRangeByName('D13'); - range.setFormula('=AVERAGEIFS(C1:C10,A1:A10,"Apple")'); - range.calculatedValue; - range = sheet.getRangeByName('D14'); - range.setFormula('=AVERAGEIFS(C1:C10,A1:A10,"Apple",B1:B10,"red1")'); - range.calculatedValue; - range = sheet.getRangeByName('D15'); - range.setFormula( - '=AVERAGEIFS(C1:C10,A1:A10,"Apple",B1:B10,"red",D1:D10,">=1")'); - range.calculatedValue; - range = sheet.getRangeByName('D16'); - range.setFormula( - '=AVERAGEIFS(C1:C10,A1:A10,"Grapes",D1:D10,"<=2",B1:B10,"blue")'); - range.calculatedValue; - range = sheet.getRangeByName('D17'); - range.setFormula('=AVERAGEIFS(C1:C10,C1:D10,">2")'); - range.calculatedValue; - range = sheet.getRangeByName('D18'); - range.setFormula('=AVERAGEIFS(C1:C10,D1:D10,"2")'); - range.calculatedValue; - final Worksheet sheet2 = workbook.worksheets.add(); - final Worksheet sheet3 = workbook.worksheets.add(); - final Worksheet sheet4 = workbook.worksheets.add(); - sheet2.getRangeByIndex(1, 1).number = 10; - sheet2.getRangeByIndex(1, 2).number = 20; - sheet2.enableSheetCalculations(); - - sheet3.getRangeByIndex(1, 1).formula = '=Sheet2!A1+Sheet2!B1'; - sheet3.getRangeByIndex(1, 2).formula = '=Sheet2!A1-Sheet2!B1'; - sheet3.getRangeByIndex(1, 3).formula = '=Sheet2!A1*Sheet2!B1'; - sheet3.getRangeByIndex(1, 4).formula = '=Sheet2!A1/Sheet2!B1'; - - final Range range1 = sheet4.getRangeByIndex(1, 1); - range1.formula = '=Sheet3!A1'; - final Range range2 = sheet4.getRangeByIndex(1, 2); - range2.formula = '=Sheet3!B1'; - final Range range3 = sheet4.getRangeByIndex(1, 3); - range3.formula = '=Sheet3!C1'; - final Range range4 = sheet4.getRangeByIndex(1, 4); - range4.formula = '=Sheet3!D1'; - final Range range5 = sheet4.getRangeByIndex(1, 5); - range5.formula = '=SUM(Sheet3!A1:A2)'; - - final Worksheet sheet5 = workbook.worksheets.add(); - sheet5.getRangeByIndex(1, 1).number = 10; - sheet5.getRangeByIndex(1, 2).number = 20; - sheet5.getRangeByIndex(1, 3).number = 12; - sheet5.getRangeByIndex(2, 1).number = 23; - sheet5.getRangeByIndex(2, 2).number = 43; - sheet5.getRangeByIndex(2, 3).number = 31; - sheet5.getRangeByIndex(3, 1).number = 25; - sheet5.getRangeByIndex(3, 2).number = 52; - sheet5.getRangeByIndex(3, 3).number = 23; - sheet5.getRangeByIndex(4, 1).number = 41; - sheet5.getRangeByIndex(4, 2).number = 75; - sheet5.getRangeByIndex(4, 3).number = 54; - - sheet5.enableSheetCalculations(); - - Range range6 = sheet5.getRangeByName('A6'); - range6.formula = '=B1-A1'; - expect('10.0', range6.calculatedValue); - range6 = sheet5.getRangeByName('A7'); - range6.formula = '=C1*B1'; - expect('240.0', range6.calculatedValue); - range6 = sheet5.getRangeByName('A8'); - range6.formula = '=B3/B2'; - expect('1.2093023255813953', range6.calculatedValue); - range6 = sheet5.getRangeByName('A9'); - range6.formula = '=B2>A1'; - expect('TRUE', range6.calculatedValue); - range6 = sheet5.getRangeByName('A10'); - range6.formula = '=B3 bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelFormulaAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Culture Async', () async { - final Workbook workbook = Workbook.withCulture('en-IN'); - final Worksheet sheet = workbook.worksheets[0]; - - final Range range1 = sheet.getRangeByIndex(2, 2); - range1.numberFormat = r'm/d/yyyy'; - range1.dateTime = DateTime(2021, 12, 22); - range1.displayText; - - final Range range2 = sheet.getRangeByIndex(4, 4); - range2.numberFormat = 'dd MMMM yyyy'; - range2.dateTime = DateTime(2022, 11, 21); - range2.displayText; - - final Worksheet sheet2 = workbook.worksheets.add(); - - final Range range3 = sheet2.getRangeByIndex(2, 2); - range3.numberFormat = 'h:mm'; - range3.dateTime = DateTime(2021, 12, 22, 22, 22, 22); - range3.displayText; - - final Range range4 = sheet2.getRangeByIndex(4, 4); - range4.numberFormat = 'h:mm:ss'; - range4.dateTime = DateTime(2022, 11, 21, 21, 21, 21); - range4.displayText; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelCultureAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Image Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - - final Picture picture1 = sheet.pictures.addBase64(1, 2, image24png); - picture1.rotation = 60; - - final Picture picture2 = sheet.pictures.addBase64(10, 10, image6png); - picture2.row = 20; - picture2.lastRow = 25; - picture2.column = 15; - picture2.lastColumn = 20; - - final Picture picture3 = sheet.pictures.addBase64(1, 15, image16jpg); - picture3.height = 300; - picture3.width = 500; - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelImageAsync.xlsx'); - workbook.dispose(); - }); - test('multiple sheets', () async { - final Workbook workbook = Workbook(2); - - final Worksheet sheet = workbook.worksheets[0]; - final Range range = sheet.getRangeByName('A1'); - sheet.hyperlinks - .add(range, HyperlinkType.url, 'http://www.syncfusion.com'); - final Range range1 = sheet.getRangeByIndex(10, 10); - sheet.hyperlinks.add(range1, HyperlinkType.url, 'http://www.google.com'); - sheet.hyperlinks.add(sheet.getRangeByName('J16'), HyperlinkType.url, - 'http://www.gmail.com'); - final Hyperlink link1 = sheet.hyperlinks.add(sheet.getRangeByName('G16'), - HyperlinkType.url, 'http://www.gmail.com'); - link1.screenTip = 'login here'; - - final Worksheet sheet1 = workbook.worksheets[1]; - sheet1.hyperlinks.add(sheet1.getRangeByIndex(2, 10), HyperlinkType.url, - 'http://www.fb.com'); - sheet1.hyperlinks.add(sheet1.getRangeByName('D16'), HyperlinkType.url, - 'http://www.yahoo.com'); - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelHyperlinkMultipleSheet.xlsx'); - }); - test('Excel AutoFit Async', () async { - final Workbook workbook = Workbook(); - final Worksheet sheet = workbook.worksheets[0]; - - // Range AutoFitColumn - Range range = sheet.getRangeByName('A1'); - range.setText('Test for AutoFit Column'); - range = sheet.getRangeByName('A2'); - range.setText( - 'WrapText WrapText WrapText WrapText WrapText WrapText WrapText'); - - sheet.getRangeByName('A1:A2').autoFitColumns(); - // Range AutoFitRow - Range range2 = sheet.getRangeByName('C1'); - range2.setText('Test for AutoFit Row'); - range2.cellStyle.fontSize = 15; - range2 = sheet.getRangeByName('C2'); - range2.setText( - 'WrapText WrapText WrapText WrapText WrapText WrapText WrapText'); - range2.cellStyle.wrapText = true; - - sheet.getRangeByName('C1:C2').autoFitRows(); - // Range Autofit - Range range3 = sheet.getRangeByName('F1'); - range3.setText('WrapText WrapText WrapText WrapText WrapText WrapText'); - range3.cellStyle.wrapText = true; - range3 = sheet.getRangeByName('F2'); - range3.setText('Test for AutoFit Text'); - range3.cellStyle.fontSize = 15; - - range3 = sheet.getRangeByName('G1'); - range3.setText('WrapText WrapText WrapText WrapText WrapText WrapText'); - range3 = sheet.getRangeByName('G2'); - range3.setText('Test for AutoFit Text'); - range3.cellStyle.fontSize = 15; - - sheet.getRangeByName('F1:G2').autoFit(); - - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelAutoFitAsync.xlsx'); - workbook.dispose(); - }); - test('Excel Image Hyperlink Async', () async { - final Workbook workbook = Workbook(1); - final Worksheet sheet = workbook.worksheets[0]; - Hyperlink link = sheet.hyperlinks.add(sheet.getRangeByIndex(3, 10), - HyperlinkType.url, 'http://www.fb.com', 'Fb login'); - link.textToDisplay = 'FaceBook'; - final Picture picture1 = sheet.pictures.addBase64(1, 1, image14png); - link = sheet.hyperlinks - .addImage(picture1, HyperlinkType.url, 'http://www.syncfusion.com'); - link = sheet.hyperlinks.add( - sheet.getRangeByIndex(1, 4), HyperlinkType.workbook, 'Sheet1!R5'); - - final Picture picture2 = sheet.pictures.addBase64(10, 10, image24png); - link = sheet.hyperlinks - .addImage(picture2, HyperlinkType.url, 'http://www.gmail.com'); - sheet.pictures.addBase64(30, 3, image10jpg); - sheet.pictures.addBase64(40, 15, image16jpg); - final Picture picture5 = sheet.pictures.addBase64(50, 25, image18jpg); - sheet.hyperlinks - .addImage(picture5, HyperlinkType.url, 'http://www.fb.com'); - final List bytes = await workbook.save(); - saveAsExcel(bytes, 'ExcelImageHyperlinkAsync.xlsx'); - workbook.dispose(); - }); - }); - group('Sample Browser Samples', () { - // Create styles for worksheet - List