diff --git a/analysis_options.yaml b/analysis_options.yaml index 59e7227c..9e8020f0 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,9 @@ -include: lib/analysis_options.yaml \ No newline at end of file +include: package:syncfusion_flutter_core/analysis_options.yaml + +analyzer: + errors: + include_file_not_found: ignore + lines_longer_than_80_chars: ignore + invalid_dependency: ignore + avoid_as: ignore + unnecessary_null_comparison: false \ No newline at end of file diff --git a/assets/maps_brazil_boundary.json b/assets/maps_brazil_boundary.json new file mode 100644 index 00000000..7c973fd8 --- /dev/null +++ b/assets/maps_brazil_boundary.json @@ -0,0 +1,3 @@ +{"type":"FeatureCollection","features":[ +{"type":"Feature","id":"BRA","properties":{"name":"Brazil"},"geometry":{"type":"Polygon","coordinates":[[[-57.625133,-30.216295],[-56.2909,-28.852761],[-55.162286,-27.881915],[-54.490725,-27.474757],[-53.648735,-26.923473],[-53.628349,-26.124865],[-54.13005,-25.547639],[-54.625291,-25.739255],[-54.428946,-25.162185],[-54.293476,-24.5708],[-54.29296,-24.021014],[-54.652834,-23.839578],[-55.027902,-24.001274],[-55.400747,-23.956935],[-55.517639,-23.571998],[-55.610683,-22.655619],[-55.797958,-22.35693],[-56.473317,-22.0863],[-56.88151,-22.282154],[-57.937156,-22.090176],[-57.870674,-20.732688],[-58.166392,-20.176701],[-57.853802,-19.969995],[-57.949997,-19.400004],[-57.676009,-18.96184],[-57.498371,-18.174188],[-57.734558,-17.552468],[-58.280804,-17.27171],[-58.388058,-16.877109],[-58.24122,-16.299573],[-60.15839,-16.258284],[-60.542966,-15.09391],[-60.251149,-15.077219],[-60.264326,-14.645979],[-60.459198,-14.354007],[-60.503304,-13.775955],[-61.084121,-13.479384],[-61.713204,-13.489202],[-62.127081,-13.198781],[-62.80306,-13.000653],[-63.196499,-12.627033],[-64.316353,-12.461978],[-65.402281,-11.56627],[-65.321899,-10.895872],[-65.444837,-10.511451],[-65.338435,-9.761988],[-66.646908,-9.931331],[-67.173801,-10.306812],[-68.048192,-10.712059],[-68.271254,-11.014521],[-68.786158,-11.03638],[-69.529678,-10.951734],[-70.093752,-11.123972],[-70.548686,-11.009147],[-70.481894,-9.490118],[-71.302412,-10.079436],[-72.184891,-10.053598],[-72.563033,-9.520194],[-73.226713,-9.462213],[-73.015383,-9.032833],[-73.571059,-8.424447],[-73.987235,-7.52383],[-73.723401,-7.340999],[-73.724487,-6.918595],[-73.120027,-6.629931],[-73.219711,-6.089189],[-72.964507,-5.741251],[-72.891928,-5.274561],[-71.748406,-4.593983],[-70.928843,-4.401591],[-70.794769,-4.251265],[-69.893635,-4.298187],[-69.444102,-1.556287],[-69.420486,-1.122619],[-69.577065,-0.549992],[-70.020656,-0.185156],[-70.015566,0.541414],[-69.452396,0.706159],[-69.252434,0.602651],[-69.218638,0.985677],[-69.804597,1.089081],[-69.816973,1.714805],[-67.868565,1.692455],[-67.53781,2.037163],[-67.259998,1.719999],[-67.065048,1.130112],[-66.876326,1.253361],[-66.325765,0.724452],[-65.548267,0.789254],[-65.354713,1.095282],[-64.611012,1.328731],[-64.199306,1.492855],[-64.083085,1.916369],[-63.368788,2.2009],[-63.422867,2.411068],[-64.269999,2.497006],[-64.408828,3.126786],[-64.368494,3.79721],[-64.816064,4.056445],[-64.628659,4.148481],[-63.888343,4.02053],[-63.093198,3.770571],[-62.804533,4.006965],[-62.08543,4.162124],[-60.966893,4.536468],[-60.601179,4.918098],[-60.733574,5.200277],[-60.213683,5.244486],[-59.980959,5.014061],[-60.111002,4.574967],[-59.767406,4.423503],[-59.53804,3.958803],[-59.815413,3.606499],[-59.974525,2.755233],[-59.718546,2.24963],[-59.646044,1.786894],[-59.030862,1.317698],[-58.540013,1.268088],[-58.429477,1.463942],[-58.11345,1.507195],[-57.660971,1.682585],[-57.335823,1.948538],[-56.782704,1.863711],[-56.539386,1.899523],[-55.995698,1.817667],[-55.9056,2.021996],[-56.073342,2.220795],[-55.973322,2.510364],[-55.569755,2.421506],[-55.097587,2.523748],[-54.524754,2.311849],[-54.088063,2.105557],[-53.778521,2.376703],[-53.554839,2.334897],[-53.418465,2.053389],[-52.939657,2.124858],[-52.556425,2.504705],[-52.249338,3.241094],[-51.657797,4.156232],[-51.317146,4.203491],[-51.069771,3.650398],[-50.508875,1.901564],[-49.974076,1.736483],[-49.947101,1.04619],[-50.699251,0.222984],[-50.388211,-0.078445],[-48.620567,-0.235489],[-48.584497,-1.237805],[-47.824956,-0.581618],[-46.566584,-0.941028],[-44.905703,-1.55174],[-44.417619,-2.13775],[-44.581589,-2.691308],[-43.418791,-2.38311],[-41.472657,-2.912018],[-39.978665,-2.873054],[-38.500383,-3.700652],[-37.223252,-4.820946],[-36.452937,-5.109404],[-35.597796,-5.149504],[-35.235389,-5.464937],[-34.89603,-6.738193],[-34.729993,-7.343221],[-35.128212,-8.996401],[-35.636967,-9.649282],[-37.046519,-11.040721],[-37.683612,-12.171195],[-38.423877,-13.038119],[-38.673887,-13.057652],[-38.953276,-13.79337],[-38.882298,-15.667054],[-39.161092,-17.208407],[-39.267339,-17.867746],[-39.583521,-18.262296],[-39.760823,-19.599113],[-40.774741,-20.904512],[-40.944756,-21.937317],[-41.754164,-22.370676],[-41.988284,-22.97007],[-43.074704,-22.967693],[-44.647812,-23.351959],[-45.352136,-23.796842],[-46.472093,-24.088969],[-47.648972,-24.885199],[-48.495458,-25.877025],[-48.641005,-26.623698],[-48.474736,-27.175912],[-48.66152,-28.186135],[-48.888457,-28.674115],[-49.587329,-29.224469],[-50.696874,-30.984465],[-51.576226,-31.777698],[-52.256081,-32.24537],[-52.7121,-33.196578],[-53.373662,-33.768378],[-53.650544,-33.202004],[-53.209589,-32.727666],[-53.787952,-32.047243],[-54.572452,-31.494511],[-55.60151,-30.853879],[-55.973245,-30.883076],[-56.976026,-30.109686],[-57.625133,-30.216295]]]}} +]} diff --git a/assets/maps_france_boundary.json b/assets/maps_france_boundary.json new file mode 100644 index 00000000..c2a6d933 --- /dev/null +++ b/assets/maps_france_boundary.json @@ -0,0 +1,3 @@ +{"type":"FeatureCollection","features":[ +{"type":"Feature","id":"FRA","properties":{"name":"France"},"geometry":{"type":"MultiPolygon","coordinates":[[[[9.560016,42.152492],[9.229752,41.380007],[8.775723,41.583612],[8.544213,42.256517],[8.746009,42.628122],[9.390001,43.009985],[9.560016,42.152492]]],[[[3.588184,50.378992],[4.286023,49.907497],[4.799222,49.985373],[5.674052,49.529484],[5.897759,49.442667],[6.18632,49.463803],[6.65823,49.201958],[8.099279,49.017784],[7.593676,48.333019],[7.466759,47.620582],[7.192202,47.449766],[6.736571,47.541801],[6.768714,47.287708],[6.037389,46.725779],[6.022609,46.27299],[6.5001,46.429673],[6.843593,45.991147],[6.802355,45.70858],[7.096652,45.333099],[6.749955,45.028518],[7.007562,44.254767],[7.549596,44.127901],[7.435185,43.693845],[6.529245,43.128892],[4.556963,43.399651],[3.100411,43.075201],[2.985999,42.473015],[1.826793,42.343385],[0.701591,42.795734],[0.338047,42.579546],[-1.502771,43.034014],[-1.901351,43.422802],[-1.384225,44.02261],[-1.193798,46.014918],[-2.225724,47.064363],[-2.963276,47.570327],[-4.491555,47.954954],[-4.59235,48.68416],[-3.295814,48.901692],[-1.616511,48.644421],[-1.933494,49.776342],[-0.989469,49.347376],[1.338761,50.127173],[1.639001,50.946606],[2.513573,51.148506],[2.658422,50.796848],[3.123252,50.780363],[3.588184,50.378992]]]]}} +]} diff --git a/assets/maps_uk_boundary.json b/assets/maps_uk_boundary.json new file mode 100644 index 00000000..31d7a4b8 --- /dev/null +++ b/assets/maps_uk_boundary.json @@ -0,0 +1,3 @@ +{"type":"FeatureCollection","features":[ +{"type":"Feature","id":"GBR","properties":{"name":"United Kingdom"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-5.661949,54.554603],[-6.197885,53.867565],[-6.95373,54.073702],[-7.572168,54.059956],[-7.366031,54.595841],[-7.572168,55.131622],[-6.733847,55.17286],[-5.661949,54.554603]]],[[[-3.005005,58.635],[-4.073828,57.553025],[-3.055002,57.690019],[-1.959281,57.6848],[-2.219988,56.870017],[-3.119003,55.973793],[-2.085009,55.909998],[-2.005676,55.804903],[-1.114991,54.624986],[-0.430485,54.464376],[0.184981,53.325014],[0.469977,52.929999],[1.681531,52.73952],[1.559988,52.099998],[1.050562,51.806761],[1.449865,51.289428],[0.550334,50.765739],[-0.787517,50.774989],[-2.489998,50.500019],[-2.956274,50.69688],[-3.617448,50.228356],[-4.542508,50.341837],[-5.245023,49.96],[-5.776567,50.159678],[-4.30999,51.210001],[-3.414851,51.426009],[-3.422719,51.426848],[-4.984367,51.593466],[-5.267296,51.9914],[-4.222347,52.301356],[-4.770013,52.840005],[-4.579999,53.495004],[-3.093831,53.404547],[-3.09208,53.404441],[-2.945009,53.985],[-3.614701,54.600937],[-3.630005,54.615013],[-4.844169,54.790971],[-5.082527,55.061601],[-4.719112,55.508473],[-5.047981,55.783986],[-5.586398,55.311146],[-5.644999,56.275015],[-6.149981,56.78501],[-5.786825,57.818848],[-5.009999,58.630013],[-4.211495,58.550845],[-3.005005,58.635]]]]}} +]} diff --git a/assets/pdf/certificate.pfx b/assets/pdf/certificate.pfx new file mode 100644 index 00000000..940afae4 Binary files /dev/null and b/assets/pdf/certificate.pfx differ diff --git a/assets/pdf/digital_signature_template.pdf b/assets/pdf/digital_signature_template.pdf new file mode 100644 index 00000000..a240ad06 Binary files /dev/null and b/assets/pdf/digital_signature_template.pdf differ diff --git a/assets/pdf/form_template.pdf b/assets/pdf/form_template.pdf new file mode 100644 index 00000000..317a05bb Binary files /dev/null and b/assets/pdf/form_template.pdf differ diff --git a/images/Cavaliers.png b/images/Cavaliers.png new file mode 100644 index 00000000..85d3bdf1 Binary files /dev/null and b/images/Cavaliers.png differ diff --git a/images/apple.png b/images/apple.png new file mode 100644 index 00000000..b5d8c15e Binary files /dev/null and b/images/apple.png differ diff --git a/images/bmi_dark.png b/images/bmi_dark.png new file mode 100644 index 00000000..d5198a99 Binary files /dev/null and b/images/bmi_dark.png differ diff --git a/images/bmi_light.png b/images/bmi_light.png new file mode 100644 index 00000000..359fc9b3 Binary files /dev/null and b/images/bmi_light.png differ diff --git a/images/cloud.png b/images/cloud.png new file mode 100644 index 00000000..2d8e6549 Binary files /dev/null and b/images/cloud.png differ diff --git a/images/cloudy.png b/images/cloudy.png new file mode 100644 index 00000000..5e033713 Binary files /dev/null and b/images/cloudy.png differ diff --git a/images/code.png b/images/code.png deleted file mode 100644 index 685bd26b..00000000 Binary files a/images/code.png and /dev/null differ diff --git a/images/flutter_examples.png b/images/flutter_examples.png deleted file mode 100644 index 37ecf365..00000000 Binary files a/images/flutter_examples.png and /dev/null differ diff --git a/images/git_hub.png b/images/git_hub.png new file mode 100644 index 00000000..004b1a85 Binary files /dev/null and b/images/git_hub.png differ diff --git a/images/git_hub_dark.png b/images/git_hub_dark.png new file mode 100644 index 00000000..598888ae Binary files /dev/null and b/images/git_hub_dark.png differ diff --git a/images/git_hub_mobile.png b/images/git_hub_mobile.png new file mode 100644 index 00000000..e11a0ae4 Binary files /dev/null and b/images/git_hub_mobile.png differ diff --git a/images/linear_gauge.png b/images/linear_gauge.png new file mode 100644 index 00000000..694d6752 Binary files /dev/null and b/images/linear_gauge.png differ diff --git a/images/maps_UK.png b/images/maps_UK.png new file mode 100644 index 00000000..7ea51e54 Binary files /dev/null and b/images/maps_UK.png differ diff --git a/images/maps_brazil.png b/images/maps_brazil.png new file mode 100644 index 00000000..af3f730e Binary files /dev/null and b/images/maps_brazil.png differ diff --git a/images/maps_default_polygon_dark.png b/images/maps_default_polygon_dark.png new file mode 100644 index 00000000..08d5feaa Binary files /dev/null and b/images/maps_default_polygon_dark.png differ diff --git a/images/maps_default_polygon_light.png b/images/maps_default_polygon_light.png new file mode 100644 index 00000000..e7095e9a Binary files /dev/null and b/images/maps_default_polygon_light.png differ diff --git a/images/maps_france.png b/images/maps_france.png new file mode 100644 index 00000000..9c96f0ff Binary files /dev/null and b/images/maps_france.png differ diff --git a/images/maps_inverted_polygon_dark.png b/images/maps_inverted_polygon_dark.png new file mode 100644 index 00000000..b0870ea6 Binary files /dev/null and b/images/maps_inverted_polygon_dark.png differ diff --git a/images/maps_inverted_polygon_light.png b/images/maps_inverted_polygon_light.png new file mode 100644 index 00000000..d4286e44 Binary files /dev/null and b/images/maps_inverted_polygon_light.png differ diff --git a/images/orange.png b/images/orange.png new file mode 100644 index 00000000..66d32caf Binary files /dev/null and b/images/orange.png differ diff --git a/images/other_fruits.png b/images/other_fruits.png new file mode 100644 index 00000000..98897e6a Binary files /dev/null and b/images/other_fruits.png differ diff --git a/images/partly_cloudy.png b/images/partly_cloudy.png new file mode 100644 index 00000000..260116b5 Binary files /dev/null and b/images/partly_cloudy.png differ diff --git a/images/pdf/signature.png b/images/pdf/signature.png new file mode 100644 index 00000000..b0c4d717 Binary files /dev/null and b/images/pdf/signature.png differ diff --git a/images/pears.png b/images/pears.png new file mode 100644 index 00000000..b13493fc Binary files /dev/null and b/images/pears.png differ diff --git a/images/person_walking.gif b/images/person_walking.gif new file mode 100644 index 00000000..c9b92106 Binary files /dev/null and b/images/person_walking.gif differ diff --git a/images/person_walking.png b/images/person_walking.png new file mode 100644 index 00000000..534e83ee Binary files /dev/null and b/images/person_walking.png differ diff --git a/images/pub_logo.png b/images/pub_logo.png new file mode 100644 index 00000000..48853bb7 Binary files /dev/null and b/images/pub_logo.png differ diff --git a/images/rain_cloudy.png b/images/rain_cloudy.png new file mode 100644 index 00000000..a38b1969 Binary files /dev/null and b/images/rain_cloudy.png differ diff --git a/images/rain_light.png b/images/rain_light.png new file mode 100644 index 00000000..47ba1a5b Binary files /dev/null and b/images/rain_light.png differ diff --git a/images/rainy.png b/images/rainy.png new file mode 100644 index 00000000..da1c7905 Binary files /dev/null and b/images/rainy.png differ diff --git a/images/rectangle_pointer.png b/images/rectangle_pointer.png new file mode 100644 index 00000000..6d8e6996 Binary files /dev/null and b/images/rectangle_pointer.png differ diff --git a/images/scroll_arrow.png b/images/scroll_arrow.png new file mode 100644 index 00000000..ca0731cb Binary files /dev/null and b/images/scroll_arrow.png differ diff --git a/images/sunny_image.png b/images/sunny_image.png new file mode 100644 index 00000000..05a83177 Binary files /dev/null and b/images/sunny_image.png differ diff --git a/images/temperature_indicator_dark.png b/images/temperature_indicator_dark.png new file mode 100644 index 00000000..9a0115f0 Binary files /dev/null and b/images/temperature_indicator_dark.png differ diff --git a/images/temperature_indicator_light.png b/images/temperature_indicator_light.png new file mode 100644 index 00000000..28d62b8c Binary files /dev/null and b/images/temperature_indicator_light.png differ diff --git a/images/thunderstorms.png b/images/thunderstorms.png new file mode 100644 index 00000000..a182ab29 Binary files /dev/null and b/images/thunderstorms.png differ diff --git a/images/treemap.png b/images/treemap.png new file mode 100644 index 00000000..a89bcd5c Binary files /dev/null and b/images/treemap.png differ diff --git a/images/treemap_medal.png b/images/treemap_medal.png new file mode 100644 index 00000000..9c4e2ff2 Binary files /dev/null and b/images/treemap_medal.png differ diff --git a/images/triangle_pointer.png b/images/triangle_pointer.png new file mode 100644 index 00000000..e44d4921 Binary files /dev/null and b/images/triangle_pointer.png differ diff --git a/images/vertical_range_slider.png b/images/vertical_range_slider.png new file mode 100644 index 00000000..f775669e Binary files /dev/null and b/images/vertical_range_slider.png differ diff --git a/images/vertical_slider.png b/images/vertical_slider.png new file mode 100644 index 00000000..c9d3b1f9 Binary files /dev/null and b/images/vertical_slider.png differ diff --git a/ios/Podfile b/ios/Podfile index aafaa991..8620baa8 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,6 +1,9 @@ # Uncomment this line to define a global platform for your project # platform :ios, '9.0' +use_frameworks! +use_modular_headers! + # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,64 +13,29 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - pods_ary = [] - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) { |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - pods_ary.push({:name => podname, :path => podpath}); - else - puts "Invalid plugin specification: #{line}" - end - } - return pods_ary + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - # Flutter Pods - generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') - if generated_xcode_build_settings.empty? - puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." - end - generated_xcode_build_settings.map { |p| - if p[:name] == 'FLUTTER_FRAMEWORK_DIR' - symlink = File.join('.symlinks', 'flutter') - File.symlink(File.dirname(p[:path]), symlink) - pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) - end - } +flutter_ios_podfile_setup - # Plugin Pods - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.map { |p| - symlink = File.join('.symlinks', 'plugins', p[:name]) - File.symlink(p[:path], symlink) - pod p[:name], :path => File.join(symlink, 'ios') - } +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/lib/analysis_options.yaml b/lib/analysis_options.yaml deleted file mode 100644 index 2abf2154..00000000 --- a/lib/analysis_options.yaml +++ /dev/null @@ -1,6 +0,0 @@ -include: syncfusion_flutter_core/analysis_options.yaml - -analyzer: - errors: - lines_longer_than_80_chars: ignore - include_file_not_found: ignore \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index a59d59e6..909aa406 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -// import 'package:syncfusion_flutter_core/core.dart'; import 'model/model.dart'; import 'sample_browser.dart'; diff --git a/lib/model/helper.dart b/lib/model/helper.dart index 09e0964b..099a4677 100644 --- a/lib/model/helper.dart +++ b/lib/model/helper.dart @@ -1,3 +1,6 @@ +/// dart imports +import 'dart:io' show Platform; + /// Package imports import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -7,7 +10,6 @@ import 'package:url_launcher/url_launcher.dart'; /// Local imports import '../widgets/bottom_sheet.dart'; -import '../widgets/flutter_backdrop.dart'; import 'mobile_view.dart'; import 'model.dart'; import 'sample_view.dart'; @@ -27,23 +29,25 @@ void onTapControlInMobile(BuildContext context, SampleModel model, void onTapControlInWeb(BuildContext context, SampleModel model, WidgetCategory category, int position) { category.selectedIndex = position; - final SubItem _subItem = category - .controlList[category.selectedIndex].subItems[0].type == - 'parent' - ? category.controlList[category.selectedIndex].subItems[0].subItems[0] - .subItems[0] - : category.controlList[category.selectedIndex].subItems[0].type == 'child' - ? category.controlList[category.selectedIndex].subItems[0].subItems[0] - : category.controlList[category.selectedIndex].subItems[0]; + final SubItem _subItem = + category.controlList![category.selectedIndex!].subItems[0].type == + 'parent' + ? category.controlList![category.selectedIndex!].subItems[0] + .subItems[0].subItems[0] + : category.controlList![category.selectedIndex!].subItems[0].type == + 'child' + ? category + .controlList![category.selectedIndex!].subItems[0].subItems[0] + : category.controlList![category.selectedIndex!].subItems[0]; - Navigator.pushNamed(context, _subItem.breadCrumbText); + Navigator.pushNamed(context, _subItem.breadCrumbText!); } /// On tap the expand button, get the fullview sample. void onTapExpandSample( BuildContext context, SubItem subItem, SampleModel model) { model.isCardView = false; - final Function _sampleWidget = model.sampleWidget[subItem.key]; + final Function _sampleWidget = model.sampleWidget[subItem.key]!; final SampleView _sampleView = _sampleWidget(GlobalKey()); Navigator.push( context, @@ -58,235 +62,166 @@ void onTapExpandSample( model.notifyListeners(); } -///_BackPanel widget contains title and description of the sample -class _BackPanel extends StatefulWidget { - const _BackPanel(this.sample); - final SubItem sample; - - @override - _BackPanelState createState() => _BackPanelState(sample); -} - -class _BackPanelState extends State<_BackPanel> { - _BackPanelState(this.sample); - final SubItem sample; - final GlobalKey _globalKey = GlobalKey(); - - @override - void initState() { - WidgetsBinding.instance.addPostFrameCallback(_afterLayout); - super.initState(); - } - - void _afterLayout(Duration duration) { - _getSizesAndPosition(); - } - - void _getSizesAndPosition() { - final RenderBox _renderBoxRed = - _globalKey.currentContext?.findRenderObject(); - final Size _size = _renderBoxRed?.size; - final Offset _position = _renderBoxRed?.localToGlobal(Offset.zero); - const double _appbarHeight = 60; - BackdropState.frontPanelHeight = _position == null - ? 0 - : (_position.dy + (_size.height - _appbarHeight) + 20); - } - - @override - Widget build(BuildContext context) { - final SampleModel _model = SampleModel.instance; - return Container( - color: _model.paletteColor, - child: Padding( - padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - sample.title, - textAlign: TextAlign.left, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 28.0, - color: Colors.white, - letterSpacing: 0.53), - ), - sample.description != null - ? Padding( - key: _globalKey, - padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), - child: Text( - sample.description, - style: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 15.0, - color: Colors.white, - letterSpacing: 0.3, - height: 1.5), - ), - ) - : Container(), - ], - ), - ), - ); - } -} - ///On expanding sample, full view sample layout renders class _FullViewSampleLayout extends StatelessWidget { const _FullViewSampleLayout({this.sample, this.sampleWidget}); - final SubItem sample; - final Widget sampleWidget; + final SubItem? sample; + final Widget? sampleWidget; @override Widget build(BuildContext context) { - final ValueNotifier frontPanelVisible = ValueNotifier(true); final SampleModel model = SampleModel.instance; final bool needsFloatingBotton = - (sample.sourceLink != null && sample.sourceLink != '') || - sample.needsPropertyPanel == true; + (sample!.sourceLink != null && sample!.sourceLink != '') || + sample!.needsPropertyPanel == true; final bool needPadding = - sample.codeLink != null && sample.codeLink.contains('/chart/'); + sample!.codeLink != null && sample!.codeLink!.contains('/chart/'); return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) => SafeArea( - child: sample == null - ? Container() - : Backdrop( - toggleFrontLayer: sample.description != null && - sample.description != '', - panelVisible: frontPanelVisible, - sampleListModel: model, - appBarActions: (sample.description != null && - sample.description != '') - ? [ - (sample.codeLink != null && sample.codeLink != '') - ? Padding( + child: sample == null + ? Container() + : Theme( + data: model.themeData, + child: Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: model.paletteColor, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(60.0), + child: AppBar( + title: Text(sample!.title!), + actions: (sample!.description != null && + sample!.description != '') + ? [ + (sample!.codeLink != null && + sample!.codeLink != '') + ? Padding( + padding: const EdgeInsets.fromLTRB( + 0, 0, 8, 0), + child: Container( + height: 37, + width: 37, + child: IconButton( + icon: Image.asset( + 'images/git_hub_mobile.png', + color: Colors.white), + onPressed: () { + launch(sample!.codeLink!); + }, + ), + ), + ) + : Container(), + Padding( padding: const EdgeInsets.fromLTRB( 0, 0, 10, 0), child: Container( height: 40, width: 40, child: IconButton( - icon: Image.asset('images/code.png', + icon: Icon(Icons.info_outline, color: Colors.white), onPressed: () { - launch(sample.codeLink); + showBottomInfo( + context, sample!.description!); }, ), ), - ) - : Container(), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 10, 0), - child: Container( - height: 40, - width: 40, - child: IconButton( - icon: Icon(Icons.info_outline, - color: Colors.white), - onPressed: () { - frontPanelVisible.value = - !frontPanelVisible.value; - }, - ), - ), - ), - ] - : (sample.codeLink != null && sample.codeLink != '') - ? ([ - Padding( - padding: - const EdgeInsets.fromLTRB(0, 0, 10, 0), - child: Container( - height: 40, - width: 40, - child: IconButton( - icon: Image.asset('images/code.png', - color: Colors.white), - onPressed: () { - launch(sample.codeLink); - }, - ), ), - ), - ]) - : null, - appBarTitle: AnimatedSwitcher( - duration: const Duration(milliseconds: 1000), - child: Text(sample.title.toString())), - backLayer: _BackPanel(sample), - frontLayer: Scaffold( - backgroundColor: model.cardThemeColor, - body: Padding( + ] + : (sample!.codeLink != null && + sample!.codeLink != '') + ? ([ + Padding( + padding: const EdgeInsets.fromLTRB( + 0, 0, 8, 0), + child: Container( + height: 37, + width: 37, + child: IconButton( + icon: Image.asset( + 'images/git_hub_mobile.png', + color: Colors.white), + onPressed: () { + launch(sample!.codeLink!); + }, + ), + ), + ), + ]) + : null, + elevation: 0.0, + backgroundColor: model.backgroundColor, + titleSpacing: NavigationToolbar.kMiddleSpacing, + )), + body: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(12), + bottom: Radius.circular(0)), + color: model.cardThemeColor), padding: needPadding ? EdgeInsets.fromLTRB( 5, 0, 5, needsFloatingBotton ? 57 : 0) : const EdgeInsets.all(0), - child: Container(child: sampleWidget), - ), - floatingActionButton: needsFloatingBotton - ? Stack(children: [ - (sample.sourceLink != null && - sample.sourceLink != '') - ? Align( - alignment: Alignment.bottomLeft, + child: Container(child: sampleWidget)), + floatingActionButton: needsFloatingBotton + ? Stack(children: [ + (sample!.sourceLink != null && + sample!.sourceLink != '') + ? Align( + alignment: Alignment.bottomLeft, + child: Container( + padding: EdgeInsets.fromLTRB( + 30, needPadding ? 50 : 0, 0, 0), child: Container( - padding: EdgeInsets.fromLTRB( - 30, needPadding ? 50 : 0, 0, 0), - child: Container( - height: 50, - width: 230, - child: InkWell( - onTap: () => - launch(sample.sourceLink), - child: Row( - children: [ - Text('Source: ', - style: TextStyle( - fontSize: 16, - color: - model.textColor)), - Text(sample.sourceText, - style: const TextStyle( - fontSize: 14, - color: Colors.blue)), - ], - ), + height: 50, + width: 230, + child: InkWell( + onTap: () => + launch(sample!.sourceLink!), + child: Row( + children: [ + Text('Source: ', + style: TextStyle( + fontSize: 16, + color: + model.textColor)), + Text(sample!.sourceText!, + style: const TextStyle( + fontSize: 14, + color: Colors.blue)), + ], ), ), ), - ) - : Container(), - sample.needsPropertyPanel != true - ? Container() - : Align( - alignment: Alignment.bottomRight, - child: FloatingActionButton( - heroTag: null, - onPressed: () { - final GlobalKey _sampleKey = - sampleWidget.key; - final SampleViewState _sampleState = - _sampleKey.currentState; - final Widget _settingsContent = - _sampleState - .buildSettings(context); - showBottomSheetSettingsPanel( - context, _settingsContent); - }, - child: const Icon(Icons.graphic_eq, - color: Colors.white), - backgroundColor: model.paletteColor, - ), ), - ]) - : null, - ), - color: model.cardThemeColor, - ), - )); + ) + : Container(), + sample!.needsPropertyPanel != true + ? Container() + : Align( + alignment: Alignment.bottomRight, + child: FloatingActionButton( + heroTag: null, + onPressed: () { + final GlobalKey _sampleKey = + sampleWidget!.key as GlobalKey; + final SampleViewState _sampleState = + _sampleKey.currentState + as SampleViewState; + final Widget _settingsContent = + _sampleState + .buildSettings(context)!; + showBottomSheetSettingsPanel( + context, _settingsContent); + }, + backgroundColor: model.paletteColor, + child: const Icon(Icons.graphic_eq, + color: Colors.white), + ), + ), + ]) + : null, + )))); } } @@ -510,8 +445,7 @@ Widget getLeftSideDrawer(SampleModel _model) { const Spacer(), Container( child: Icon(Icons.arrow_forward, - color: _model.backgroundColor ?? - Colors.blue), + color: _model.backgroundColor), ), ], ), @@ -560,8 +494,7 @@ Widget getLeftSideDrawer(SampleModel _model) { const Spacer(), Container( child: Icon(Icons.arrow_forward, - color: _model.backgroundColor ?? - Colors.blue), + color: _model.backgroundColor), ), ], ), @@ -610,8 +543,7 @@ Widget getLeftSideDrawer(SampleModel _model) { const Spacer(), Container( child: Icon(Icons.arrow_forward, - color: _model.backgroundColor ?? - Colors.blue), + color: _model.backgroundColor), ), ], ), @@ -644,7 +576,7 @@ Widget getLeftSideDrawer(SampleModel _model) { )), Align( alignment: Alignment.bottomCenter, - child: Text('Version 18.4.30', + child: Text('Version 19.1.0.54', style: TextStyle( color: _model.drawerTextIconColor, fontSize: 12, @@ -689,42 +621,42 @@ Widget getFooter(BuildContext context, SampleModel model) { Row( children: [ InkWell( - child: const Text('Documentation', - style: TextStyle(color: Colors.blue, fontSize: 12)), onTap: () => launch( 'https://help.syncfusion.com/flutter/introduction/overview'), + child: const Text('Documentation', + style: TextStyle(color: Colors.blue, fontSize: 12)), ), Text(' | ', style: TextStyle( fontSize: 12, color: model.textColor.withOpacity(0.7))), InkWell( - child: const Text('Forum', - style: TextStyle(color: Colors.blue, fontSize: 12)), onTap: () => launch('https://www.syncfusion.com/forums/flutter'), + child: const Text('Forum', + style: TextStyle(color: Colors.blue, fontSize: 12)), ), Text(' | ', style: TextStyle( fontSize: 12, color: model.textColor.withOpacity(0.7))), InkWell( - child: const Text('Blog', - style: TextStyle(color: Colors.blue, fontSize: 12)), onTap: () => launch('https://www.syncfusion.com/blogs/?s=flutter'), + child: const Text('Blog', + style: TextStyle(color: Colors.blue, fontSize: 12)), ), Text(' | ', style: TextStyle( fontSize: 12, color: model.textColor.withOpacity(0.7))), InkWell( + onTap: () => launch('https://www.syncfusion.com/kb/flutter'), child: const Text('Knowledge base', style: TextStyle(color: Colors.blue, fontSize: 12)), - onTap: () => launch('https://www.syncfusion.com/kb/flutter'), ) ], ), Container( padding: const EdgeInsets.only(top: 10), - child: Text('Copyright © 2001 - 2020 Syncfusion Inc.', + child: Text('Copyright © 2001 - 2021 Syncfusion Inc.', style: TextStyle( color: model.textColor.withOpacity(0.7), fontSize: 12, @@ -858,8 +790,11 @@ Widget showWebThemeSettings(SampleModel model) { Container( height: 44, padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), - child: RaisedButton( - color: model.paletteColor, + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.paletteColor), + ), onPressed: () => _applyThemeAndPaletteColor( model, context, _selectedValue), child: const Text('APPLY', @@ -880,26 +815,27 @@ Widget showWebThemeSettings(SampleModel model) { void _applyThemeAndPaletteColor( SampleModel model, BuildContext context, int selectedValue) { model.selectedThemeIndex = selectedValue; - model.backgroundColor = model.currentThemeData.brightness == Brightness.dark + model.backgroundColor = model.currentThemeData!.brightness == Brightness.dark ? model.currentPrimaryColor : model.currentPaletteColor; model.paletteColor = model.currentPaletteColor; - model.changeTheme(model.currentThemeData); + model.changeTheme(model.currentThemeData!); // ignore: invalid_use_of_protected_member model.notifyListeners(); Navigator.pop(context); } /// Adding the palette color in the theme setting panel. -List _addColorPalettes(SampleModel model, [StateSetter setState]) { +List _addColorPalettes(SampleModel model, [StateSetter? setState]) { final List _colorPaletteWidgets = []; - for (int i = 0; i < model.paletteColors.length; i++) { + for (int i = 0; i < model.paletteColors!.length; i++) { _colorPaletteWidgets.add(Material( color: model.bottomSheetBackgroundColor, child: Ink( decoration: BoxDecoration( color: Colors.transparent, - border: Border.all(color: model.paletteBorderColors[i], width: 2.0), + border: + Border.all(color: model.paletteBorderColors![i], width: 2.0), shape: BoxShape.circle, ), child: InkWell( @@ -907,7 +843,7 @@ List _addColorPalettes(SampleModel model, [StateSetter setState]) { child: Icon( Icons.brightness_1, size: 40.0, - color: model.paletteColors[i], + color: model.paletteColors![i], ), ), ))); @@ -916,16 +852,17 @@ List _addColorPalettes(SampleModel model, [StateSetter setState]) { } /// Changing the palete color of the application. -void _changeColorPalette(SampleModel model, int index, [StateSetter setState]) { - for (int j = 0; j < model.paletteBorderColors.length; j++) { - model.paletteBorderColors[j] = Colors.transparent; +void _changeColorPalette(SampleModel model, int index, + [StateSetter? setState]) { + for (int j = 0; j < model.paletteBorderColors!.length; j++) { + model.paletteBorderColors![j] = Colors.transparent; } - model.paletteBorderColors[index] = model.paletteColors[index]; - model.currentPaletteColor = model.paletteColors[index]; - model.currentPrimaryColor = model.darkPaletteColors[index]; + model.paletteBorderColors![index] = model.paletteColors![index]; + model.currentPaletteColor = model.paletteColors![index]; + model.currentPrimaryColor = model.darkPaletteColors![index]; - model.isWeb - ? setState(() { + model.isWebFullView + ? setState!(() { /// update the palette color changes }) : @@ -935,7 +872,8 @@ void _changeColorPalette(SampleModel model, int index, [StateSetter setState]) { /// Getting status of the control/subitems/sample. String getStatusTag(SubItem item) { - const bool _isWeb = kIsWeb; + final bool _isWeb = + kIsWeb || Platform.isWindows || Platform.isMacOS || Platform.isLinux; String status = ''; if (item.subItems == null) { status = (item.status == 'new' || item.status == 'New') @@ -946,28 +884,28 @@ String getStatusTag(SubItem item) { } else { int newCount = 0; int updateCount = 0; - for (int i = 0; i < item.subItems.length; i++) { - if (item.subItems[i].subItems == null) { - if (item.subItems[i].status == 'New' || - item.subItems[i].status == 'new') { + for (int i = 0; i < item.subItems!.length; i++) { + if (item.subItems![i].subItems == null) { + if (item.subItems![i].status == 'New' || + item.subItems![i].status == 'new') { newCount++; - } else if (item.subItems[i].status == 'Updated' || - item.subItems[i].status == 'updated') { + } else if (item.subItems![i].status == 'Updated' || + item.subItems![i].status == 'updated') { updateCount++; } } else { - for (int j = 0; j < item.subItems[i].subItems.length; j++) { - if (item.subItems[i].subItems[j].status == 'New' || - item.subItems[i].subItems[j].status == 'new') { + for (int j = 0; j < item.subItems![i].subItems.length; j++) { + if (item.subItems![i].subItems[j].status == 'New' || + item.subItems![i].subItems[j].status == 'new') { newCount++; - } else if (item.subItems[i].subItems[j].status == 'Updated' || - item.subItems[i].subItems[j].status == 'updated') { + } else if (item.subItems![i].subItems[j].status == 'Updated' || + item.subItems![i].subItems[j].status == 'updated') { updateCount++; } } } } - status = (newCount != 0 && newCount == item.subItems.length) + status = (newCount != 0 && newCount == item.subItems!.length) ? (_isWeb ? 'New' : 'N') : (newCount != 0 || updateCount != 0) ? (_isWeb ? 'Updated' : 'U') @@ -1141,8 +1079,11 @@ void showBottomSettingsPanel(SampleModel model, BuildContext context) { margin: const EdgeInsets.all(0), height: 50, width: double.infinity, - child: RaisedButton( - color: model.paletteColor, + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.paletteColor), + ), onPressed: () => _applyThemeAndPaletteColor( model, context, _selectedIndex), child: const Text('APPLY', @@ -1193,3 +1134,56 @@ void showBottomSheetSettingsPanel(BuildContext context, Widget propertyWidget) { ]), )); } + +///To show the sample description in the bottom sheet +void showBottomInfo(BuildContext context, String information) { + final SampleModel _model = SampleModel.instance; + if (information != null && information != '') { + showRoundedModalBottomSheet( + context: context, + color: _model.bottomSheetBackgroundColor, + builder: (BuildContext context) => Theme( + data: ThemeData( + brightness: _model.themeData.brightness, + primaryColor: _model.backgroundColor), + child: Container( + padding: const EdgeInsets.fromLTRB(15, 0, 0, 5), + child: Stack(children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Description', + style: TextStyle( + color: _model.textColor, + fontSize: 18, + letterSpacing: 0.34, + fontWeight: FontWeight.bold)), + IconButton( + icon: Icon( + Icons.close, + color: _model.textColor, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 45, 12, 15), + child: ListView(shrinkWrap: true, children: [ + Text( + information, + textAlign: TextAlign.justify, + style: TextStyle( + color: _model.textColor, + fontWeight: FontWeight.normal, + fontSize: 15.0, + letterSpacing: 0.2, + height: 1.2), + ) + ])) + ]), + ))); + } +} diff --git a/lib/model/mobile_view.dart b/lib/model/mobile_view.dart index f10b13bf..ecd69ac4 100644 --- a/lib/model/mobile_view.dart +++ b/lib/model/mobile_view.dart @@ -10,146 +10,207 @@ import 'sample_view.dart'; /// Renders the Mobile layout class LayoutPage extends StatefulWidget { /// Holds the _category, model of the current selected control - const LayoutPage({this.category, this.sampleModel, Key key}) + const LayoutPage({this.category, this.sampleModel, Key? key}) : super(key: key); /// Holds the selected control's _category information - final WidgetCategory category; + final WidgetCategory? category; /// Holds the sampleModel details - final SampleModel sampleModel; + final SampleModel? sampleModel; @override _LayoutPageState createState() => _LayoutPageState(); } /// State of mobile layout widget. class _LayoutPageState extends State { - SampleModel _model; - WidgetCategory _category; - StateSetter refreshSetState; + late SampleModel _model; + late WidgetCategory _category; + StateSetter? codeIconChangeSetState; + StateSetter? infoIconChangeSetState; + SubItem? currentSample; + bool isInitState = false; @override void initState() { - _model = widget.sampleModel; - _category = widget.category; - + _model = widget.sampleModel!; + _category = widget.category!; super.initState(); } int _primaryTabIndex = 0; int _secondaryTabIndex = 0; - bool _showCodeIcon = false; + bool _showIcon = false; @override Widget build(BuildContext context) { - _showCodeIcon = - _category.controlList[_category.selectedIndex].subItems[0].type == - 'sample' || - (_category.controlList[_category.selectedIndex].subItems[0].type != + _showIcon = _category + .controlList![_category.selectedIndex!].subItems[0].type == + 'sample' || + (_category.controlList![_category.selectedIndex!].subItems[0].type != + 'parent' && + _category.controlList![_category.selectedIndex!].subItems[0] + .displayType != + 'card'); + currentSample = _category + .controlList![_category.selectedIndex!].subItems[0].type == + 'sample' + ? _category.controlList![_category.selectedIndex!].subItems[0] + : (_category.controlList![_category.selectedIndex!].subItems[0].type != 'parent' && - _category.controlList[_category.selectedIndex].subItems[0] + _category.controlList![_category.selectedIndex!].subItems[0] .displayType != - 'card'); + 'card' && + _category.controlList![_category.selectedIndex!].subItems[0] + .subItems != + null) + ? _category + .controlList![_category.selectedIndex!].subItems[0].subItems[0] + : null; return Theme( data: ThemeData( brightness: _model.themeData.brightness, primaryColor: _model.backgroundColor), - child: StatefulBuilder( - builder: (BuildContext buildContext, StateSetter setState) { - refreshSetState = setState; - return SafeArea( - child: DefaultTabController( - length: _category - .controlList[_category.selectedIndex].subItems.length, - child: Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () => Navigator.maybePop(context, false), - ), - backgroundColor: _model.paletteColor, - bottom: ((_category.controlList[_category.selectedIndex] - .sampleList != - null && - _category.controlList[_category.selectedIndex] - .displayType == - 'card')) || - _category.controlList[_category.selectedIndex] - .subItems.length == - 1 - ? null - : TabBar( - onTap: (int index) { - if (index != _primaryTabIndex) { - _primaryTabIndex = index; - refreshSetState(() { - _showCodeIcon = _category - .controlList[ - _category.selectedIndex] + child: SafeArea( + child: DefaultTabController( + length: _category + .controlList![_category.selectedIndex!].subItems.length, + child: Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () => Navigator.maybePop(context, false), + ), + backgroundColor: _model.paletteColor, + bottom: ((_category.controlList![_category.selectedIndex!] + .sampleList != + null && + _category.controlList![_category.selectedIndex!] + .displayType == + 'card')) || + _category.controlList![_category.selectedIndex!] + .subItems.length == + 1 + ? null + : TabBar( + onTap: (int index) { + if (index != _primaryTabIndex) { + _primaryTabIndex = index; + _secondaryTabIndex = 0; + if (codeIconChangeSetState != null) { + codeIconChangeSetState!(() { + currentSample = _category.controlList![_category.selectedIndex!].subItems[index].type == 'sample' + ? _category + .controlList![ + _category.selectedIndex!] + .subItems[index] + : ((_category.controlList![_category.selectedIndex!].subItems[index].type != 'parent' && + _category + .controlList![_category + .selectedIndex!] + .subItems[index] + .displayType != + 'card' && + _category + .controlList![_category + .selectedIndex!] + .subItems[index] + .subItems + .length == + 1) + ? _category + .controlList![_category.selectedIndex!] + .subItems[index] + .subItems[0] + : _category.controlList![_category.selectedIndex!].subItems[index].subItems[0]); + + _showIcon = _category + .controlList![ + _category.selectedIndex!] .subItems[index] .type == 'sample' || (_category - .controlList[ - _category.selectedIndex] + .controlList![ + _category.selectedIndex!] .subItems[index] .type != 'parent' && _category - .controlList[ - _category.selectedIndex] + .controlList![ + _category.selectedIndex!] .subItems[index] .displayType != 'card'); + infoIconChangeSetState!(() {}); }); } - }, - indicator: const UnderlineTabIndicator( - borderSide: BorderSide( - width: 5.0, - color: Color.fromRGBO(252, 220, 0, 1)), - ), - isScrollable: true, - tabs: _getTabs( - _category.controlList[_category.selectedIndex] - .subItems, - 'parent'), + } + }, + indicator: const UnderlineTabIndicator( + borderSide: BorderSide( + width: 5.0, + color: Color.fromRGBO(252, 220, 0, 1)), ), - title: Text( - _category.controlList[_category.selectedIndex].title - .toString(), - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16.0, - color: Colors.white, - letterSpacing: 0.3)), - actions: ((_category.controlList[_category.selectedIndex] - .sampleList != - null && - _category.controlList[_category.selectedIndex] - .displayType != - 'card' && - _category - .controlList[_category.selectedIndex] - .sampleList[_primaryTabIndex] - .codeLink != - null && - _category - .controlList[_category.selectedIndex] - .sampleList[_primaryTabIndex] - .codeLink != - '') || - (_category.controlList[_category.selectedIndex] - .childList != - null && - _category - .controlList[_category.selectedIndex] - .childList[_primaryTabIndex] - .displayType != - 'card')) - ? [ - Visibility( - visible: _showCodeIcon, + isScrollable: true, + tabs: _getTabs( + _category.controlList![_category.selectedIndex!] + .subItems, + 'parent'), + ), + title: Text( + _category.controlList![_category.selectedIndex!].title + .toString(), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16.0, + color: Colors.white, + letterSpacing: 0.3)), + actions: ((_category.controlList![_category.selectedIndex!] + .sampleList != + null && + _category.controlList![_category.selectedIndex!] + .displayType != + 'card') || + (_category.controlList![_category.selectedIndex!] + .childList != + null && + _category + .controlList![_category.selectedIndex!] + .childList[_primaryTabIndex] + .displayType != + 'card')) + ? [ + StatefulBuilder(builder: (BuildContext buildContext, + StateSetter setState) { + codeIconChangeSetState = setState; + return Visibility( + visible: _showIcon && currentSample != null, + child: Padding( + padding: + const EdgeInsets.fromLTRB(0, 0, 8, 0), + child: Container( + height: 37, + width: 37, + child: IconButton( + icon: Image.asset( + 'images/git_hub_mobile.png', + color: Colors.white), + onPressed: () { + launch(currentSample!.codeLink!); + }, + ), + ), + )); + }), + StatefulBuilder(builder: (BuildContext buildContext, + StateSetter setState) { + infoIconChangeSetState = setState; + return Visibility( + visible: _showIcon && + currentSample != null && + currentSample!.description != null && + currentSample!.description != '', child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 10, 0), @@ -157,87 +218,49 @@ class _LayoutPageState extends State { height: 40, width: 40, child: IconButton( - icon: Image.asset('images/code.png', + icon: Icon(Icons.info_outline, color: Colors.white), onPressed: () { - launch(_category.controlList[_category.selectedIndex].sampleList == null - ? (_category.controlList[_category.selectedIndex].childList[_primaryTabIndex].subItems[_secondaryTabIndex].codeLink == null && - _category - .controlList[_category - .selectedIndex] - .childList[ - _primaryTabIndex] - .subItems[ - _secondaryTabIndex] - .subItems - .length == - 1 && - _category - .controlList[_category - .selectedIndex] - .childList[ - _primaryTabIndex] - .subItems[ - _secondaryTabIndex] - .displayType != - 'card' - ? _category - .controlList[ - _category.selectedIndex] - .childList[_primaryTabIndex] - .subItems[ - _secondaryTabIndex] - .subItems[0] - .codeLink - : _category - .controlList[ - _category.selectedIndex] - .childList[_primaryTabIndex] - .subItems[ - _secondaryTabIndex] - .codeLink) - : _category - .controlList[_category.selectedIndex] - .sampleList[_primaryTabIndex] - .codeLink); + showBottomInfo(context, + currentSample!.description!); }, ), ), - )), - ] - : null, - ), - body: TabBarView( - physics: const NeverScrollableScrollPhysics(), - children: (_category.controlList[_category.selectedIndex] - .sampleList != - null) || - _category.controlList[_category.selectedIndex] - .subItems.length == - 1 - ? _getSamples( - _model, - _category.controlList[_category.selectedIndex] - .sampleList, - _category.controlList[_category.selectedIndex] - .displayType) - : (_category.controlList[_category.selectedIndex] - .childList != - null && - _checkSubItemsType(_category - .controlList[_category.selectedIndex] - .subItems)) - ? _getChildTabViewChildren( - _model, - _category.controlList[_category.selectedIndex] - .childList) - : _getParentTabViewChildren( - _model, - _category.controlList[_category.selectedIndex] - .subItems))), - ), - ); - })); + )); + }) + ] + : null, + ), + body: TabBarView( + physics: const NeverScrollableScrollPhysics(), + children: (_category.controlList![_category.selectedIndex!] + .sampleList != + null) || + _category.controlList![_category.selectedIndex!] + .subItems.length == + 1 + ? _getSamples( + _model, + _category.controlList![_category.selectedIndex!] + .sampleList, + _category.controlList![_category.selectedIndex!] + .displayType) + : (_category.controlList![_category.selectedIndex!] + .childList != + null && + _checkSubItemsType(_category + .controlList![_category.selectedIndex!] + .subItems)) + ? _getChildTabViewChildren( + _model, + _category.controlList![_category.selectedIndex!] + .childList) + : _getParentTabViewChildren( + _model, + _category.controlList![_category.selectedIndex!] + .subItems))), + ), + )); } /// Returns true, if the list doesn't contain any child type. @@ -252,13 +275,13 @@ class _LayoutPageState extends State { /// Get the samples based on display type List _getSamples( - SampleModel model, List list, String displayType) => + SampleModel model, List list, String? displayType) => displayType == 'card' ? _getCardViewSamples(model, list) : _getFullViewSamples(model, list); /// Get tabs which length is equal to list length - List _getTabs(List list, [String tabView]) { + List _getTabs(List list, [String? tabView]) { final List _tabs = []; String _status; for (int i = 0; i < list.length; i++) { @@ -311,8 +334,8 @@ class _LayoutPageState extends State { _needsFloatingBotton = (_sampleDetail.sourceLink != null && _sampleDetail.sourceLink != '') || _sampleDetail.needsPropertyPanel == true; - final Function _sampleWidget = model.sampleWidget[list[j].key]; - final SampleView _sampleView = _sampleWidget(GlobalKey()); + final Function? _sampleWidget = model.sampleWidget[list[j].key]; + final SampleView _sampleView = _sampleWidget!(GlobalKey()); _tabs.add( Scaffold( backgroundColor: model.cardThemeColor, @@ -329,14 +352,14 @@ class _LayoutPageState extends State { height: 50, width: 230, child: InkWell( - onTap: () => launch(_sampleDetail.sourceLink), + onTap: () => launch(_sampleDetail.sourceLink!), child: Row( children: [ Text('Source: ', style: TextStyle( fontSize: 16, color: model.textColor)), - Text(_sampleDetail.sourceText, + Text(_sampleDetail.sourceText!, style: const TextStyle( fontSize: 14, color: Colors.blue)), ], @@ -353,17 +376,18 @@ class _LayoutPageState extends State { child: FloatingActionButton( heroTag: null, onPressed: () { - final GlobalKey _sampleKey = _sampleView.key; + final GlobalKey _sampleKey = + _sampleView.key as GlobalKey; final SampleViewState _sampleState = - _sampleKey.currentState; + _sampleKey.currentState as SampleViewState; final Widget _settingsContent = - _sampleState.buildSettings(context); + _sampleState.buildSettings(context)!; showBottomSheetSettingsPanel( context, _settingsContent); }, + backgroundColor: model.paletteColor, child: const Icon(Icons.graphic_eq, color: Colors.white), - backgroundColor: model.paletteColor, ), ), ]) @@ -385,8 +409,8 @@ class _LayoutPageState extends State { addAutomaticKeepAlives: true, itemCount: list.length, itemBuilder: (BuildContext context, int position) { - final String _status = list[position].status; - _sampleWidget = model.sampleWidget[list[position].key]; + final String? _status = list[position].status; + _sampleWidget = model.sampleWidget[list[position].key]!; _sampleView = _sampleWidget(GlobalKey()); return Container( color: model.themeData.brightness == Brightness.dark @@ -503,38 +527,46 @@ class _LayoutPageState extends State { List _getChildTabViewChildren(SampleModel model, List list) { final List _tabs = []; for (int i = 0; i < list.length; i++) { - if (list[i].subItems.isNotEmpty) { + if (list[i].subItems!.isNotEmpty) { _tabs.add(Container( alignment: Alignment.center, child: DefaultTabController( - length: list[i].subItems.length, + length: list[i].subItems!.length, child: Scaffold( appBar: list[i].displayType == 'card' || (list[i].displayType != 'card' && - list[i].subItems.length == 1) + list[i].subItems!.length == 1) ? null : PreferredSize( + preferredSize: const Size.fromHeight(46.1), child: AppBar( backgroundColor: const Color.fromRGBO(241, 241, 241, 1), bottom: TabBar( onTap: (int index) { - _secondaryTabIndex = index; + if (_secondaryTabIndex != index && + codeIconChangeSetState != null) { + codeIconChangeSetState!(() { + _secondaryTabIndex = index; + currentSample = list[i].subItems![index]; + infoIconChangeSetState!(() {}); + }); + } }, unselectedLabelColor: Colors.black, labelColor: Colors.blue, indicatorColor: Colors.transparent, indicatorWeight: 0.1, isScrollable: true, - tabs: _getTabs(list[i].subItems), + tabs: _getTabs(list[i].subItems as List), ), - ), - preferredSize: const Size.fromHeight(46.1), - ), + )), body: TabBarView( physics: const NeverScrollableScrollPhysics(), children: _getSamples( - model, list[i].subItems, list[i].displayType)))), + model, + list[i].subItems as List, + list[i].displayType)))), )); } } @@ -546,19 +578,20 @@ class _LayoutPageState extends State { SampleModel model, List list) { final List _tabs = []; for (int i = 0; i < list.length; i++) { - if (list[i].subItems.isNotEmpty) { + if (list[i].subItems!.isNotEmpty) { _tabs.add(Container( alignment: Alignment.center, child: DefaultTabController( - length: list[i].subItems.length, + length: list[i].subItems!.length, child: Scaffold( appBar: (list[i].type == 'child' && list[i].displayType == 'card') || (list[i].type == 'child' && list[i].displayType != 'card' && - list[i].subItems.length == 1) + list[i].subItems!.length == 1) ? null : PreferredSize( + preferredSize: const Size.fromHeight(46.1), child: AppBar( backgroundColor: const Color.fromRGBO(241, 241, 241, 1), @@ -566,15 +599,19 @@ class _LayoutPageState extends State { onTap: (int index) { if (_secondaryTabIndex != index) { _secondaryTabIndex = index; - refreshSetState(() { - _showCodeIcon = - (list[i].subItems[index].displayType != + codeIconChangeSetState!(() { + _showIcon = + (list[i].subItems![index].displayType != 'card' || list[i] - .subItems[index] + .subItems![index] .subItems .length == 1); + currentSample = _showIcon + ? list[i].subItems![index].subItems[0] + : null; + infoIconChangeSetState!(() {}); }); } }, @@ -583,18 +620,19 @@ class _LayoutPageState extends State { indicatorColor: Colors.transparent, indicatorWeight: 0.1, isScrollable: true, - tabs: _getTabs(list[i].subItems), + tabs: _getTabs(list[i].subItems as List), ), ), - preferredSize: const Size.fromHeight(46.1), ), body: TabBarView( physics: const NeverScrollableScrollPhysics(), children: list[i].type == 'child' ? _getSamples( - model, list[i].subItems, list[i].displayType) + model, + list[i].subItems as List, + list[i].displayType) : _getChildTabViewChildren( - model, list[i].subItems)))), + model, list[i].subItems as List)))), )); } } diff --git a/lib/model/model.dart b/lib/model/model.dart index dae9b976..de68d90e 100644 --- a/lib/model/model.dart +++ b/lib/model/model.dart @@ -1,10 +1,14 @@ /// Dart import import 'dart:convert'; +import 'dart:io' show Platform; /// Package imports +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/foundation.dart'; +import 'package:desktop_window/desktop_window.dart'; + +import '../model/web_view.dart'; /// Local import import '../sample_list.dart'; @@ -26,30 +30,38 @@ class WidgetCategory { } /// Name of the category - String categoryName; + String? categoryName; /// Control collection under the particular category - List controlList; + List? controlList; /// Sorting the categories based on this id in mobile. - final int mobileCategoryId; + final int? mobileCategoryId; /// Sorting the categories based on this id in web. - final int webCategoryId; + final int? webCategoryId; /// Specify false if the category need not to show in web /// (as Viewer - not supported in web). - final bool showInWeb; + final bool? showInWeb; /// Selected control in the controllist under the particular category - int selectedIndex = 0; + int? selectedIndex = 0; } /// Defines the control class. class Control { /// Contructor holds the tile, description, status etc., of the [Control] - Control(this.title, this.description, this.image, this.status, - this.displayType, this.subItems, this.controlId, this.showInWeb); + Control( + this.title, + this.description, + this.image, + this.status, + this.displayType, + this.subItems, + this.controlId, + this.showInWeb, + this.isBeta); /// Getting the control details from the json file factory Control.fromJson(Map json) { @@ -61,40 +73,44 @@ class Control { json['displayType'], json['subItems'], json['controlId'], - json['showInWeb']); + json['showInWeb'], + json['isBeta']); } /// Contains title of the control, display in the home page - final String title; + final String? title; /// Contains description of the control, display in the home page - final String description; + final String? description; /// Contains image relates to the control, display in the home page - final String image; + final String? image; - /// Conatins status of the control New/Updated/Preview - final String status; + /// Conatins status of the control New/Updated/Beta + final String? status; /// Display the controls based on this order. - final int controlId; + final int? controlId; /// Need to mention this when samples directly given without any sub category /// Mention as card/fullView, by default it will taken as "fullView". - final String displayType; + final String? displayType; /// Specify false if the control need not to show in web /// (as pdf viewer - not supported in web). - final bool showInWeb; + final bool? showInWeb; /// Contains the subItem list which comes under sample type - List sampleList; + List? sampleList; /// Contains the subItem list which comes under [child] type - List childList; + List? childList; /// Contains the sample details collection - List subItems; + List? subItems; + + /// To specify the control is beta or not in `https://pub.dev/publishers/syncfusion.com/packages` + final bool? isBeta; } /// Contains the detail of sample in different hierarchy levels @@ -140,64 +156,64 @@ class SubItem { /// by default it taken as "sample". /// Note: In all cases displayType is given as "fullView", /// additionally sample's tab will come. - final String type; + final String? type; /// Mention the samples layout. /// displayType given as card/fullView. /// by default it taken as "fullView". /// Note: Need to mention this when on display type is child. - final String displayType; + final String? displayType; /// Need to mention in all type. - final String title; + final String? title; /// Below values need to give when type is "sample". - final String key; + final String? key; /// Contains Github sample link - final String codeLink; + final String? codeLink; /// Contains the description of the sample /// to be displayed in the sample backpanel - final String description; + final String? description; /// Status of the sample, displays above the sample - final String status; + final String? status; /// Specify false if the sample need not to show in web /// (as sample with dash array). - final bool showInWeb; + final bool? showInWeb; /// SourceLink which will launch a url of the sample's source /// on tapping source text present under the sample. - final String sourceLink; + final String? sourceLink; /// Short form of the source link which will displays under the sample. - final String sourceText; + final String? sourceText; /// No need to give when type is "sample". - List subItems; + List? subItems; /// If current sample has property panel mention true. - final bool needsPropertyPanel; + final bool? needsPropertyPanel; /// Contains appropriate category name - String categoryName; + String? categoryName; ///Holds the URL text - String breadCrumbText; + String? breadCrumbText; ///Current parent subItem index - int parentIndex; + int? parentIndex; ///Current child subItem index - int childIndex; + int? childIndex; ///Current child subItem index - int sampleIndex; + int? sampleIndex; /// Holds appropriate control - Control control; + Control? control; } /// SampleModel class is the base of the Sample browser @@ -215,36 +231,36 @@ class SampleModel extends Listenable { searchControlItems.addAll(controlList); for (int index = 0; index < controlList.length; index++) { if (controlList[index].sampleList != null) { - for (int i = 0; i < controlList[index].sampleList.length; i++) { - searchSampleItems.add(controlList[index].sampleList[i]); + for (int i = 0; i < controlList[index].sampleList!.length; i++) { + searchSampleItems.add(controlList[index].sampleList![i]); } } else if (controlList[index].childList != null) { - for (int i = 0; i < controlList[index].childList.length; i++) { + for (int i = 0; i < controlList[index].childList!.length; i++) { for (int j = 0; - j < controlList[index].childList[i].subItems.length; + j < controlList[index].childList![i].subItems!.length; j++) { - if (controlList[index].childList[i].subItems[j].type != 'child') { + if (controlList[index].childList![i].subItems![j].type != 'child') { searchSampleItems - .add(controlList[index].childList[i].subItems[j]); + .add(controlList[index].childList![i].subItems![j]); } else { //ignore: prefer_foreach for (final SubItem sample - in controlList[index].childList[i].subItems[j].subItems) { + in controlList[index].childList![i].subItems![j].subItems) { searchSampleItems.add(sample); } } } } } else { - for (int i = 0; i < controlList[index].subItems.length; i++) { + for (int i = 0; i < controlList[index].subItems!.length; i++) { for (int j = 0; - j < controlList[index].subItems[i].subItems.length; + j < controlList[index].subItems![i].subItems.length; j++) { for (int k = 0; - k < controlList[index].subItems[i].subItems[j].subItems.length; + k < controlList[index].subItems![i].subItems[j].subItems.length; k++) { searchSampleItems - .add(controlList[index].subItems[i].subItems[j].subItems[k]); + .add(controlList[index].subItems![i].subItems[j].subItems[k]); } } } @@ -264,16 +280,22 @@ class SampleModel extends Listenable { static List _categoryList = []; /// Holds the category list - List categoryList; + late List categoryList; /// Holds the sorted control list - List controlList, searchControlItems; + late List controlList; + + /// Holds the searched control list + late List searchControlItems; ///List of all the samples - List sampleList; + late List sampleList; /// To handle search - List searchSampleItems, searchResults; + late List searchSampleItems; + + /// To handle search + late List searchResults; /// holds theme based current palette color Color backgroundColor = const Color.fromRGBO(0, 116, 227, 1); @@ -286,7 +308,7 @@ class SampleModel extends Listenable { Color currentPrimaryColor = const Color.fromRGBO(0, 116, 227, 1); /// holds the current theme data - ThemeData themeData; + late ThemeData themeData; /// Holds theme baased color of web outputcontainer Color textColor = const Color.fromRGBO(51, 51, 51, 1); @@ -304,10 +326,7 @@ class SampleModel extends Listenable { Color webBackgroundColor = const Color.fromRGBO(246, 246, 246, 1); /// Holds theme based color of icon - Color webIconColor = const Color.fromRGBO(55, 55, 55, 1); - - /// set [kISWeb] result - bool isWeb = false; + Color webIconColor = const Color.fromRGBO(0, 0, 0, 0.54); /// Holds theme based input container color Color webInputColor = const Color.fromRGBO(242, 242, 242, 1); @@ -321,30 +340,34 @@ class SampleModel extends Listenable { /// Holds the theme based divider color Color dividerColor = const Color.fromRGBO(204, 204, 204, 1); - /// Holds the old and current browser window's height and width - Size oldWindowSize, currentWindowSize; - static List _routes; + /// Holds the old browser window's height and width + Size? oldWindowSize; + + /// Holds the current browser window's height and width + late Size currentWindowSize; + + static List _routes = []; /// List of navigation routes text and appropriate subitem - List routes; + late List? routes; /// Holds the current visible sample, only for web - dynamic currentRenderSample; + late dynamic? currentRenderSample; /// Holds the current rendered sample's key, only for web - String currentSampleKey; + late String? currentSampleKey; /// Contains the light theme pallete colors - List paletteColors; + late List? paletteColors; /// Contains the pallete's border colors - List paletteBorderColors; + late List? paletteBorderColors; /// Contains dark theme theme palatte colors - List darkPaletteColors; + late List? darkPaletteColors; /// Holds current theme data - ThemeData currentThemeData; + ThemeData? currentThemeData; /// Holds current pallete color Color currentPaletteColor = const Color.fromRGBO(0, 116, 227, 1); @@ -358,22 +381,52 @@ class SampleModel extends Listenable { /// Holds the information of isMobileResolution or not /// To render the appbar and search bar based on it - bool isMobileResolution; + late bool isMobileResolution; /// Holds the current system theme - ThemeData systemTheme; + late ThemeData systemTheme; /// Editing controller which used in the search text field TextEditingController editingController = TextEditingController(); /// Key of the property panel widget - GlobalKey propertyPanelKey; + late GlobalKey propertyPanelKey; /// Holds the information of to be maximize or not bool needToMaximize = false; ///Storing state of current output container - dynamic outputContainerState; + late dynamic outputContainerState; + + ///Storing state of web output container + late SampleOutputContainerState webOutputContainerState; + + ///check whether application is running on web/linuxOS/windowsOS/macOS + bool isWebFullView = false; + + ///Check whether application is running on a mobile device + bool isMobile = false; + + ///Check whether application is running on the web browser + bool isWeb = false; + + ///Check whether application is running on the desktop + bool isDesktop = false; + + ///Check whether application is running on the Android mobile device + bool isAndroid = false; + + ///Check whether application is running on the Windows desktop OS + bool isWindows = false; + + ///Check whether application is running on the iOS mobile device + bool isIOS = false; + + ///Check whether application is running on the Linux desktop OS + bool isLinux = false; + + ///Check whether application is running on the macOS desktop + bool isMacOS = false; /// Switching between light, dark, system themes void changeTheme(ThemeData _themeData) { @@ -383,7 +436,7 @@ class SampleModel extends Listenable { { dividerColor = const Color.fromRGBO(61, 61, 61, 1); cardColor = const Color.fromRGBO(48, 48, 48, 1); - webIconColor = const Color.fromRGBO(230, 230, 230, 1); + webIconColor = const Color.fromRGBO(255, 255, 255, 0.65); webOutputContainerColor = const Color.fromRGBO(23, 23, 23, 1); webInputColor = const Color.fromRGBO(44, 44, 44, 1); webBackgroundColor = const Color.fromRGBO(33, 33, 33, 1); @@ -397,7 +450,7 @@ class SampleModel extends Listenable { { dividerColor = const Color.fromRGBO(204, 204, 204, 1); cardColor = Colors.white; - webIconColor = const Color.fromRGBO(55, 55, 55, 1); + webIconColor = const Color.fromRGBO(0, 0, 0, 0.54); webOutputContainerColor = Colors.white; webInputColor = const Color.fromRGBO(242, 242, 242, 1); webBackgroundColor = const Color.fromRGBO(246, 246, 246, 1); @@ -437,9 +490,14 @@ class SampleModel extends Listenable { /// Then store the details in [SampleModel._categoryList] /// and [SampleModel._controlList] Future updateControlItems() async { + if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) { + await DesktopWindow.setMinWindowSize(Size(775, 230)); + } + bool _isSample = false; bool _isChild = false; - const bool _isWeb = kIsWeb; + final bool _isWeb = + kIsWeb || Platform.isWindows || Platform.isMacOS || Platform.isLinux; final String _jsonText = await rootBundle.loadString('lib/sample_details.json'); List _firstLevelSubItems = []; @@ -450,40 +508,45 @@ Future updateControlItems() async { final List categoryList = json.decode(_jsonText); for (int index = 0; index < categoryList.length; index++) { SampleModel._categoryList.add(WidgetCategory.fromJson(categoryList[index])); - List controlList = []; - if (!_isWeb || SampleModel._categoryList[index].showInWeb != false) { + final List controlList = []; + if ((!_isWeb || SampleModel._categoryList[index].showInWeb != false) && + (SampleModel._categoryList[index].categoryName != 'Viewer' || + kIsWeb || + (!Platform.isWindows && !Platform.isMacOS && !Platform.isLinux))) { for (int i = 0; - i < SampleModel._categoryList[index].controlList.length; + i < SampleModel._categoryList[index].controlList!.length; i++) { controlList.add( - Control.fromJson(SampleModel._categoryList[index].controlList[i])); + Control.fromJson(SampleModel._categoryList[index].controlList![i])); if (!_isWeb || controlList[i].showInWeb != false) { - for (int j = 0; j < controlList[i].subItems.length; j++) { + for (int j = 0; j < controlList[i].subItems!.length; j++) { _firstLevelSubItems - .add(SubItem.fromJson(controlList[i].subItems[j])); + .add(SubItem.fromJson(controlList[i].subItems![j])); if (_firstLevelSubItems[j].type == 'parent') { - for (int k = 0; k < _firstLevelSubItems[j].subItems.length; k++) { + for (int k = 0; + k < _firstLevelSubItems[j].subItems!.length; + k++) { if (!_isWeb || - SubItem.fromJson(_firstLevelSubItems[j].subItems[k]) + SubItem.fromJson(_firstLevelSubItems[j].subItems![k]) .showInWeb != false) { _secondLevelSubItems.add( - SubItem.fromJson(_firstLevelSubItems[j].subItems[k])); + SubItem.fromJson(_firstLevelSubItems[j].subItems![k])); for (int l = 0; l < _secondLevelSubItems[_secondLevelSubItems.length - 1] - .subItems + .subItems! .length; l++) { if (!_isWeb || SubItem.fromJson(_secondLevelSubItems[ _secondLevelSubItems.length - 1] - .subItems[l]) + .subItems![l]) .showInWeb != false) { _thirdLevelSubItems.add(SubItem.fromJson( _secondLevelSubItems[_secondLevelSubItems.length - 1] - .subItems[l])); + .subItems![l])); } _thirdLevelSubItems[_thirdLevelSubItems.length - 1] .parentIndex = j; @@ -494,23 +557,30 @@ Future updateControlItems() async { _thirdLevelSubItems[_thirdLevelSubItems.length - 1] .control = controlList[i]; final String breadCrumbText = ('/' + - controlList[i].title + + controlList[i].title! + '/' + - _firstLevelSubItems[j].title + + _firstLevelSubItems[j].title! + '/' + _secondLevelSubItems[ _secondLevelSubItems.length - 1] - .title + - '/' + - _thirdLevelSubItems[_thirdLevelSubItems.length - 1] - .title) + .title! + + (_secondLevelSubItems[ + _secondLevelSubItems.length - 1] + .subItems! + .length == + 1 + ? '' + : ('/' + + _thirdLevelSubItems[ + _thirdLevelSubItems.length - 1] + .title!))) .replaceAll(' ', '-') .toLowerCase(); _thirdLevelSubItems[_thirdLevelSubItems.length - 1] .breadCrumbText = breadCrumbText; _thirdLevelSubItems[_thirdLevelSubItems.length - 1] .categoryName = - SampleModel._categoryList[index].categoryName; + SampleModel._categoryList[index].categoryName!; sampleRoutes.add(SampleRoute( routeName: breadCrumbText, subItem: _thirdLevelSubItems[ @@ -527,14 +597,14 @@ Future updateControlItems() async { if (!_isWeb || _firstLevelSubItems[j].showInWeb != false) { _isChild = true; for (int k = 0; - k < _firstLevelSubItems[j].subItems.length; + k < _firstLevelSubItems[j].subItems!.length; k++) { if (!_isWeb || - SubItem.fromJson(_firstLevelSubItems[j].subItems[k]) + SubItem.fromJson(_firstLevelSubItems[j].subItems![k]) .showInWeb != false) { _secondLevelSubItems.add( - SubItem.fromJson(_firstLevelSubItems[j].subItems[k])); + SubItem.fromJson(_firstLevelSubItems[j].subItems![k])); _secondLevelSubItems[_secondLevelSubItems.length - 1] .childIndex = j; _secondLevelSubItems[_secondLevelSubItems.length - 1] @@ -542,20 +612,20 @@ Future updateControlItems() async { _secondLevelSubItems[_secondLevelSubItems.length - 1] .control = controlList[i]; final String breadCrumbText = ('/' + - controlList[i].title + + controlList[i].title! + '/' + - _firstLevelSubItems[j].title + + _firstLevelSubItems[j].title! + '/' + _secondLevelSubItems[ _secondLevelSubItems.length - 1] - .title) + .title!) .replaceAll(' ', '-') .toLowerCase(); _secondLevelSubItems[_secondLevelSubItems.length - 1] .breadCrumbText = breadCrumbText; _secondLevelSubItems[_secondLevelSubItems.length - 1] .categoryName = - SampleModel._categoryList[index].categoryName; + SampleModel._categoryList[index].categoryName!; sampleRoutes.add(SampleRoute( routeName: breadCrumbText, subItem: _secondLevelSubItems[ @@ -566,7 +636,7 @@ Future updateControlItems() async { _secondLevelSubItems = []; } else { _firstLevelSubItems.removeAt(j); - controlList[i].subItems.removeAt(j); + controlList[i].subItems!.removeAt(j); j--; } } else { @@ -574,15 +644,15 @@ Future updateControlItems() async { _firstLevelSubItems[j].sampleIndex ??= j; if (!_isWeb || _firstLevelSubItems[j].showInWeb != false) { final String breadCrumbText = ('/' + - controlList[i].title + + controlList[i].title! + '/' + - _firstLevelSubItems[j].title) + _firstLevelSubItems[j].title!) .replaceAll(' ', '-') .toLowerCase(); _firstLevelSubItems[j].breadCrumbText = breadCrumbText; _firstLevelSubItems[j].control = controlList[i]; _firstLevelSubItems[j].categoryName = - SampleModel._categoryList[index].categoryName; + SampleModel._categoryList[index].categoryName!; sampleRoutes.add(SampleRoute( routeName: breadCrumbText, subItem: _firstLevelSubItems[j])); @@ -606,7 +676,7 @@ Future updateControlItems() async { _firstLevelSubItems = []; } else { controlList.removeAt(i); - SampleModel._categoryList[index].controlList.removeAt(i); + SampleModel._categoryList[index].controlList!.removeAt(i); i--; } } @@ -624,18 +694,18 @@ Future updateControlItems() async { /// Sorting the controls based on control id category wise. for (int i = 0; i < SampleModel._categoryList.length; i++) { - SampleModel._categoryList[i].controlList + SampleModel._categoryList[i].controlList! .sort((dynamic a, dynamic b) => a.controlId.compareTo(b.controlId)); } if (_isWeb) { /// Sorting categories based on [webCategoryId] SampleModel._categoryList.sort((WidgetCategory a, WidgetCategory b) => - a.webCategoryId.compareTo(b.webCategoryId)); + a.webCategoryId!.compareTo(b.webCategoryId!)); } else { /// Sorting categories based on [mobileCategoryId] SampleModel._categoryList.sort((WidgetCategory a, WidgetCategory b) => - a.mobileCategoryId.compareTo(b.mobileCategoryId)); + a.mobileCategoryId!.compareTo(b.mobileCategoryId!)); } } @@ -645,8 +715,8 @@ class SampleRoute { SampleRoute({this.routeName, this.subItem}); ///Holds the text which show in the URL - final String routeName; + final String? routeName; ///Holds the sample details - final SubItem subItem; + final SubItem? subItem; } diff --git a/lib/model/sample_view.dart b/lib/model/sample_view.dart index 1c90d237..0fb93d52 100644 --- a/lib/model/sample_view.dart +++ b/lib/model/sample_view.dart @@ -7,21 +7,21 @@ import 'model.dart'; /// Base class of the sample's stateful widget class abstract class SampleView extends StatefulWidget { /// base class constructor of sample's stateful widget class - const SampleView({Key key}) : super(key: key); + const SampleView({Key? key}) : super(key: key); } /// Base class of the sample's state class abstract class SampleViewState extends State { /// Holds the SampleModel information - SampleModel model; + late SampleModel model; /// Holds the information of current page is card view or not - bool isCardView; + late bool isCardView; @override void initState() { model = SampleModel.instance; - isCardView = model.isCardView && !model.isWeb; + isCardView = model.isCardView && !model.isWebFullView; super.initState(); } @@ -34,7 +34,7 @@ abstract class SampleViewState extends State { } /// Get the settings panel content. - Widget buildSettings(BuildContext context) { + Widget? buildSettings(BuildContext context) { return null; } } @@ -59,52 +59,62 @@ class ChartSampleData { this.volume}); /// Holds x value of the datapoint - final dynamic x; + final dynamic? x; /// Holds y value of the datapoint - final num y; + final num? y; /// Holds x value of the datapoint - final dynamic xValue; + final dynamic? xValue; /// Holds y value of the datapoint - final num yValue; + final num? yValue; /// Holds y value of the datapoint(for 2nd series) - final num secondSeriesYValue; + final num? secondSeriesYValue; /// Holds y value of the datapoint(for 3nd series) - final num thirdSeriesYValue; + final num? thirdSeriesYValue; /// Holds point color of the datapoint - final Color pointColor; + final Color? pointColor; /// Holds size of the datapoint - final num size; + final num? size; /// Holds datalabel/text value mapper of the datapoint - final String text; + final String? text; /// Holds open value of the datapoint - final num open; + final num? open; /// Holds close value of the datapoint - final num close; + final num? close; /// Holds low value of the datapoint - final num low; + final num? low; /// Holds high value of the datapoint - final num high; + final num? high; /// Holds open value of the datapoint - final num volume; + final num? volume; } +/// Chart Sales Data class SalesData { + /// Holds the datapoint values like x, y, etc., SalesData(this.x, this.y, [this.date, this.color]); + + /// X value of the data point final dynamic x; + + /// y value of the data point final dynamic y; - final Color color; - final DateTime date; + + /// color value of the data point + final Color? color; + + /// Date time value of the data point + final DateTime? date; } diff --git a/lib/model/web_view.dart b/lib/model/web_view.dart index b96be765..86e654bb 100644 --- a/lib/model/web_view.dart +++ b/lib/model/web_view.dart @@ -14,17 +14,17 @@ import 'sample_view.dart'; /// Renders web layout class WebLayoutPage extends StatefulWidget { /// Holds the selected control's category, etc., - const WebLayoutPage({this.sampleModel, this.category, Key key, this.subItem}) + const WebLayoutPage({this.sampleModel, this.category, Key? key, this.subItem}) : super(key: key); /// Holds [SampleModel] - final SampleModel sampleModel; + final SampleModel? sampleModel; /// Hold the selected control's category information - final WidgetCategory category; + final WidgetCategory? category; ///Holds the sample details - final SubItem subItem; + final SubItem? subItem; @override _WebLayoutPageState createState() => _WebLayoutPageState(); @@ -36,40 +36,40 @@ class _WebLayoutPageState extends State { GlobalKey sampleInputKey = GlobalKey(); GlobalKey sampleOutputKey = GlobalKey(); - _SampleInputContainer inputContainer; + late _SampleInputContainer inputContainer; - _SampleOutputContainer outputContainer; + late _SampleOutputContainer outputContainer; - String selectSample; + String? selectSample; - _Popup popup; + late _Popup popup; - SampleModel model; - WidgetCategory category; - SubItem sample; - List subItems; - String orginText; + late SampleModel model; + late WidgetCategory category; + late SubItem sample; + late List? subItems; + late String orginText; @override void initState() { - model = widget.sampleModel; - category = widget.category; - sample = widget.subItem; + model = widget.sampleModel!; + category = widget.category!; + sample = widget.subItem!; orginText = sample.parentIndex != null - ? sample.control.title + + ? sample.control!.title! + ' > ' + - sample.control.subItems[sample.parentIndex].title + + sample.control!.subItems![sample.parentIndex!].title + ' > ' + - sample.control.subItems[sample.parentIndex] + sample.control!.subItems![sample.parentIndex!] .subItems[sample.childIndex].title : sample.childIndex != null - ? sample.control.title + + ? sample.control!.title! + ' > ' + - widget.subItem.control.subItems[sample.childIndex].title + + widget.subItem!.control!.subItems![sample.childIndex!].title + ' > ' + - sample.title - : sample.control.title + ' > ' + sample.title; + sample.title! + : sample.control!.title! + ' > ' + sample.title!; subItems = sample.parentIndex != null - ? sample.control.subItems[sample.parentIndex] + ? sample.control!.subItems![sample.parentIndex!] .subItems[sample.childIndex].subItems : null; model.addListener(_handleChange); @@ -97,6 +97,9 @@ class _WebLayoutPageState extends State { Widget build(BuildContext context) { ///Checking the download button is currently hovered bool isHoveringDownloadButton = false; + + ///Checking the get package button is currently hovered + bool isHoveringPubDevButton = false; return Scaffold( key: scaffoldKey, drawer: (MediaQuery.of(context).size.width > 768) @@ -132,25 +135,27 @@ class _WebLayoutPageState extends State { icon: const Icon(Icons.menu, color: Colors.white), onPressed: () { if (outputContainer != null) { - final GlobalKey globalKey = outputContainer.key; - final _SampleOutputContainerState - _outputContainerState = globalKey.currentState; + final GlobalKey globalKey = + outputContainer.key as GlobalKey; + final SampleOutputContainerState + _outputContainerState = globalKey.currentState + as SampleOutputContainerState; if (_outputContainerState.outputScaffoldKey - .currentState.isEndDrawerOpen) { + .currentState!.isEndDrawerOpen) { Navigator.pop(context); } } if (popup != null) { - final GlobalKey globalkey = popup.key; + final GlobalKey globalkey = popup.key as GlobalKey; final _PopupState popupState = - globalkey.currentState; + globalkey.currentState as _PopupState; if (popupState.scaffoldKey.currentState != null && - popupState - .scaffoldKey.currentState.isEndDrawerOpen) { + popupState.scaffoldKey.currentState! + .isEndDrawerOpen) { Navigator.pop(context); } } - scaffoldKey.currentState.openDrawer(); + scaffoldKey.currentState!.openDrawer(); }, ), automaticallyImplyLeading: @@ -159,27 +164,12 @@ class _WebLayoutPageState extends State { backgroundColor: model.paletteColor, titleSpacing: MediaQuery.of(context).size.width <= 768 ? 0 : -30, - title: Row(children: [ - const Text('Flutter UI Widgets ', - style: TextStyle( - color: Colors.white, - fontSize: 18, - letterSpacing: 0.53, - fontFamily: 'Roboto-Medium')), - Container( - padding: const EdgeInsets.fromLTRB(3, 0, 3, 0), - decoration: const BoxDecoration( - shape: BoxShape.rectangle, - color: Color.fromRGBO(245, 188, 14, 1)), - child: const Text( - 'BETA', - style: TextStyle( - fontSize: 14, - letterSpacing: 0.26, - fontFamily: 'Roboto-Medium', - color: Colors.black), - )) - ]), + title: const Text('Flutter UI Widgets ', + style: TextStyle( + color: Colors.white, + fontSize: 18, + letterSpacing: 0.53, + fontFamily: 'Roboto-Medium')), actions: [ model.isMobileResolution ? Container(height: 0, width: 9) @@ -206,32 +196,81 @@ class _WebLayoutPageState extends State { child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { return MouseRegion( - child: InkWell( - hoverColor: Colors.white, - child: Padding( - padding: const EdgeInsets.fromLTRB( - 8, 9, 8, 9), - child: Text('DOWNLOAD NOW', - style: TextStyle( - color: isHoveringDownloadButton - ? model.paletteColor - : Colors.white, - fontSize: 12, - fontFamily: 'Roboto-Medium')), - ), - onTap: () { - launch( - 'https://www.syncfusion.com/downloads/flutter/confirm'); - }, + onHover: (PointerHoverEvent event) { + isHoveringDownloadButton = true; + setState(() {}); + }, + onExit: (PointerExitEvent event) { + isHoveringDownloadButton = false; + setState(() {}); + }, + child: InkWell( + hoverColor: Colors.white, + onTap: () { + launch( + 'https://www.syncfusion.com/downloads/flutter/confirm'); + }, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 9, 8, 9), + child: Text('DOWNLOAD NOW', + style: TextStyle( + color: isHoveringDownloadButton + ? model.paletteColor + : Colors.white, + fontSize: 12, + fontFamily: 'Roboto-Medium')), ), + ), + ); + }))), + + ///Get package from pub.dev option + model.isMobileResolution + ? Container() + : Container( + padding: EdgeInsets.only(left: 12), + alignment: Alignment.center, + child: Container( + width: 118, + height: 32, + decoration: BoxDecoration( + border: Border.all(color: Colors.white)), + child: StatefulBuilder(builder: + (BuildContext context, StateSetter setState) { + return MouseRegion( onHover: (PointerHoverEvent event) { - isHoveringDownloadButton = true; + isHoveringPubDevButton = true; setState(() {}); }, onExit: (PointerExitEvent event) { - isHoveringDownloadButton = false; + isHoveringPubDevButton = false; setState(() {}); - }); + }, + child: InkWell( + hoverColor: Colors.white, + onTap: () { + launch( + 'https://pub.dev/publishers/syncfusion.com/packages'); + }, + child: Padding( + padding: const EdgeInsets.fromLTRB( + 0, 7, 8, 7), + child: Row(children: [ + Image.asset('images/pub_logo.png', + fit: BoxFit.contain, + height: 33, + width: 33), + Text('Get Packages', + style: TextStyle( + color: isHoveringPubDevButton + ? model.paletteColor + : Colors.white, + fontSize: 12, + fontFamily: 'Roboto-Medium')) + ]), + ), + )); }))), Container( height: 60, @@ -240,24 +279,27 @@ class _WebLayoutPageState extends State { icon: const Icon(Icons.settings, color: Colors.white), onPressed: () { if (outputContainer != null) { - final GlobalKey globalKey = outputContainer.key; - final _SampleOutputContainerState - _outputContainerState = globalKey.currentState; - if (_outputContainerState - .outputScaffoldKey.currentState.isEndDrawerOpen) { + final GlobalKey globalKey = + outputContainer.key as GlobalKey; + final SampleOutputContainerState + _outputContainerState = globalKey.currentState + as SampleOutputContainerState; + if (_outputContainerState.outputScaffoldKey + .currentState!.isEndDrawerOpen) { Navigator.pop(context); } } if (popup != null) { - final GlobalKey globalkey = popup.key; - final _PopupState popupState = globalkey.currentState; + final GlobalKey globalkey = popup.key as GlobalKey; + final _PopupState popupState = + globalkey.currentState as _PopupState; if (popupState.scaffoldKey.currentState != null && popupState - .scaffoldKey.currentState.isEndDrawerOpen) { + .scaffoldKey.currentState!.isEndDrawerOpen) { Navigator.pop(context); } } - scaffoldKey.currentState.openEndDrawer(); + scaffoldKey.currentState!.openEndDrawer(); }, ), ), @@ -295,9 +337,9 @@ class _WebLayoutPageState extends State { ///Expansion key for expansion tile container class _ExpansionKey { _ExpansionKey({this.expansionIndex, this.isExpanded, this.globalKey}); - bool isExpanded; - int expansionIndex; - GlobalKey globalKey; + bool? isExpanded; + int? expansionIndex; + GlobalKey? globalKey; } /// Renders samples titles in list view or in expansion tile, @@ -307,13 +349,13 @@ class _SampleInputContainer extends StatefulWidget { {this.sampleModel, this.category, this.webLayoutPageState, this.key}) : super(key: key); - final SampleModel sampleModel; - final WidgetCategory category; + final SampleModel? sampleModel; + final WidgetCategory? category; @override - final Key key; + final Key? key; - final _WebLayoutPageState webLayoutPageState; + final _WebLayoutPageState? webLayoutPageState; @override State createState() { @@ -322,12 +364,12 @@ class _SampleInputContainer extends StatefulWidget { } class _SampleInputContainerState extends State<_SampleInputContainer> { - SampleModel sampleModel; - WidgetCategory category; + late SampleModel sampleModel; + late WidgetCategory category; - List<_ExpansionKey> expansionKey; + late List<_ExpansionKey> expansionKey; - bool initialRender; + late bool initialRender; /// Notify the framework void refresh() { @@ -349,8 +391,8 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { ///Get the widgets in expansionTile Widget _expandedChildren( SampleModel model, SubItem item, WidgetCategory category, int index) { - GlobalKey _currentGlobalKey; - _ExpansionKey _currentExpansionKey; + GlobalKey? _currentGlobalKey; + _ExpansionKey? _currentExpansionKey; if (initialRender) { _currentGlobalKey = GlobalKey(); _currentExpansionKey = _ExpansionKey( @@ -368,35 +410,35 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { } } } - return item.subItems != null && item.subItems.isNotEmpty + return item.subItems != null && item.subItems!.isNotEmpty ? _TileContainer( key: _currentGlobalKey, category: category, sampleModel: model, expansionKey: _currentExpansionKey, - webLayoutPageState: widget.webLayoutPageState, + webLayoutPageState: widget.webLayoutPageState!, item: item) : Material( color: model.webBackgroundColor, child: InkWell( hoverColor: Colors.grey.withOpacity(0.2), onTap: () { - final GlobalKey globalKey = - widget.webLayoutPageState.outputContainer.key; - final _SampleOutputContainerState _outputContainerState = - globalKey.currentState; + final GlobalKey globalKey = widget + .webLayoutPageState!.outputContainer.key as GlobalKey; + final SampleOutputContainerState _outputContainerState = + globalKey.currentState as SampleOutputContainerState; if (_outputContainerState - .outputScaffoldKey.currentState.isEndDrawerOpen || - widget.webLayoutPageState.scaffoldKey.currentState + .outputScaffoldKey.currentState!.isEndDrawerOpen || + widget.webLayoutPageState!.scaffoldKey.currentState! .isDrawerOpen) { Navigator.pop(context); } _outputContainerState.sample = item; _outputContainerState.needTabs = false; _outputContainerState.orginText = - widget.webLayoutPageState.sample.control.title + + widget.webLayoutPageState!.sample.control!.title! + ' > ' + - item.title; + item.title!; if (model.currentSampleKey == null || model.currentSampleKey != item.key) { _outputContainerState.refresh(); @@ -406,7 +448,7 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { color: Colors.transparent, padding: const EdgeInsets.fromLTRB(20, 10, 10, 10), alignment: Alignment.centerLeft, - child: Text(item.title, + child: Text(item.title!, style: TextStyle( color: model.textColor, fontSize: 13, @@ -415,18 +457,50 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { List _getSampleList(SampleModel model, WidgetCategory category) { final List _list = - widget.webLayoutPageState.sample.control.subItems; + widget.webLayoutPageState!.sample.control!.subItems as List; final List _children = []; for (int i = 0; i < _list.length; i++) { - final bool _isNeedSelect = widget.webLayoutPageState.selectSample == null - ? widget.webLayoutPageState.sample.breadCrumbText == + final bool _isNeedSelect = widget.webLayoutPageState!.selectSample == null + ? widget.webLayoutPageState!.sample.breadCrumbText == _list[i].breadCrumbText - : widget.webLayoutPageState.selectSample == _list[i].title; + : widget.webLayoutPageState!.selectSample == _list[i].title; _children.add(Material( color: model.webBackgroundColor, child: _list[i].type != 'parent' && _list[i].type != 'child' ? InkWell( hoverColor: Colors.grey.withOpacity(0.2), + onTap: () { + final _SampleInputContainerState + _sampleInputContainerState = widget + .webLayoutPageState! + .sampleInputKey + .currentState as _SampleInputContainerState; + final GlobalKey globalKey = widget + .webLayoutPageState!.outputContainer.key as GlobalKey; + final SampleOutputContainerState _outputContainerState = + globalKey.currentState as SampleOutputContainerState; + if (_outputContainerState + .outputScaffoldKey.currentState!.isEndDrawerOpen || + widget.webLayoutPageState!.scaffoldKey.currentState! + .isDrawerOpen) { + Navigator.pop(context); + } + _outputContainerState.sample = _list[i]; + _outputContainerState.needTabs = false; + _outputContainerState.orginText = + widget.webLayoutPageState!.sample.control!.title! + + ' > ' + + _list[i].title!; + widget.webLayoutPageState!.selectSample = _list[i].title!; + if (model.currentSampleKey == null || + (_list[i].key != null + ? model.currentSampleKey != _list[i].key + : model.currentSampleKey != + _list[i].subItems![0].key)) { + _sampleInputContainerState.refresh(); + _outputContainerState.refresh(); + } + }, child: Container( color: _isNeedSelect ? Colors.grey.withOpacity(0.2) @@ -447,7 +521,7 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { const EdgeInsets.fromLTRB(15, 10, 10, 10), alignment: Alignment.centerLeft, child: Text( - _list[i].title, + _list[i].title!, style: TextStyle( color: _isNeedSelect ? model.backgroundColor @@ -457,10 +531,10 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { ? Container( decoration: BoxDecoration( shape: BoxShape.rectangle, - color: _list[i].status.toLowerCase() == + color: _list[i].status!.toLowerCase() == 'new' ? const Color.fromRGBO(55, 153, 30, 1) - : (_list[i].status.toLowerCase() == + : (_list[i].status!.toLowerCase() == 'updated') ? const Color.fromRGBO( 246, 117, 0, 1) @@ -469,7 +543,7 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { Radius.circular(10))), padding: const EdgeInsets.fromLTRB(5, 2.7, 5, 2.7), - child: Text(_list[i].status, + child: Text(_list[i].status!, style: const TextStyle( color: Colors.white, fontSize: 10.5))) : Container(), @@ -477,36 +551,6 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { ? const Padding(padding: EdgeInsets.only(right: 5)) : Container(), ])), - onTap: () { - final _SampleInputContainerState - _sampleInputContainerState = - widget.webLayoutPageState.sampleInputKey.currentState; - final GlobalKey globalKey = - widget.webLayoutPageState.outputContainer.key; - final _SampleOutputContainerState _outputContainerState = - globalKey.currentState; - if (_outputContainerState - .outputScaffoldKey.currentState.isEndDrawerOpen || - widget.webLayoutPageState.scaffoldKey.currentState - .isDrawerOpen) { - Navigator.pop(context); - } - _outputContainerState.sample = _list[i]; - _outputContainerState.needTabs = false; - _outputContainerState.orginText = - widget.webLayoutPageState.sample.control.title + - ' > ' + - _list[i].title; - widget.webLayoutPageState.selectSample = _list[i].title; - if (model.currentSampleKey == null || - (_list[i].key != null - ? model.currentSampleKey != _list[i].key - : model.currentSampleKey != - _list[i].subItems[0].key)) { - _sampleInputContainerState.refresh(); - _outputContainerState.refresh(); - } - }, ) : _expandedChildren(model, _list[i], category, i))); } @@ -516,8 +560,8 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { @override Widget build(BuildContext context) { - sampleModel = widget.sampleModel; - category = widget.category; + sampleModel = widget.sampleModel!; + category = widget.category!; return Container( color: sampleModel.webBackgroundColor, height: MediaQuery.of(context).size.height - 45, @@ -528,6 +572,12 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { padding: const EdgeInsets.only(top: 5), height: 40, child: InkWell( + onTap: () { + Navigator.pop(context); + if (MediaQuery.of(context).size.width <= 768) { + Navigator.pop(context); + } + }, child: Row( children: [ const Padding( @@ -536,25 +586,22 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { Container( child: Icon(Icons.arrow_back, size: 20, color: sampleModel.backgroundColor)), - Container( - padding: const EdgeInsets.only(left: 12), - child: Text( - widget.webLayoutPageState.sample.control.title, - style: TextStyle( - color: sampleModel.backgroundColor, - fontSize: 16, - fontFamily: 'Roboto-Medium'), - )), - const Spacer(), + Flexible( + child: Container( + padding: const EdgeInsets.only(left: 12), + child: Text( + widget.webLayoutPageState!.sample.control!.title!, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: TextStyle( + color: sampleModel.backgroundColor, + fontSize: 16, + fontFamily: 'Roboto-Medium'), + ))), + Container(width: 2), const Padding(padding: EdgeInsets.only(top: 5)), ], ), - onTap: () { - Navigator.pop(context); - if (MediaQuery.of(context).size.width <= 768) { - Navigator.pop(context); - } - }, ), ), Expanded( @@ -578,42 +625,55 @@ class _SampleOutputContainer extends StatefulWidget { this.routes}) : super(key: key); - final SampleModel sampleModel; + final SampleModel? sampleModel; @override - final Key key; - final String orginText; + final Key? key; + final String? orginText; - final SubItem initialSample; - final WidgetCategory category; - final List initialSubItems; + final SubItem? initialSample; + final WidgetCategory? category; + final List? initialSubItems; - final _WebLayoutPageState webLayoutPageState; + final _WebLayoutPageState? webLayoutPageState; - final Map routes; + final Map? routes; @override State createState() { - return _SampleOutputContainerState(); + return SampleOutputContainerState(); } } -class _SampleOutputContainerState extends State<_SampleOutputContainer> { - SubItem sample; - List subItems; - bool needTabs; - String orginText; - int tabIndex; +/// state of sample output container +class SampleOutputContainerState extends State<_SampleOutputContainer> { + /// sample + late SubItem sample; + + /// List of samples + late List subItems; + + /// Flag for need Tabs + bool? needTabs; + + /// Origin text + late String orginText; + + /// index of tab + int? tabIndex; + + /// Key of scaffold state GlobalKey outputScaffoldKey = GlobalKey(); final GlobalKey _propertiesPanelKey = GlobalKey(); - _PropertiesPanel _propertiesPanel; - bool _initialRender; - GlobalKey _outputKey; + late _PropertiesPanel _propertiesPanel; + late bool _initialRender; + late GlobalKey _outputKey; + double _tabTextWidth = 0; @override void initState() { _initialRender = true; - orginText = widget.orginText; + orginText = widget.orginText!; super.initState(); } @@ -635,15 +695,27 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { @override Widget build(BuildContext context) { - final SampleModel _model = widget.sampleModel; + final SampleModel _model = widget.sampleModel!; + _model.webOutputContainerState = this; final double width = MediaQuery.of(context).size.width; if (_initialRender && widget.initialSubItems != null) { needTabs = true; - subItems = widget.initialSubItems; + subItems = widget.initialSubItems!; } - final SubItem _sample = _initialRender ? widget.initialSample : sample; + final SubItem _sample = (_initialRender ? widget.initialSample : sample)!; _propertiesPanel = _PropertiesPanel(sampleModel: _model, key: _propertiesPanelKey); + _tabTextWidth = 0; + final List? tabs = + needTabs == true && subItems.length > 1 ? _getTabs(subItems) : null; + final double _scrollbarWidth = width * + ((_model.isMobileResolution && width > 600) + ? 0.75 + : (width <= 500 + ? 0.585 + : width < 890 + ? 0.58 + : 0.65)); return Theme( data: ThemeData( brightness: _model.themeData.brightness, @@ -657,10 +729,10 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { Container( padding: const EdgeInsets.only(left: 10), alignment: Alignment.centerLeft, - + ///Space added for avoiding text hide issue of the ///string having `infinite` word - child: Text(_sample.title + ' ', + child: Text(_sample.title! + ' ', style: TextStyle( color: _model.textColor, letterSpacing: 0.39, @@ -671,7 +743,7 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { alignment: Alignment.centerLeft, child: Text( needTabs == true && subItems.length != 1 - ? orginText + ' > ' + _sample.title + ? orginText + ' > ' + _sample.title! : orginText, style: TextStyle( color: _model.textColor.withOpacity(0.65), @@ -685,9 +757,9 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { endDrawer: _propertiesPanel, body: needTabs == true ? DefaultTabController( - initialIndex: tabIndex ?? - widget.webLayoutPageState.sample - .sampleIndex, + initialIndex: (tabIndex ?? + widget.webLayoutPageState!.sample + .sampleIndex)!, key: UniqueKey(), length: subItems.length, child: Container( @@ -695,10 +767,10 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { color: _model.webOutputContainerColor, border: Border.all( color: - _model.themeData.brightness == + (_model.themeData.brightness == Brightness.light ? Colors.grey[300] - : Colors.transparent, + : Colors.transparent)!, width: 1), borderRadius: BorderRadius.circular(3), ), @@ -725,122 +797,199 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { .spaceBetween, children: [ Container( - width: width * - ((_model.isMobileResolution && - width > 600) - ? 0.75 - : (width <= 500 - ? 0.585 - : width < - 890 - ? 0.58 - : 0.65)), - child: - SingleChildScrollView( - key: PageStorageKey< - String>((subItems - .isNotEmpty - ? subItems[0] - .title - : '') + - 'tabscroll'), - scrollDirection: - Axis - .horizontal, - child: Material( - color: _model - .webInputColor, - child: InkWell( - hoverColor: _model.paletteColor.withOpacity(0.3), - child: subItems.length == 1 - ? Container() - : TabBar( - indicatorPadding: EdgeInsets.zero, - indicatorColor: _model.backgroundColor, - onTap: (int value) { - widget.sampleModel.needToMaximize = false; - final GlobalKey globalKey = widget.webLayoutPageState.outputContainer.key; - final _SampleOutputContainerState _outputContainerState = globalKey.currentState; - _outputContainerState.sample = subItems[value]; - _outputContainerState.needTabs = true; - _outputContainerState.subItems = subItems; - _outputContainerState.tabIndex = value; - if (_model.currentSampleKey == null || _model.currentSampleKey != _outputContainerState.sample.key) { - _outputContainerState.refresh(); - } - }, - labelColor: _model.backgroundColor, - unselectedLabelColor: _model.themeData.brightness == Brightness.dark ? Colors.white : const Color.fromRGBO(89, 89, 89, 1), - isScrollable: true, - tabs: _getTabs(subItems), - ))))), - Container( + width: _scrollbarWidth, + child: Stack( + children: [ + SingleChildScrollView( + key: PageStorageKey< + String>((subItems + .isNotEmpty + ? subItems[ + 0] + .title! + : '') + + 'tabscroll'), + scrollDirection: + Axis + .horizontal, + child: Material( + color: _model + .webInputColor, + child: InkWell( + hoverColor: _model.paletteColor.withOpacity(0.3), + child: subItems.length == 1 + ? Container() + : TabBar( + indicatorPadding: EdgeInsets.zero, + indicatorColor: _model.backgroundColor, + onTap: (int value) { + widget.sampleModel!.needToMaximize = false; + final GlobalKey globalKey = widget.webLayoutPageState!.outputContainer.key as GlobalKey; + final SampleOutputContainerState _outputContainerState = globalKey.currentState as SampleOutputContainerState; + _outputContainerState.sample = subItems[value]; + _outputContainerState.needTabs = true; + _outputContainerState.subItems = subItems; + _outputContainerState.tabIndex = value; + if (_model.currentSampleKey == null || _model.currentSampleKey != _outputContainerState.sample.key) { + _outputContainerState.refresh(); + } + }, + labelColor: _model.backgroundColor, + unselectedLabelColor: _model.themeData.brightness == Brightness.dark ? Colors.white : const Color.fromRGBO(89, 89, 89, 1), + isScrollable: true, + tabs: tabs!, + )))), + (_scrollbarWidth + + 10) < + _tabTextWidth + ? Align( + alignment: + Alignment + .centerRight, + child: + Container( + decoration: + BoxDecoration( + gradient: + LinearGradient( + colors: [ + _model + .webInputColor + .withOpacity(0.21), + _model + .webInputColor + .withOpacity(1.0) + ], + stops: [ + 0.0, + 0.7 + ], + )), + width: 55, + alignment: + Alignment + .centerRight, + )) + : SizedBox + .fromSize( + size: Size + .zero), + (_scrollbarWidth + + 10) < + _tabTextWidth + ? Align( + alignment: + Alignment + .centerRight, + child: + Container( + alignment: + Alignment + .centerRight, + child: Image.asset( + 'images/scroll_arrow.png', + color: _model.themeData.brightness == Brightness.dark + ? Color.fromRGBO( + 255, + 255, + 255, + 0.65) + : Color.fromRGBO( + 0, + 0, + 0, + 0.54), + fit: BoxFit + .contain, + height: + 18, + width: + 18), + )) + : SizedBox + .fromSize( + size: Size + .zero), + ], + ), + ), + Expanded( child: Row( - children: [ - const Padding( - padding: - EdgeInsets.only( - left: 15), + mainAxisAlignment: + MainAxisAlignment + .end, + children: [ + Flexible( + child: SizedBox( + height: 21, + width: 21, + child: InkWell( + onTap: () { + launch(_sample + .codeLink!); + }, + child: Image + .asset( + _model.themeData.brightness == + Brightness.dark + ? 'images/git_hub_dark.png' + : 'images/git_hub.png', + fit: BoxFit + .contain, + ))), ), - Container( - height: 24, - width: 24, + Padding( + padding: EdgeInsets + .only( + left: width < + 500 + ? 5 + : 10)), + Flexible( child: InkWell( - child: Icon( - Icons.code, - color: _model - .webIconColor), onTap: () { - launch(_sample - .codeLink); + performMaximize( + _model, + _sample); }, + child: Transform + .scale( + scale: 0.85, + child: Icon( + Icons + .open_in_full, + color: _model + .webIconColor), + ), ), ), - const Padding( - padding: - EdgeInsets.only( - left: 13), - ), - InkWell( - child: Container( - child: Transform.scale( - scale: 0.85, - child: Icon( - Icons - .open_in_full, - color: _model - .webIconColor))), - onTap: () { - performMaximize( - _model, - _sample); - }, - ), - const Padding( - padding: - EdgeInsets.only( - left: 15), - ), - _sample.needsPropertyPanel == - true - ? Container( - height: 24, - width: 24, - child: - InkWell( + Padding( + padding: EdgeInsets + .only( + left: width < + 500 + ? 5 + : 10)), + Flexible( + child: _sample + .needsPropertyPanel == + true + ? InkWell( + onTap: () { + outputScaffoldKey + .currentState! + .openEndDrawer(); + }, child: Icon( Icons .menu, color: _model .webIconColor), - onTap: () { - outputScaffoldKey - .currentState - .openEndDrawer(); - }, - ), - ) - : Container(), + ) + : SizedBox.fromSize( + size: Size + .zero), + ) ], ), ) @@ -860,10 +1009,10 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { decoration: BoxDecoration( color: _model.webOutputContainerColor, border: Border.all( - color: _model.themeData.brightness == + color: (_model.themeData.brightness == Brightness.light ? Colors.grey[300] - : Colors.transparent, + : Colors.transparent)!, width: 1), borderRadius: BorderRadius.circular(3), ), @@ -884,68 +1033,65 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { mainAxisAlignment: MainAxisAlignment.end, children: [ - Container( - child: Row( - children: [ - const Padding( - padding: EdgeInsets.only( - left: 15), - ), - Container( - height: 24, - width: 24, - child: InkWell( - child: Icon(Icons.code, - color: _model - .webIconColor), - onTap: () { - launch( - _sample.codeLink); - }, - ), - ), - const Padding( - padding: EdgeInsets.only( - left: 15), - ), - InkWell( - child: Container( - child: Transform.scale( - scale: 0.85, - child: Icon( - Icons - .open_in_full, - color: _model - .webIconColor))), + Flexible( + child: SizedBox( + height: 21, + width: 21, + child: InkWell( onTap: () { - performMaximize( - _model, _sample); + launch(_sample.codeLink!); }, + child: Image.asset( + _model.themeData + .brightness == + Brightness.dark + ? 'images/git_hub_dark.png' + : 'images/git_hub.png', + fit: BoxFit.contain)), + )), + Padding( + padding: EdgeInsets.only( + left: width < 500 + ? 5 + : 10)), + Flexible( + child: InkWell( + onTap: () { + performMaximize( + _model, _sample); + }, + child: Transform.scale( + scale: 0.85, + child: Icon( + Icons.open_in_full, + color: _model + .webIconColor), ), - const Padding( - padding: EdgeInsets.only( - left: 15), - ), - _sample.needsPropertyPanel == - true - ? Container( - height: 24, - width: 24, - child: InkWell( - child: Icon( - Icons.menu, - color: _model - .webIconColor), + ), + ), + Padding( + padding: EdgeInsets.only( + left: width < 500 + ? 5 + : 10)), + Flexible( + child: + _sample.needsPropertyPanel == + true + ? InkWell( onTap: () { outputScaffoldKey - .currentState + .currentState! .openEndDrawer(); }, - ), - ) - : Container(), - ], - )), + child: Icon( + Icons.menu, + color: _model + .webIconColor), + ) + : SizedBox.fromSize( + size: Size.zero), + ), ]), ), Expanded( @@ -964,7 +1110,7 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { subItem: _sample, sampleView: _model.sampleWidget[ - _sample.key], + _sample.key]!, sampleModel: _model), )), _sample.sourceLink != null && @@ -980,7 +1126,7 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { 15, 10, 0, - 15), + 13), height: 40, child: Row( children: < @@ -998,10 +1144,10 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { InkWell( onTap: () => launch(_sample - .sourceLink), + .sourceLink!), child: Text( _sample - .sourceText, + .sourceText!, style: const TextStyle( fontSize: 12, @@ -1021,7 +1167,7 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { ? Container( padding: const EdgeInsets.only(left: 10, top: 18), alignment: Alignment.centerLeft, - child: Text(_sample.description, + child: Text(_sample.description!, textAlign: TextAlign.justify, style: TextStyle( color: _model.textColor, @@ -1033,22 +1179,48 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { ); } + /// Method to maximize sample void performMaximize(SampleModel model, SubItem sample) { model.needToMaximize = true; - _PopupState state = widget.webLayoutPageState.popUpKey.currentState; + final _PopupState state = + widget.webLayoutPageState!.popUpKey.currentState as _PopupState; state._sampleDetails = sample; state._currentWidgetKey = model.currentRenderSample.key; - _OutputContainerState _outputContainerState = _outputKey.currentState; + final _OutputContainerState _outputContainerState = + _outputKey.currentState as _OutputContainerState; _outputContainerState.setState(() {}); state.refresh(true); } + Size _measureTextSize(String textValue, TextStyle textStyle) { + final TextPainter textPainter = TextPainter( + textAlign: TextAlign.center, + textDirection: TextDirection.ltr, + text: TextSpan(text: textValue, style: textStyle)); + textPainter.layout(); + return Size(textPainter.width, textPainter.height); + } + /// Get tabs which length is equal to list length List _getTabs(List list) { final List _tabs = []; + _tabTextWidth = 0; for (int i = 0; i < list.length; i++) { if (list.isNotEmpty) { final String _status = getStatusTag(list[i]); + _tabTextWidth += (_measureTextSize( + list[i].title.toString() + (_status != '' ? ' ' : ''), + TextStyle(letterSpacing: 0.5, fontFamily: 'Roboto-Medium')) + .width + + _measureTextSize( + _status == 'New' + ? 'N' + : _status == 'Updated' + ? 'U' + : '', + TextStyle(fontSize: 11, color: Colors.white)) + .width + + 32 /*labelPadding*/); _tabs.add(Tab( child: Row( children: [ @@ -1104,7 +1276,7 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { ? Align( alignment: Alignment.centerLeft, child: Container( - padding: const EdgeInsets.fromLTRB(15, 10, 0, 15), + padding: const EdgeInsets.fromLTRB(15, 10, 0, 13), height: 40, child: Row( children: [ @@ -1115,8 +1287,8 @@ class _SampleOutputContainerState extends State<_SampleOutputContainer> { fontSize: 12), ), InkWell( - onTap: () => launch(list[i].sourceLink), - child: Text(list[i].sourceText, + onTap: () => launch(list[i].sourceLink!), + child: Text(list[i].sourceText!, style: const TextStyle( fontSize: 12, color: Colors.blue)), ), @@ -1141,16 +1313,16 @@ class _OutputContainer extends StatefulWidget { this.sampleOutputContainerState}) : super(key: key); - final SampleModel sampleModel; + final SampleModel? sampleModel; @override - final Key key; + final Key? key; - final SubItem subItem; + final SubItem? subItem; - final Function sampleView; + final Function? sampleView; - final _SampleOutputContainerState sampleOutputContainerState; + final SampleOutputContainerState? sampleOutputContainerState; @override State createState() { @@ -1160,10 +1332,11 @@ class _OutputContainer extends StatefulWidget { class _OutputContainerState extends State<_OutputContainer> { _OutputContainerState(); - GlobalKey renderOutputKey; + late GlobalKey? renderOutputKey; - Widget renderWidget; + Widget? renderWidget; + @override void initState() { renderOutputKey = GlobalKey(); super.initState(); @@ -1171,42 +1344,43 @@ class _OutputContainerState extends State<_OutputContainer> { @override Widget build(BuildContext context) { - widget.sampleModel.outputContainerState = this; - widget.sampleOutputContainerState._outputKey = widget.key; - widget.sampleModel.oldWindowSize = widget.sampleModel.oldWindowSize == null - ? MediaQuery.of(context).size - : widget.sampleModel.currentWindowSize; - - widget.sampleModel.currentWindowSize = MediaQuery.of(context).size; - if (widget.sampleModel.oldWindowSize.width != - widget.sampleModel.currentWindowSize.width || - widget.sampleModel.oldWindowSize.height != - widget.sampleModel.currentWindowSize.height) { - widget.sampleModel.currentSampleKey = widget.subItem.key; - return widget.sampleModel.needToMaximize + widget.sampleModel!.outputContainerState = this; + widget.sampleOutputContainerState!._outputKey = widget.key as GlobalKey; + widget.sampleModel!.oldWindowSize = + widget.sampleModel!.oldWindowSize == null + ? MediaQuery.of(context).size + : widget.sampleModel!.currentWindowSize; + + widget.sampleModel!.currentWindowSize = MediaQuery.of(context).size; + if (widget.sampleModel!.oldWindowSize!.width != + widget.sampleModel!.currentWindowSize.width || + widget.sampleModel!.oldWindowSize!.height != + widget.sampleModel!.currentWindowSize.height) { + widget.sampleModel!.currentSampleKey = widget.subItem!.key!; + return widget.sampleModel!.needToMaximize ? Container() - : Container(child: widget.sampleModel.currentRenderSample); + : Container(child: widget.sampleModel!.currentRenderSample); } else { - widget.sampleModel.currentRenderSample = renderWidget != null - ? renderWidget - : widget.sampleView(GlobalKey()); + widget.sampleModel!.currentRenderSample = + renderWidget ?? widget.sampleView!(GlobalKey()); renderWidget = null; - widget.sampleModel.propertyPanelKey = - widget.sampleModel.currentRenderSample.key; - widget.sampleModel.currentSampleKey = widget.subItem.key; - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData( - brightness: widget.sampleModel.themeData.brightness, - primaryColor: widget.sampleModel.backgroundColor), - initialRoute: widget.subItem.breadCrumbText, - routes: { - widget.subItem.breadCrumbText: (BuildContext cotext) => Scaffold( - backgroundColor: widget.sampleModel.cardThemeColor, - body: widget.sampleModel.needToMaximize + widget.sampleModel!.propertyPanelKey = + widget.sampleModel!.currentRenderSample.key; + widget.sampleModel!.currentSampleKey = widget.subItem!.key; + return ClipRect( + child: MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData( + brightness: widget.sampleModel!.themeData.brightness, + primaryColor: widget.sampleModel!.backgroundColor), + initialRoute: widget.subItem!.breadCrumbText, + routes: { + widget.subItem!.breadCrumbText!: (BuildContext cotext) => Scaffold( + backgroundColor: widget.sampleModel!.cardThemeColor, + body: widget.sampleModel!.needToMaximize ? Container() - : widget.sampleModel.currentRenderSample) - }); + : widget.sampleModel!.currentRenderSample) + })); } } } @@ -1214,10 +1388,10 @@ class _OutputContainerState extends State<_OutputContainer> { /// Get the Proeprty panel widget in the drawer class _PropertiesPanel extends StatefulWidget { _PropertiesPanel({this.sampleModel, this.key}) : super(key: key); - final SampleModel sampleModel; + final SampleModel? sampleModel; @override - final Key key; + final Key? key; @override State createState() { @@ -1226,35 +1400,32 @@ class _PropertiesPanel extends StatefulWidget { } class _PropertiesPanelState extends State<_PropertiesPanel> { - GlobalKey _sampleKey; - - @override - void initState() { - super.initState(); - } + late GlobalKey? _sampleKey; @override Widget build(BuildContext context) { - final SampleModel model = widget.sampleModel; + final SampleModel model = widget.sampleModel!; _sampleKey = model.propertyPanelKey; - final SampleViewState _sampleViewState = _sampleKey.currentState; - final Widget _settingPanelContent = _sampleViewState.buildSettings(context); + final SampleViewState _sampleViewState = + _sampleKey!.currentState as SampleViewState; + final Widget _settingPanelContent = + _sampleViewState.buildSettings(context)!; return Theme( data: ThemeData( - brightness: widget.sampleModel.themeData.brightness, - primaryColor: widget.sampleModel.backgroundColor), + brightness: widget.sampleModel!.themeData.brightness, + primaryColor: widget.sampleModel!.backgroundColor), child: Drawer( elevation: 3, child: SizedBox( width: 280, child: Container( decoration: BoxDecoration( - color: widget.sampleModel.cardThemeColor, + color: widget.sampleModel!.cardThemeColor, border: Border.all( color: const Color.fromRGBO(0, 0, 0, 0.12), width: 2), ), - padding: const EdgeInsets.fromLTRB(10, 20, 0, 20), + padding: const EdgeInsets.fromLTRB(10, 10, 0, 20), child: Container( padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), child: ListView( @@ -1270,7 +1441,7 @@ class _PropertiesPanelState extends State<_PropertiesPanel> { ), IconButton( icon: Icon(Icons.close, - color: widget.sampleModel.webIconColor), + color: widget.sampleModel!.webIconColor), onPressed: () { Navigator.pop(context); }, @@ -1299,13 +1470,13 @@ class _TileContainer extends StatefulWidget { this.key}) : super(key: key); - final SampleModel sampleModel; + final SampleModel? sampleModel; @override - final Key key; - final SubItem item; - final WidgetCategory category; - final _WebLayoutPageState webLayoutPageState; - final _ExpansionKey expansionKey; + final Key? key; + final SubItem? item; + final WidgetCategory? category; + final _WebLayoutPageState? webLayoutPageState; + final _ExpansionKey? expansionKey; @override State createState() { @@ -1316,32 +1487,34 @@ class _TileContainer extends StatefulWidget { class _TileContainerState extends State<_TileContainer> { @override Widget build(BuildContext context) { - final SampleModel _model = widget.sampleModel; + final SampleModel _model = widget.sampleModel!; return CustomExpansionTile( headerBackgroundColor: _model.webBackgroundColor, onExpansionChanged: (bool value) { - final _SampleInputContainerState _sampleInputContainerState = - widget.webLayoutPageState.sampleInputKey.currentState; + final _SampleInputContainerState _sampleInputContainerState = widget + .webLayoutPageState! + .sampleInputKey + .currentState as _SampleInputContainerState; final List<_ExpansionKey> expansionKey = _sampleInputContainerState.expansionKey; for (int k = 0; k < expansionKey.length; k++) { if (expansionKey[k].expansionIndex == - widget.expansionKey.expansionIndex) { + widget.expansionKey!.expansionIndex) { expansionKey[k].isExpanded = value; break; } } }, initiallyExpanded: true, - title: Text(widget.item.title, + title: Text(widget.item!.title!, style: TextStyle( color: _model.textColor, fontSize: 13, letterSpacing: -0.19, fontFamily: 'Roboto-Medium')), - key: PageStorageKey(widget.item.title), + key: PageStorageKey(widget.item!.title!), children: _getNextLevelChildren( - _model, widget.item.subItems, widget.item.title), + _model, widget.item!.subItems as List, widget.item!.title!), ); } @@ -1349,15 +1522,15 @@ class _TileContainerState extends State<_TileContainer> { List _getNextLevelChildren( SampleModel model, List list, String text) { final List _nextLevelChildren = []; - final SubItem currenSample = widget.webLayoutPageState.sample; + final SubItem currenSample = widget.webLayoutPageState!.sample; if (list != null && list.isNotEmpty) { for (int i = 0; i < list.length; i++) { final String _status = getStatusTag(list[i]); bool _isNeedSelect = false; if (list[i].subItems != null) { - for (int j = 0; j < list[i].subItems.length; j++) { + for (int j = 0; j < list[i].subItems!.length; j++) { if (currenSample.breadCrumbText == - list[i].subItems[j].breadCrumbText) { + list[i].subItems![j].breadCrumbText) { _isNeedSelect = true; break; } else { @@ -1374,38 +1547,39 @@ class _TileContainerState extends State<_TileContainer> { hoverColor: Colors.grey.withOpacity(0.2), onTap: () { final _SampleInputContainerState - _sampleInputContainerState = - widget.webLayoutPageState.sampleInputKey.currentState; - final GlobalKey _globalKey = - widget.webLayoutPageState.outputContainer.key; - final _SampleOutputContainerState _outputContainerState = - _globalKey.currentState; - if (_outputContainerState - .outputScaffoldKey.currentState.isEndDrawerOpen || - widget.webLayoutPageState.scaffoldKey.currentState + _sampleInputContainerState = widget + .webLayoutPageState! + .sampleInputKey + .currentState as _SampleInputContainerState; + final GlobalKey _globalKey = widget + .webLayoutPageState!.outputContainer.key as GlobalKey; + final SampleOutputContainerState _outputContainerState = + _globalKey.currentState as SampleOutputContainerState; + if (_outputContainerState.outputScaffoldKey.currentState! + .isEndDrawerOpen || + widget.webLayoutPageState!.scaffoldKey.currentState! .isDrawerOpen) { Navigator.pop(context); } _outputContainerState.sample = list[i]; _outputContainerState.needTabs = false; _outputContainerState.orginText = - widget.webLayoutPageState.sample.control.title + + widget.webLayoutPageState!.sample.control!.title! + ' > ' + text + ' > ' + - list[i].title; + list[i].title!; - widget.webLayoutPageState.selectSample = widget - .webLayoutPageState.selectSample = list[i].title; - widget.webLayoutPageState.sample = + widget.webLayoutPageState!.selectSample = list[i].title!; + widget.webLayoutPageState!.sample = list[i].subItems != null - ? list[i].subItems[0] + ? list[i].subItems![0] : list[i]; if (model.currentSampleKey == null || (list[i].key != null ? model.currentSampleKey != list[i].key : model.currentSampleKey != - list[i].subItems[0].key)) { + list[i].subItems![0].key)) { _sampleInputContainerState.refresh(); _outputContainerState.refresh(); } @@ -1429,7 +1603,7 @@ class _TileContainerState extends State<_TileContainer> { alignment: Alignment.centerLeft, padding: const EdgeInsets.fromLTRB(20, 10, 10, 10), - child: Text(list[i].title, + child: Text(list[i].title!, style: TextStyle( fontSize: 13, fontFamily: 'Roboto-Regular', @@ -1461,6 +1635,53 @@ class _TileContainerState extends State<_TileContainer> { color: model.webBackgroundColor, child: InkWell( hoverColor: Colors.grey.withOpacity(0.2), + onTap: () { + final _SampleInputContainerState + _sampleInputContainerState = widget + .webLayoutPageState! + .sampleInputKey + .currentState as _SampleInputContainerState; + final GlobalKey _globalKey = widget + .webLayoutPageState!.outputContainer.key as GlobalKey; + final SampleOutputContainerState _outputContainerState = + _globalKey.currentState as SampleOutputContainerState; + if (list[i].subItems != null && + list[i].subItems!.isNotEmpty) { + _outputContainerState.subItems = + list[i].subItems as List; + _outputContainerState.sample = list[i].subItems![0]; + _outputContainerState.tabIndex = 0; + _outputContainerState.needTabs = true; + } else { + _outputContainerState.sample = list[i]; + _outputContainerState.needTabs = false; + } + if (_outputContainerState + .outputScaffoldKey.currentState!.isEndDrawerOpen || + widget.webLayoutPageState!.scaffoldKey.currentState! + .isDrawerOpen) { + Navigator.pop(context); + } + _outputContainerState.orginText = + widget.webLayoutPageState!.sample.control!.title! + + ' > ' + + text + + ' > ' + + list[i].title!; + + widget.webLayoutPageState!.selectSample = list[i].title!; + widget.webLayoutPageState!.sample = list[i].subItems != null + ? list[i].subItems![0] + : list[i]; + if (model.currentSampleKey == null || + (list[i].key != null + ? model.currentSampleKey != list[i].key + : model.currentSampleKey != + list[i].subItems![0].key)) { + _sampleInputContainerState.refresh(); + _outputContainerState.refresh(); + } + }, child: Container( color: _isNeedSelect ? Colors.grey.withOpacity(0.2) @@ -1481,7 +1702,7 @@ class _TileContainerState extends State<_TileContainer> { alignment: Alignment.centerLeft, padding: const EdgeInsets.only( left: 18, top: 7, bottom: 7), - child: Text(list[i].title, + child: Text(list[i].title!, style: TextStyle( fontSize: 13, fontFamily: 'Roboto-Regular', @@ -1507,50 +1728,6 @@ class _TileContainerState extends State<_TileContainer> { ? const Padding(padding: EdgeInsets.only(right: 5)) : Container(), ])), - onTap: () { - final _SampleInputContainerState - _sampleInputContainerState = - widget.webLayoutPageState.sampleInputKey.currentState; - final GlobalKey _globalKey = - widget.webLayoutPageState.outputContainer.key; - final _SampleOutputContainerState _outputContainerState = - _globalKey.currentState; - if (list[i].subItems != null && - list[i].subItems.isNotEmpty) { - _outputContainerState.subItems = list[i].subItems; - _outputContainerState.sample = list[i].subItems[0]; - _outputContainerState.tabIndex = 0; - _outputContainerState.needTabs = true; - } else { - _outputContainerState.sample = list[i]; - _outputContainerState.needTabs = false; - } - if (_outputContainerState - .outputScaffoldKey.currentState.isEndDrawerOpen || - widget.webLayoutPageState.scaffoldKey.currentState - .isDrawerOpen) { - Navigator.pop(context); - } - _outputContainerState.orginText = - widget.webLayoutPageState.sample.control.title + - ' > ' + - text + - ' > ' + - list[i].title; - - widget.webLayoutPageState.selectSample = list[i].title; - widget.webLayoutPageState.sample = list[i].subItems != null - ? list[i].subItems[0] - : list[i]; - if (model.currentSampleKey == null || - (list[i].key != null - ? model.currentSampleKey != list[i].key - : model.currentSampleKey != - list[i].subItems[0].key)) { - _sampleInputContainerState.refresh(); - _outputContainerState.refresh(); - } - }, ))); } } @@ -1561,24 +1738,20 @@ class _TileContainerState extends State<_TileContainer> { /// Showing the expanded sample in a pop-up widget class _Popup extends StatefulWidget { _Popup({this.key, this.show}) : super(key: key); - final Key key; - final bool show; @override - _PopupState createState() => _PopupState(show); + final Key? key; + final bool? show; + @override + _PopupState createState() => _PopupState(show!); } class _PopupState extends State<_Popup> { _PopupState(this.show); bool show; - SubItem _sampleDetails; + SubItem? _sampleDetails; - GlobalKey _currentWidgetKey; - - @override - void initState() { - super.initState(); - } + late GlobalKey? _currentWidgetKey; void refresh(popupShow) { setState(() { @@ -1593,10 +1766,10 @@ class _PopupState extends State<_Popup> { } GlobalKey scaffoldKey = GlobalKey(); - _PropertiesPanel _propertiesPanel; - GlobalKey _propertiesPanelKey = GlobalKey(); + late _PropertiesPanel? _propertiesPanel; + final GlobalKey _propertiesPanelKey = GlobalKey(); - SampleModel model; + SampleModel? model; @override Widget build(BuildContext context) { model = SampleModel.instance; @@ -1614,36 +1787,36 @@ class _PopupState extends State<_Popup> { child: _sampleDetails != null ? Theme( data: ThemeData( - brightness: model.themeData.brightness, - primaryColor: model.backgroundColor), + brightness: model!.themeData.brightness, + primaryColor: model!.backgroundColor), child: Scaffold( key: scaffoldKey, endDrawer: _propertiesPanel, appBar: PreferredSize( preferredSize: Size.fromHeight(40), child: AppBar( - title: Text(_sampleDetails.title, + title: Text(_sampleDetails!.title!, style: TextStyle( fontFamily: 'Roboto-Medium', fontSize: 16, - color: model.textColor)), + color: model!.textColor)), automaticallyImplyLeading: false, backgroundColor: - model.webBackgroundColor, + model!.webBackgroundColor, actions: [ - _sampleDetails.needsPropertyPanel == + _sampleDetails!.needsPropertyPanel == true ? Container( height: 40, width: 40, child: IconButton( icon: Icon(Icons.menu, - color: - model.webIconColor), + color: model! + .webIconColor), onPressed: () { - model.propertyPanelKey = - _currentWidgetKey; - scaffoldKey.currentState + model!.propertyPanelKey = + _currentWidgetKey!; + scaffoldKey.currentState! .openEndDrawer(); }, )) @@ -1653,12 +1826,12 @@ class _PopupState extends State<_Popup> { width: 40, child: IconButton( icon: Icon(Icons.close, - color: model.webIconColor), + color: model!.webIconColor), onPressed: () { - model.needToMaximize = false; - _OutputContainerState + model!.needToMaximize = false; + final _OutputContainerState _outputContainerState = - model.outputContainerState; + model!.outputContainerState; _outputContainerState .setState(() { _outputContainerState @@ -1672,7 +1845,7 @@ class _PopupState extends State<_Popup> { ), ) ])), - backgroundColor: model.themeData.brightness == + backgroundColor: model!.themeData.brightness == Brightness.dark ? const Color.fromRGBO(33, 33, 33, 1) : Colors.white, @@ -1680,27 +1853,3 @@ class _PopupState extends State<_Popup> { : Container())))); } } - -/// Holds current render sample -class _RenderOutput extends StatefulWidget { - _RenderOutput({this.renderWidget, this.key}) : super(key: key); - - @override - final Key key; - - final Widget renderWidget; - - @override - State createState() { - return _RenderOutputState(renderWidget); - } -} - -class _RenderOutputState extends State<_RenderOutput> { - _RenderOutputState(this.renderWidget); - Widget renderWidget; - @override - Widget build(BuildContext context) { - return renderWidget; - } -} diff --git a/lib/sample_browser.dart b/lib/sample_browser.dart index 7ffb3261..72b60d15 100644 --- a/lib/sample_browser.dart +++ b/lib/sample_browser.dart @@ -5,6 +5,7 @@ import 'dart:io' show Platform; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:url_launcher/url_launcher.dart'; /// local imports @@ -25,43 +26,49 @@ class SampleBrowser extends StatefulWidget { } class _SampleBrowserState extends State { - SampleModel _sampleListModel; + late SampleModel _sampleListModel; @override void initState() { _sampleListModel = SampleModel.instance; - _sampleListModel.isWeb = kIsWeb; + _initializeProperties(); super.initState(); } @override Widget build(BuildContext context) { final Map navigationRoutes = { - _sampleListModel.isWeb ? '/' : '/demos': (BuildContext context) => + _sampleListModel.isWebFullView ? '/' : '/demos': (BuildContext context) => HomePage() }; - for (int i = 0; i < _sampleListModel.routes.length; i++) { - final SampleRoute sampleRoute = _sampleListModel.routes[i]; - WidgetCategory category; + for (int i = 0; i < _sampleListModel.routes!.length; i++) { + final SampleRoute sampleRoute = _sampleListModel.routes![i]; + WidgetCategory? category; for (int j = 0; j < _sampleListModel.categoryList.length; j++) { - if (sampleRoute.subItem.categoryName == + if (sampleRoute.subItem!.categoryName == _sampleListModel.categoryList[j].categoryName) { category = _sampleListModel.categoryList[j]; break; } } - navigationRoutes[sampleRoute.routeName] = (BuildContext context) => + navigationRoutes[sampleRoute.routeName!] = (BuildContext context) => WebLayoutPage( sampleModel: _sampleListModel, category: category, subItem: sampleRoute.subItem); } - if (_sampleListModel.isWeb) { + if (_sampleListModel.isWebFullView) { _sampleListModel.currentThemeData = ThemeData.light(); _sampleListModel.paletteBorderColors = []; - _sampleListModel.changeTheme(_sampleListModel.currentThemeData); + _sampleListModel.changeTheme(_sampleListModel.currentThemeData!); } - return _sampleListModel.isWeb + + ///Avoiding page poping on escape key press + final Map shortcuts = + Map.of(WidgetsApp.defaultShortcuts) + ..remove(LogicalKeySet(LogicalKeyboardKey.escape)); + return _sampleListModel.isWebFullView ? MaterialApp( + shortcuts: shortcuts, initialRoute: '/', routes: navigationRoutes, debugShowCheckedModeBanner: false, @@ -84,10 +91,28 @@ class _SampleBrowserState extends State { (_sampleListModel.systemTheme.brightness != Brightness.dark ? ThemeData.light() : ThemeData.dark()); - _sampleListModel.changeTheme(_sampleListModel.currentThemeData); + _sampleListModel.changeTheme(_sampleListModel.currentThemeData!); return HomePage(); })); } + + void _initializeProperties() { + final SampleModel model = SampleModel.instance; + model.isWebFullView = + kIsWeb || Platform.isWindows || Platform.isMacOS || Platform.isLinux; + if (kIsWeb) { + model.isWeb = true; + } else { + model.isAndroid = Platform.isAndroid; + model.isIOS = Platform.isIOS; + model.isLinux = Platform.isLinux; + model.isWindows = Platform.isWindows; + model.isMacOS = Platform.isMacOS; + model.isDesktop = + Platform.isLinux || Platform.isMacOS || Platform.isWindows; + model.isMobile = Platform.isAndroid || Platform.isIOS; + } + } } /// Home page of the sample browser for both mobile and web @@ -100,7 +125,7 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { - SampleModel sampleListModel; + late SampleModel sampleListModel; GlobalKey scaffoldKey = GlobalKey(); final ScrollController controller = ScrollController(); @override @@ -124,6 +149,10 @@ class _HomePageState extends State { Widget build(BuildContext context) { ///Checking the download button is currently hovered bool isHoveringDownloadButton = false; + + ///Checking the get packages is currently hovered + bool isHoveringPubDevButton = false; + final bool isMaxxSize = MediaQuery.of(context).size.width >= 1000; final SampleModel model = sampleListModel; model.isMobileResolution = (MediaQuery.of(context).size.width) < 768; return Container( @@ -131,15 +160,19 @@ class _HomePageState extends State { child: model.isMobileResolution ? Scaffold( resizeToAvoidBottomInset: false, - drawer: (!model.isWeb && Platform.isIOS) + drawer: (!model.isWebFullView && Platform.isIOS) ? null //Avoiding drawer in iOS platform : getLeftSideDrawer(model), key: scaffoldKey, backgroundColor: model.webBackgroundColor, - endDrawer: model.isWeb ? showWebThemeSettings(model) : null, + endDrawer: + model.isWebFullView ? showWebThemeSettings(model) : null, appBar: PreferredSize( preferredSize: const Size.fromHeight(46.0), child: AppBar( + leading: (!model.isWebFullView && Platform.isIOS) + ? Container() + : null, elevation: 0.0, backgroundColor: model.paletteColor, title: AnimateOpacityWidget( @@ -156,8 +189,8 @@ class _HomePageState extends State { icon: const Icon(Icons.settings, color: Colors.white), onPressed: () { - model.isWeb - ? scaffoldKey.currentState.openEndDrawer() + model.isWebFullView + ? scaffoldKey.currentState!.openEndDrawer() : showBottomSettingsPanel(model, context); }, ), @@ -185,34 +218,15 @@ class _HomePageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: - const EdgeInsets.fromLTRB(24, 10, 0, 0), - child: Row(children: [ - const Text('Flutter UI Widgets ', - style: TextStyle( - color: Colors.white, - fontSize: 28, - letterSpacing: 0.53, - fontFamily: 'Roboto-Bold')), - model.isWeb - ? Container( - padding: - const EdgeInsets.fromLTRB( - 3, 0, 3, 0), - decoration: const BoxDecoration( - shape: BoxShape.rectangle, - color: Color.fromRGBO( - 245, 188, 14, 1)), - child: const Text( - 'BETA', - style: TextStyle( - fontSize: 14, - letterSpacing: 0.26, - fontFamily: 'Roboto-Medium', - color: Colors.black), - )) - : Container() - ])), + padding: + const EdgeInsets.fromLTRB(24, 10, 0, 0), + child: const Text('Flutter UI Widgets ', + style: TextStyle( + color: Colors.white, + fontSize: 28, + letterSpacing: 0.53, + fontFamily: 'Roboto-Bold')), + ), const Padding( padding: EdgeInsets.fromLTRB(24, 0, 0, 0), child: Text('Fast . Fluid . Flexible', @@ -228,7 +242,7 @@ class _HomePageState extends State { Container( alignment: Alignment.bottomCenter, width: double.infinity, - height: 16, + height: kIsWeb ? 16 : 14, decoration: BoxDecoration( color: model.webBackgroundColor, borderRadius: const BorderRadius.only( @@ -251,9 +265,13 @@ class _HomePageState extends State { padding: const EdgeInsets.only(top: 10, right: 10), width: MediaQuery.of(context).size.width >= - 900 - ? 400 - : MediaQuery.of(context).size.width / 3, + 920 + ? 300 + : MediaQuery.of(context).size.width / + (MediaQuery.of(context).size.width < + 820 + ? 5 + : 4), height: MediaQuery.of(context).size.height * 0.0445, child: SearchBar( @@ -266,7 +284,8 @@ class _HomePageState extends State { ? Container() : Container( alignment: Alignment.center, - padding: EdgeInsets.only(top: 10), + padding: EdgeInsets.only( + top: 10, left: isMaxxSize ? 20 : 0), child: Container( width: 115, height: 32, @@ -277,51 +296,112 @@ class _HomePageState extends State { (BuildContext context, StateSetter setState) { return MouseRegion( - child: InkWell( - hoverColor: Colors.white, - child: Padding( - padding: - const EdgeInsets.fromLTRB( - 8, 9, 8, 9), - child: Text('DOWNLOAD NOW', + onHover: (PointerHoverEvent event) { + isHoveringDownloadButton = true; + setState(() {}); + }, + onExit: (PointerExitEvent event) { + isHoveringDownloadButton = false; + setState(() {}); + }, + child: InkWell( + hoverColor: Colors.white, + onTap: () { + launch( + 'https://www.syncfusion.com/downloads/flutter/confirm'); + }, + child: Padding( + padding: + const EdgeInsets.fromLTRB( + 8, 9, 8, 9), + child: Text('DOWNLOAD NOW', + style: TextStyle( + color: + isHoveringDownloadButton + ? model + .paletteColor + : Colors.white, + fontSize: 12, + fontFamily: + 'Roboto-Medium')), + ), + ), + ); + }))), + + ///Get package from pub.dev option + model.isMobileResolution + ? Container() + : Container( + alignment: Alignment.center, + padding: EdgeInsets.only( + top: 10, left: isMaxxSize ? 25 : 12), + child: Container( + width: 118, + height: 32, + decoration: BoxDecoration( + border: + Border.all(color: Colors.white)), + child: StatefulBuilder(builder: + (BuildContext context, + StateSetter setState) { + return MouseRegion( + onHover: (PointerHoverEvent event) { + isHoveringPubDevButton = true; + setState(() {}); + }, + onExit: (PointerExitEvent event) { + isHoveringPubDevButton = false; + setState(() {}); + }, + child: InkWell( + hoverColor: Colors.white, + onTap: () { + launch( + 'https://pub.dev/publishers/syncfusion.com/packages'); + }, + child: Padding( + padding: + const EdgeInsets.fromLTRB( + 0, 7, 8, 7), + child: Row(children: [ + Image.asset( + 'images/pub_logo.png', + fit: BoxFit.contain, + height: 33, + width: 33), + Text('Get Packages', style: TextStyle( color: - isHoveringDownloadButton + isHoveringPubDevButton ? model .paletteColor : Colors.white, fontSize: 12, fontFamily: - 'Roboto-Medium')), - ), - onTap: () { - launch( - 'https://www.syncfusion.com/downloads/flutter/confirm'); - }, + 'Roboto-Medium')) + ]), ), - onHover: (PointerHoverEvent event) { - isHoveringDownloadButton = true; - setState(() {}); - }, - onExit: (PointerExitEvent event) { - isHoveringDownloadButton = false; - setState(() {}); - }); + ), + ); }))), - Container( - padding: MediaQuery.of(context).size.width < 500 - ? const EdgeInsets.only(top: 20, left: 5) - : const EdgeInsets.only(top: 10, right: 20), - height: 60, - width: 60, - child: IconButton( - icon: const Icon(Icons.settings, - color: Colors.white), - onPressed: () { - scaffoldKey.currentState.openEndDrawer(); - }, - ), - ), + Padding( + padding: + EdgeInsets.only(left: isMaxxSize ? 15 : 0), + child: Container( + padding: MediaQuery.of(context).size.width < 500 + ? const EdgeInsets.only(top: 20, left: 5) + : EdgeInsets.only(top: 10, right: 15), + height: 60, + width: 60, + child: IconButton( + icon: const Icon(Icons.settings, + color: Colors.white), + onPressed: () { + scaffoldKey.currentState!.openEndDrawer(); + }, + ), + )), ], )), body: _CategorizedCards())), @@ -473,14 +553,14 @@ class _PersistentHeaderDelegate extends SliverPersistentHeaderDelegate { _PersistentHeaderDelegate(SampleModel sampleModel) { _sampleListModel = sampleModel; } - SampleModel _sampleListModel; + SampleModel? _sampleListModel; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return SizedBox( height: 90, child: Container( - color: _sampleListModel.paletteColor, + color: _sampleListModel!.paletteColor, child: Column( children: [ Container( @@ -491,13 +571,13 @@ class _PersistentHeaderDelegate extends SliverPersistentHeaderDelegate { Container( height: 20, decoration: BoxDecoration( - color: _sampleListModel.webBackgroundColor, + color: _sampleListModel!.webBackgroundColor, borderRadius: const BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0)), boxShadow: [ BoxShadow( - color: _sampleListModel.webBackgroundColor, + color: _sampleListModel!.webBackgroundColor, offset: const Offset(0, 2.0), blurRadius: 0.25, ) @@ -528,7 +608,7 @@ class _CategorizedCards extends StatefulWidget { class _CategorizedCardsState extends State<_CategorizedCards> { SampleModel model = SampleModel.instance; - double _cardWidth; + late double _cardWidth; @override Widget build(BuildContext context) { @@ -544,7 +624,7 @@ class _CategorizedCardsState extends State<_CategorizedCards> { ? deviceWidth * 0.041 : deviceWidth * 0.05; - Widget organizedCardWidget; + Widget? organizedCardWidget; if (deviceWidth > 1060) { padding = deviceWidth * 0.011; @@ -556,9 +636,9 @@ class _CategorizedCardsState extends State<_CategorizedCards> { _sidePadding = (deviceWidth - 2740) * 0.5; padding = 30; } - List firstColumnWidgets = []; - List secondColumnWidgets = []; - List thirdColumnWidgets = []; + final List firstColumnWidgets = []; + final List secondColumnWidgets = []; + final List thirdColumnWidgets = []; int firstColumnControlCount = 0; int secondColumnControlCount = 0; for (int i = 0; i < model.categoryList.length; i++) { @@ -566,15 +646,15 @@ class _CategorizedCardsState extends State<_CategorizedCards> { firstColumnWidgets.add(_getCategoryWidget(model.categoryList[i])); firstColumnWidgets .add(Padding(padding: EdgeInsets.only(top: padding))); - firstColumnControlCount += model.categoryList[i].controlList.length; + firstColumnControlCount += model.categoryList[i].controlList!.length; } else if (secondColumnControlCount < model.controlList.length / 3 && (secondColumnControlCount + - model.categoryList[i].controlList.length < + model.categoryList[i].controlList!.length < model.controlList.length / 3)) { secondColumnWidgets.add(_getCategoryWidget(model.categoryList[i])); secondColumnWidgets .add(Padding(padding: EdgeInsets.only(top: padding))); - secondColumnControlCount += model.categoryList[i].controlList.length; + secondColumnControlCount += model.categoryList[i].controlList!.length; } else { thirdColumnWidgets.add(_getCategoryWidget(model.categoryList[i])); thirdColumnWidgets @@ -598,15 +678,15 @@ class _CategorizedCardsState extends State<_CategorizedCards> { } else if (deviceWidth >= 768) { padding = deviceWidth * 0.018; _cardWidth = (deviceWidth * 0.9) / 2; - List firstColumnWidgets = []; - List secondColumnWidgets = []; + final List firstColumnWidgets = []; + final List secondColumnWidgets = []; int firstColumnControlCount = 0; for (int i = 0; i < model.categoryList.length; i++) { if (firstColumnControlCount < model.controlList.length / 2) { firstColumnWidgets.add(_getCategoryWidget(model.categoryList[i])); firstColumnWidgets .add(Padding(padding: EdgeInsets.only(top: padding))); - firstColumnControlCount += model.categoryList[i].controlList.length; + firstColumnControlCount += model.categoryList[i].controlList!.length; } else { secondColumnWidgets.add(_getCategoryWidget(model.categoryList[i])); secondColumnWidgets @@ -629,7 +709,7 @@ class _CategorizedCardsState extends State<_CategorizedCards> { _cardWidth = deviceWidth * 0.9; padding = deviceWidth * 0.035; _sidePadding = (deviceWidth * 0.1) / 2; - List verticalOrderedWidgets = []; + final List verticalOrderedWidgets = []; for (int i = 0; i < model.categoryList.length; i++) { verticalOrderedWidgets.add(_getCategoryWidget(model.categoryList[i])); verticalOrderedWidgets @@ -665,7 +745,7 @@ class _CategorizedCardsState extends State<_CategorizedCards> { Container( padding: const EdgeInsets.only(top: 15, bottom: 2), child: Text( - category.categoryName.toUpperCase(), + category.categoryName!.toUpperCase(), style: TextStyle( color: model.backgroundColor, fontSize: 16, @@ -685,16 +765,8 @@ class _CategorizedCardsState extends State<_CategorizedCards> { /// get the list view of the controls in the specified category List _getControlListView(WidgetCategory category) { final List items = []; - String status; - for (int i = 0; i < category.controlList.length; i++) { - final Control control = category.controlList[i]; - status = (control.status == 'preview' || control.status == 'Preview') && - !model.isWeb && - Platform.isIOS - ? 'New' - : (control.title == 'Radial Gauge' && model.isWeb) - ? null - : control.status; + for (int i = 0; i < category.controlList!.length; i++) { + final Control control = category.controlList![i]; items.add(Container( color: model.cardColor, child: Material( @@ -704,7 +776,7 @@ class _CategorizedCardsState extends State<_CategorizedCards> { splashFactory: InkRipple.splashFactory, hoverColor: Colors.grey.withOpacity(0.2), onTap: () { - !model.isWeb + !model.isWebFullView ? onTapControlInMobile(context, model, category, i) : onTapControlInWeb(context, model, category, i); model.searchResults.clear(); @@ -712,43 +784,65 @@ class _CategorizedCardsState extends State<_CategorizedCards> { child: Container( child: ListTile( contentPadding: EdgeInsets.fromLTRB( - 12, 2, 0, category.controlList.length > 3 ? 6 : 0), - leading: Image.asset(control.image, fit: BoxFit.cover), + 12, 2, 0, category.controlList!.length > 3 ? 6 : 0), + leading: Image.asset(control.image!, fit: BoxFit.cover), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - control.title, - textAlign: TextAlign.left, - softWrap: true, - textScaleFactor: 1, - overflow: TextOverflow.fade, - style: TextStyle( - fontSize: 12, - letterSpacing: 0.1, - color: model.textColor, - fontFamily: 'Roboto-Bold'), - ), - status != null + Row(children: [ + Text( + control.title!, + textAlign: TextAlign.left, + softWrap: true, + textScaleFactor: 1, + overflow: TextOverflow.fade, + style: TextStyle( + fontSize: 12, + letterSpacing: 0.1, + color: model.textColor, + fontFamily: 'Roboto-Bold'), + ), + (!model.isWebFullView && Platform.isIOS) + ? Container() + : control.isBeta == true + ? Padding( + padding: EdgeInsets.only(left: 8), + child: Container( + padding: const EdgeInsets.fromLTRB( + 3, 3, 3, 2), + decoration: const BoxDecoration( + shape: BoxShape.rectangle, + color: Color.fromRGBO( + 245, 188, 14, 1)), + child: const Text( + 'BETA', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w500, + letterSpacing: 0.12, + fontFamily: 'Roboto-Medium', + color: Colors.black), + ))) + : Container() + ]), + control.status != null ? Container( decoration: BoxDecoration( shape: BoxShape.rectangle, - color: status.toLowerCase() == 'new' + color: control.status!.toLowerCase() == + 'new' ? const Color.fromRGBO(55, 153, 30, 1) - : status.toLowerCase() == 'updated' + : control.status!.toLowerCase() == + 'updated' ? const Color.fromRGBO( 246, 117, 0, 1) - : status.toLowerCase() == - 'preview' - ? const Color.fromRGBO( - 74, 90, 231, 1) - : Colors.transparent, + : Colors.transparent, borderRadius: const BorderRadius.only( topLeft: Radius.circular(10), bottomLeft: Radius.circular(10))), padding: const EdgeInsets.fromLTRB(6, 2.7, 4, 2.7), - child: Text(status, + child: Text(control.status!, style: const TextStyle( fontFamily: 'Roboto-Medium', color: Colors.white, @@ -759,7 +853,7 @@ class _CategorizedCardsState extends State<_CategorizedCards> { child: Padding( padding: const EdgeInsets.fromLTRB(0.0, 7.0, 12.0, 0.0), child: Text( - control.description, + control.description!, textAlign: TextAlign.left, softWrap: true, textScaleFactor: 1, diff --git a/lib/sample_details.json b/lib/sample_details.json index ac206287..087b3dc4 100644 --- a/lib/sample_details.json +++ b/lib/sample_details.json @@ -9,7 +9,7 @@ "description": "Generate and display data in machine-readable 1D and 2D barcodes", "image": "images/barcode.png", "displayType": "tab", - "controlId": 6, + "controlId": 8, "subItems": [ { "type": "sample", @@ -33,6 +33,101 @@ } ] }, + { + "title": "Treemap", + "description": "Visualize hierarchically structured data that is sized and colored by quantitative variables", + "image": "images/treemap.png", + "displayType": "tab", + "status": "New", + "isBeta": true, + "controlId": 4, + "subItems": [ + { + "type": "child", + "title": "Layouts", + "subItems": [ + { + "type": "sample", + "title": "Squarified", + "key": "squarified_treemap_flat", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/flat/flat.dart" + }, + { + "type": "sample", + "title": "Slice", + "key": "slice_treemap_flat", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/flat/flat.dart" + }, + { + "type": "sample", + "title": "Dice", + "key": "dice_treemap_flat", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/flat/flat.dart" + } + ] + }, + { + "type": "child", + "title": "Hierarchical", + "subItems": [ + { + "type": "sample", + "title": "Hierarchical", + "key": "squarified_treemap_hierarchical", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/hierarchical/hierarchical.dart" + } + ] + }, + { + "type": "child", + "title": "Value color mapping", + "subItems": [ + { + "type": "sample", + "title": "Value color mapping", + "key": "squarified_value_color_mapping", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/value_color_mapping/value_color_mapping.dart" + } + ] + }, + { + "type": "child", + "title": "Range color mapping", + "subItems": [ + { + "type": "sample", + "title": "Range color mapping", + "key": "squarified_range_color_mapping", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/range_color_mapping/range_color_mapping.dart" + } + ] + }, + { + "type": "child", + "title": "Selection", + "subItems": [ + { + "type": "sample", + "title": "Selection", + "key": "squarified_treemap_selection", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/selection/selection.dart" + } + ] + }, + { + "type": "child", + "title": "Custom background", + "subItems": [ + { + "type": "sample", + "title": "Custom background", + "key": "squarified_treemap_custom_background", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/treemap/custom_background/custom_background.dart" + } + ] + } + ] + }, { "title": "Cartesian Charts", "description": "Plot over 30 chart types ranging from line charts to financial charts", @@ -586,6 +681,20 @@ } ] }, + { + "type": "child", + "title": "On-demand Loading", + "displayType": "tab", + "subItems": [ + { + "title": "Infinite scrolling", + "key": "infinite_scrolling", + "status": "New", + "description": "This sample demonstrates the infinite scrolling functionality. When horizontal scrolling reaches the end of the chart, more data will be loaded and a circular progress indicator will be shown until loading. ", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/on_demand_loading/infinite_scrolling.dart" + } + ] + }, { "type": "parent", "title": "Axis Types", @@ -676,6 +785,28 @@ } ] }, + { + "type": "child", + "title": "Date Time Category", + "displayType": "card", + "status": "New", + "subItems": [ + { + "title": "Default date time category axis", + "key": "default_datetime_category_axis", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/axis_types/date_time_category/default_date_time_category.dart", + "description": "", + "status": "new" + }, + { + "title": "Label format", + "key": "default_datetime_category_axis_label", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/axis_types/date_time_category/date_time_category_with_label_format.dart", + "description": "", + "status": "new" + } + ] + }, { "type": "child", "title": "Logarithmic", @@ -730,7 +861,6 @@ { "title": "Maximum width for labels", "key": "chart_maximum_label_width", - "status": "New", "description": "Maximum width for axis labels can be specified using the maximumLabelWidth property. The maximum space occupied by the axis labels can be changed using the labelsExtent property. A tooltip will be shown on clicking/tapping the trimmed axis label in both cases.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart", "sourceLink": "https://www.emporis.com/statistics/worlds-tallest-buildings", @@ -1031,11 +1161,13 @@ { "type": "child", "title": "Trackball", + "status": "Updated", "displayType": "card", "subItems": [ { "title": "Chart with trackball", "key": "chart_with_trackball", + "status": "Updated", "description": "The trackball is enabled in this sample. Tap the chart to show the trackball and drag the chart to change the position of the trackball continuously. On the web, you can move the cursor over the chart area to display the trackball.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart", "needsPropertyPanel": true @@ -1043,7 +1175,6 @@ { "title": "Customized trackball", "key": "chart_with_trackball_template", - "status": "New", "description": "This example displays a custom widget as the trackball. To see the customized trackball, tap the chart area in mobile and hover the chart area on the web.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart", "needsPropertyPanel": true @@ -1085,7 +1216,6 @@ { "title": "Navigation with events", "key": "navigate_with_events", - "status": "New", "description": "Tap/click on the axis labels, data points or on the data labels for navigating to an external link.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart", "sourceLink": "https://www.emporis.com/statistics/worlds-tallest-buildings", @@ -1100,12 +1230,39 @@ "subItems": [ { "title": "Add a point on click", - "status": "New", "description": "This example depicts the pixel to data point conversion feature. Tap/click on the chart area to add a data point dynamically on that location.", "key": "chart_interactivity", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart" } ] + }, + { + "type": "child", + "title": "Pagination", + "displayType": "tab", + "subItems": [ + { + "title": "Pagination", + "key": "pagination", + "status": "New", + "description": "This sample shows how to view the next set of data on swiping the chart using the 'onPlotAreaSwipe' callback function. You can swipe from left to right or vice versa and also click on the days at the bottom to view the next set of data.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/on_demand_loading/pagination.dart" + } + ] + }, + { + "type": "child", + "title": "Auto Scrolling", + "displayType": "tab", + "subItems": [ + { + "title": "Auto Scrolling", + "description": "In this sample, the data is being added every second. The chart is scrolled to the end automatically to view the current data and you can pan the chart from left to right direction to view the previous data points.", + "status": "new", + "key": "auto_scrolling", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart" + } + ] } ] }, @@ -1237,7 +1394,6 @@ }, { "title": "Interaction", - "status": "New", "description": "This example depicts the pixel to data point conversion feature. Tap/click on the chart area to add a data point dynamically on that location.", "key": "chart_interactivity", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart" @@ -1292,7 +1448,7 @@ "title": "Circular Charts", "description": "Visualize the data using pie, doughnut, and radial bar charts", "image": "images/circle_series.png", - "status": "", + "status": "Updated", "controlId": 2, "subItems": [ { @@ -1305,7 +1461,7 @@ "displayType": "card", "subItems": [ { - "title": "Default pie chart", + "title": "Default", "key": "default_pie_chart", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart" }, @@ -1324,16 +1480,39 @@ "needsPropertyPanel": true }, { - "title": "Pie with grouping", + "title": "Grouping", "key": "pie_with_grouping", "description": "This sample demonstrates the grouping functionality in a pie chart. Data points’ values less than the specified value can be grouped together.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart" }, { - "title": "Pie with smart labels", + "title": "Smart labels", "key": "pie_with_smart_labels", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart", "needsPropertyPanel": true + }, + { + "title": "Gradient fill", + "key": "pie_with_gradient", + "description": "This sample demonstrates how to apply different types of gradient to the pie slices. Here you can apply the linear, sweep, and radial gradients using the dropdown menu in the property panel.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/pie_with_gradient.dart", + "status": "new", + "needsPropertyPanel": true + }, + { + "title": "Image fill", + "key": "pie_with_imageShader", + "status": "new", + "description":"This sample demonstrates how to fill the pie slices with various images for each slice using the 'ImageShader'.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart" + }, + { + "title": "Point render mode", + "key": "pie_point_render_mode", + "status": "new", + "description":"This sample demonstrates how to fill the pie slices with various images for each slice using the 'ImageShader'.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart", + "needsPropertyPanel": true } ] }, @@ -1343,25 +1522,25 @@ "displayType": "card", "subItems": [ { - "title": "Default doughnut chart", + "title": "Default", "key": "default_doughnut_chart", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart", "sourceLink": "https://www.pngkit.com/view/u2q8y3w7r5y3t4o0_composition-of-ocean-water-earths-oceans-elements-percentage/", "sourceText": "www.pngkit.com" }, { - "title": "Doughnut with center elevation", + "title": "Center elevation", "key": "doughnut_with_center_elevation", "description": "The doughnut chart is rendered with elevated circle at the center using annotations feature in this sample.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart" }, { - "title": "Doughnut with rounded corners", + "title": "Rounded corners", "key": "doughnut_with_rounded_corners", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart" }, { - "title": "Doughnut with color mapping", + "title": "Color mapping", "key": "doughnut_with_color_mapping", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart" }, @@ -1370,6 +1549,14 @@ "key": "semi_doughnut_chart", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart", "needsPropertyPanel": true + }, + { + "title": "Gradient fill", + "key": "doughnut_with_gradient", + "description":"This sample demonstrates how to apply different types of gradient to the doughnut slices. Here you can apply the linear, sweep, and radial gradients using the dropdown menu in the property panel.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_gradient.dart", + "status": "new", + "needsPropertyPanel": true } ] }, @@ -1379,12 +1566,12 @@ "displayType": "card", "subItems": [ { - "title": "Default radial bar chart", + "title": "Default", "key": "default_radialbar_chart", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart" }, { - "title": "Radial bar with legend", + "title": "Legend", "key": "radialbar_with_legend", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart" }, @@ -1393,6 +1580,13 @@ "key": "customized_radialbar_chart", "description": "This sample renders the radial bar chart with annotation at the center and templated legend.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart" + }, + { + "title": "Gradient fill", + "status": "new", + "key": "radialbar_with_gradient", + "description": "This sample renders the radial bar chart with gradient.", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_gradient.dart" } ] } @@ -1464,7 +1658,8 @@ "title": "Radial Gauge", "description": "Visualize one or multiple measures on a circular scale with pointers and ranges", "image": "images/circle_gauge.png", - "controlId": 3, + "controlId": 4, + "status": "Updated", "subItems": [ { "type": "child", @@ -1580,8 +1775,10 @@ "type": "sample", "title": "Marker pointer", "key": "radial_marker", + "status": "Updated", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointers/marker_pointer.dart", - "description": "" + "description": "", + "needsPropertyPanel": true }, { "type": "sample", @@ -1589,6 +1786,14 @@ "key": "text_pointer", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointers/text_pointer.dart", "description": "" + }, + { + "type": "sample", + "title": "Widget pointer", + "key": "radial_widget_pointer", + "status": "new", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointers/widget_pointer.dart", + "description": "This sample demonstrates how to use a custom widget as a pointer using the 'WidgetPointer'." } ] }, @@ -1655,16 +1860,18 @@ "subItems": [ { "type": "sample", - "title": "Radial slider", - "key": "radial_pointerdragging", - "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointer_interaction/radial_slider.dart", - "description": "" + "title": "Pointer drag", + "key": "radial_slider", + "status": "updated", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointer_interaction/radial_range_slider.dart", + "description": "", + "needsPropertyPanel": true }, { "type": "sample", - "title": "Radial range slider", - "key": "radial_slider", - "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointer_interaction/radial_range_slider.dart", + "title": "Dragging with slider", + "key": "radial_pointerdragging", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/gauge/pointer_interaction/radial_slider.dart", "description": "" } ] @@ -1742,13 +1949,184 @@ } ] }, + { + "title": "Linear Gauge", + "status": "New", + "description": "Visualize one or multiple measures on a linear scale with pointers and ranges", + "image": "images/linear_gauge.png", + "controlId": 5, + "isBeta": true, + "subItems": [ + { + "type": "child", + "title": "Showcase", + "displayType": "card", + "subItems": [ + { + "type": "sample", + "title": "Thermometer", + "key": "thermometer", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/thermometer.dart", + "description": "" + }, + { + "type": "sample", + "title": "Height calculator", + "key": "height_calculator", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/heightCalculator.dart", + "description": "" + }, + { + "type": "sample", + "title": "Water level indicator", + "key": "water_indicator", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/waterIndicator.dart", + "description": "" + }, + { + "type": "sample", + "title": "Volume settings", + "key": "volume_settings", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/volume_settings.dart", + "description": "" + }, + { + "type": "sample", + "title": "Progress bar", + "key": "progress_bar", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/progress_bar.dart", + "description": "" + }, + { + "type": "sample", + "title": "Task tracker", + "key": "task_tracker", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/task_tracker.dart", + "description": "" + }, + { + "type": "sample", + "title": "Sleep watch score", + "key": "sleep_watch", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/sleep_watch_score.dart", + "description": "" + }, + { + "type": "sample", + "title": "Steps counter", + "key": "steps_counter", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/steps_counter.dart", + "description": "" + }, + { + "type": "sample", + "title": "Temperature meter", + "key": "heat_meter", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/heat_mter.dart", + "description": "" + }, + { + "type": "sample", + "title": "Battery indicator", + "key": "battery_indicator", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/showcase/battery_indicator.dart", + "description": "" + } + ] + }, + { + "type": "child", + "title": "Axis", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Track", + "key": "axis_track", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/axis/axis_track.dart", + "description": "" + }, + { + "type": "sample", + "title": "Ticks", + "key": "ticks_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/axis/tick_customization.dart", + "description": "" + }, + { + "type": "sample", + "title": "Labels", + "key": "label_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/axis/label_customization.dart", + "description": "" + } + ] + }, + { + "type": "child", + "title": "Range", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Default range", + "key": "custom_range", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/ranges/range_customization.dart", + "description": "" + } + ] + }, + { + "type": "child", + "title": "Pointers", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Shape pointer", + "key": "shape_pointer", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/pointers/shape_pointer.dart", + "description": "" + }, + { + "type": "sample", + "title": "Widget pointer", + "key": "widget_pointer", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/pointers/widget_pointer.dart", + "description": "" + }, + { + "type": "sample", + "title": "Bar pointer", + "key": "bar_pointer", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/pointers/bar_pointer.dart", + "description": "" + } + ] + }, + { + "type": "child", + "title": "API", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "API", + "key": "api_gauge", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/linear_gauge/api/api_customization.dart", + "description": "" + } + ] + } + ] + }, { "title": "Funnel Chart", "description": "Visualize the sequential data using funnel chart", "image": "images/funnel.png", "status": "", "displayType": "card", - "controlId": 5, + "controlId": 7, "subItems": [ { "title": "Default funnel chart", @@ -1775,7 +2153,7 @@ "image": "images/pyramid.png", "status": "", "displayType": "card", - "controlId": 4, + "controlId": 6, "subItems": [ { "title": "Default pyramid chart", @@ -1803,26 +2181,24 @@ "description": "Easily visualize data over a geographical area", "image": "images/map.png", "displayType": "tab", - "controlId": 7, + "controlId": 3, + "isBeta": true, "status": "Updated", "subItems": [ { "type": "child", "title": "Shape Layer", - "status": "Updated", "displayType": "tab", "subItems": [ { "type": "sample", "title": "Range color mapping", - "status": "Updated", "key": "range_color_mapping", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart" }, { "type": "sample", "title": "Equal color mapping", - "status": "Updated", "key": "equal_color_mapping", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart" }, @@ -1847,7 +2223,6 @@ { "type": "sample", "title": "Legend", - "status": "Updated", "key": "legend", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/shape_layer/legend/legend.dart", "needsPropertyPanel": true @@ -1861,14 +2236,13 @@ { "type": "sample", "title": "Zooming", - "status": "Updated", "key": "zooming", + "status": "Updated", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/shape_layer/zooming/zooming.dart" }, { "type": "sample", "title": "Sublayer", - "status": "new", "key": "sublayer", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/shape_layer/sublayer/sublayer.dart" } @@ -1882,10 +2256,10 @@ "subItems": [ { "type": "sample", - "title": "OSM", + "title": "OpenStreetMap", + "key": "open_street_map", "status": "Updated", - "key": "osm", - "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/tile_layer/osm/osm.dart" + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/tile_layer/open_street_map/open_street_map.dart" }, { "type": "sample", @@ -1896,7 +2270,6 @@ { "type": "sample", "title": "Arcs and Lines", - "status": "New", "key": "arcs", "description": "This sample demonstrates how the arc layer and the line layer can be used for denoting the air routes between the different locations.", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/tile_layer/vector_layer/arcs.dart", @@ -1905,10 +2278,17 @@ { "type": "sample", "title": "Polylines", - "status": "New", "key": "polylines", "description": "This sample demonstrates how the polyline layer can be used for denoting the road routes between the two locations.", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/tile_layer/vector_layer/polylines.dart" + }, + { + "type": "sample", + "title": "Polygon", + "status": "New", + "key": "polygon", + "description": "This sample demonstrates how the default and inverted polygons can be used to denote a particular area", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/maps/tile_layer/vector_layer/polygon.dart" } ] } @@ -1919,7 +2299,7 @@ "description": "Indicates the progress of a task with customizable visuals. Designed using Radial Gauge widget.", "image": "images/circular_progress_bar.png", "displayType": "tab", - "controlId": 8, + "controlId": 10, "subItems": [ { "type": "sample", @@ -1936,7 +2316,6 @@ { "type": "sample", "title": "Segment styles", - "showInWeb": false, "key": "progress_bar_segment_styles", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/progress_bar/segment_styles.dart" }, @@ -1965,7 +2344,7 @@ "description": "Light-weight line, area, column and win-loss charts which fits in a very small area.", "image": "images/sparkline_winloss.png", "displayType": "tab", - "status": "New", + "isBeta":true, "controlId": 9, "subItems": [ { @@ -1984,7 +2363,7 @@ "type": "sample", "title": "Customization", "key": "sparkline_customization", - "description" : "This example depicts various useful features available in Spark charts. Enable the marker, data label, trackball, range band and also change the axis value with the options in the properties panel.", + "description": "This example depicts various useful features available in Spark charts. Enable the marker, data label, trackball, range band and also change the axis value with the options in the properties panel.", "needsPropertyPanel": true, "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sparkline/customization.dart" }, @@ -1992,7 +2371,7 @@ "type": "sample", "title": "Sparkline in Grid", "key": "sparkline_grid", - "description" : "This example depicts the rendering of Syncfusion Flutter Spark Charts in the cells of the Syncfusion Flutter Data Grid widget.", + "description": "This example depicts the rendering of Syncfusion Flutter Spark Charts in the cells of the Syncfusion Flutter Data Grid widget.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sparkline/sparkline_in_grid.dart" }, { @@ -2012,10 +2391,11 @@ "controlList": [ { "title": "DataGrid", + "status": "Updated", "description": "Displays large amounts of data with different data types in a tabular view", "image": "images/Datagrid.png", - "status": "Preview", "displayType": "tab", + "isBeta": true, "controlId": 1, "subItems": [ { @@ -2062,14 +2442,13 @@ "type": "sample", "title": "Custom Header", "key": "custom_header_datagrid", - "description": "This sample showcases how to load a widget to a header cell using the headerCellBuilder property. In this sample, the dropdown icon is loaded along with the text to the header cell. If you click the header cell, the popup menu options will be shown. You can sort that specific column or freeze it.", + "description": "In this sample, the dropdown icon is loaded along with the text to the header cell. If you click the header cell, the popup menu options will be shown. You can sort that specific column.", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/columns/datagrid_custom_header.dart" }, { "type": "sample", "title": "Stacked Header", "key": "stacked_header_datagrid", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/columns/datagrid_stacked_header.dart" } ] @@ -2081,7 +2460,7 @@ { "type": "sample", "title": "Sorting", - "description": "This sample demonstrates how to sort one or more columns. In the Web platform, you can sort multiple columns by tapping the column header with the CTRL key where as in a mobile platform you can tap the column headers. It also provides some additional functionalities like Tri-state sorting and displaying sort numbers that indicate the sort order.", + "description": "This sample demonstrates how to sort one or more columns. In the Web and Desktop platforms, you can sort multiple columns by tapping the column header with the CTRL key where as in a mobile platform you can tap the column headers. It also provides some additional functionalities like Tri-state sorting and displaying sort numbers that indicate the sort order.", "key": "sorting_datagrid", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/sorting/datagrid_sorting.dart", "needsPropertyPanel": true @@ -2108,6 +2487,7 @@ { "type": "sample", "title": "Freeze Panes", + "status": "Updated", "key": "freeze_panes_datagrid", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/freeze_panes/datagrid_freeze_panes.dart" } @@ -2115,14 +2495,13 @@ }, { "type": "child", - "title": "Auto Row Height", + "title": "Row Height", "subItems": [ { "type": "sample", - "title": "Auto Row Height", - "description": "This sample showcases the auto row height feature of the DataGrid that improves readability of the content. DataGrid provides support to change the height of the row based on its content that changes at run time for all columns or certain columns.", - "key": "auto_row_height_datagrid", - "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/auto_row_height/datagrid_auto_row_height.dart" + "title": "Row Height", + "key": "row_height_datagrid", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/row_height/datagrid_row_height.dart" } ] }, @@ -2133,6 +2512,7 @@ { "type": "sample", "title": "Styling", + "status": "Updated", "key": "styling_datagrid", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/apperance/styling/datagrid_styling.dart", "needsPropertyPanel": true @@ -2153,18 +2533,29 @@ "type": "sample", "title": "Infinite Scrolling", "key": "load_more_infinite_scrolling_datagrid", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/loadmore/datagrid_infinite_scrolling.dart" }, { "type": "sample", "title": "Load More", "key": "load_more_datagrid", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/loadmore/datagrid_load_more.dart" } ] }, + { + "type": "child", + "title": "Pull To Refresh", + "subItems": [ + { + "type": "sample", + "title": "Pull To Refresh", + "key": "pull_to_refresh_datagrid", + "status": "New", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/pull_to_refresh/datagrid_pull_to_refresh.dart" + } + ] + }, { "type": "child", "title": "Paging", @@ -2177,6 +2568,19 @@ } ] }, + { + "type": "child", + "title": "Swiping", + "subItems": [ + { + "type": "sample", + "title": "Swiping", + "status": "New", + "key": "swiping_datagrid", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/datagrid/swiping/datagrid_swiping.dart" + } + ] + }, { "type": "child", "title": "Real-Time Update", @@ -2229,7 +2633,6 @@ { "type": "sample", "title": "Special Regions", - "status": "Updated", "key": "special_regions_calendar", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/calendar/special_regions.dart" }, @@ -2241,8 +2644,14 @@ }, { "type": "sample", - "title": "Event Customization", + "title": "Load More", + "key": "loadmore_calendar", "status": "New", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/calendar/calendar_loadmore.dart" + }, + { + "type": "sample", + "title": "Event Customization", "key": "customization_calendar", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/calendar/customization.dart" }, @@ -2282,13 +2691,14 @@ "title": "Date Range Picker", "description": "Allows to easily select dates or range of dates", "image": "images/Date_range_picker.png", - "status": "Preview", "displayType": "tab", "controlId": 2, + "isBeta": true, "subItems": [ { "type": "sample", "title": "Getting Started", + "status": "Updated", "key": "getting_started_date_picker", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/date_picker/date_picker_getting_started.dart", "needsPropertyPanel": true @@ -2297,7 +2707,6 @@ "type": "sample", "title": "Hijri Calendar", "key": "hijri_calendar_date_picker", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/date_picker/hijri_calendar.dart", "needsPropertyPanel": true }, @@ -2323,8 +2732,9 @@ "type": "sample", "title": "Vertical Calendar", "key": "vertical_calendar", - "status": "New", - "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/date_picker/vertical_calendar.dart" + "status": "Updated", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/date_picker/vertical_calendar.dart", + "needsPropertyPanel": true } ] } @@ -2334,23 +2744,21 @@ "categoryName": "Viewer", "mobileCategoryId": 4, "webCategoryId": 4, - "showInWeb": false, "controlList": [ { "title": "PDF Viewer", "description": "View the PDF document seamlessly and efficiently", "image": "images/pdf_viewer.png", "displayType": "tab", - "showInWeb": false, - "status": "Preview", + "isBeta": true, "controlId": 1, + "status": "Updated", "subItems": [ { "type": "sample", "title": "Getting Started", "key": "pdf_viewer_getting_started", "status": "Updated", - "showInWeb": false, "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf_viewer/pdf_viewer_getting_started.dart" }, { @@ -2358,7 +2766,6 @@ "title": "Custom Toolbar", "key": "pdf_viewer_custom_toolbar", "status": "Updated", - "showInWeb": false, "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart" } ] @@ -2374,8 +2781,8 @@ "title": "PDF", "description": "Create PDF document with text, images and tables", "image": "images/pdf.png", - "status": "Preview", "displayType": "tab", + "isBeta": true, "controlId": 1, "subItems": [ { @@ -2414,19 +2821,31 @@ "key": "find_text", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf/find_text.dart" }, - { + { "type": "sample", "title": "Encryption", "key": "encryption", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf/encryption.dart" }, { "type": "sample", "title": "Conformance", "key": "conformance", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf/conformance.dart" + }, + { + "type": "sample", + "title": "Form Filling", + "key": "form", + "status": "New", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf/form.dart" + }, + { + "type": "sample", + "title": "Digital Signature", + "key": "digital_signature", + "status": "New", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/pdf/digital_signature.dart" } ] }, @@ -2434,8 +2853,8 @@ "title": "XlsIO", "description": "Create Excel documents with text, numbers, cell formatting, formulas, charts, images, and more", "image": "images/xlsio.png", - "status": "Preview", "displayType": "tab", + "isBeta": true, "controlId": 2, "subItems": [ { @@ -2460,9 +2879,15 @@ "type": "sample", "title": "Balance Sheet", "key": "balance_sheet", - "status": "New", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/xlsio/balance_sheet/balance_sheet.dart" - } + }, + { + "type": "sample", + "title": "Attendance Tracker", + "key": "attendance_tracker", + "status": "New", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/xlsio/attendance_tracker/attendance_tracker.dart" + } ] } ] @@ -2474,7 +2899,7 @@ "controlList": [ { "title": "Slider", - "description": "Select a date or numeric value", + "description": "The horizontal slider enables you to select a date or a numeric value", "image": "images/slider.png", "displayType": "tab", "controlId": 1, @@ -2558,7 +2983,7 @@ }, { "title": "Range Slider", - "description": "Select a date or numeric range", + "description": "The horizontal range slider enables you to select a date or a numeric range", "image": "images/range_slider.png", "controlId": 2, "subItems": [ @@ -2644,13 +3069,190 @@ } ] }, + { + "title": "Vertical Slider", + "description": "The vertical slider enables you to select a date or a numeric value", + "image": "images/vertical_slider.png", + "displayType": "tab", + "status": "New", + "controlId": 3, + "subItems": [ + { + "type": "child", + "title": "Basic features", + "status": "New", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Default", + "key": "default_vertical_slider", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/basic_features/default_vertical_slider.dart", + "description": "" + }, + { + "type": "sample", + "title": "Divisors, labels, and ticks", + "key": "vertical_slider_divisor_label_tick", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_divisor_label_tick.dart", + "description": "" + }, + { + "type": "sample", + "title": "Date interval", + "key": "vertical_slider_date_interval", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_date_interval.dart", + "description": "" + }, + { + "type": "sample", + "title": "Tooltip position", + "key": "vertical_slider_tooltip_position", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart", + "description": "" + }, + { + "type": "sample", + "title": "Step", + "key": "vertical_slider_step", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_step.dart", + "description": "" + } + ] + }, + { + "type": "child", + "status": "New", + "title": "Customization", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Thumb icon customization", + "key": "vertical_thumb_icon_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/customization/thumb_customization/vertical_slider_thumb_icon_customization.dart" + }, + { + "type": "sample", + "title": "Size customization", + "key": "vertical_slider_size_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/customization/size_customization/vertical_slider_size_customization.dart" + }, + { + "type": "sample", + "title": "Color customization", + "key": "vertical_slider_color_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/customization/color_customization/vertical_slider_color_customization.dart" + }, + { + "type": "sample", + "title": "Shape customization", + "key": "vertical_slider_shape_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_shape_customization.dart" + } + ] + } + ] + }, + { + "title": "Vertical Range Slider", + "description": "The vertical range slider enables you to select a date or a numeric range", + "image": "images/vertical_range_slider.png", + "displayType": "tab", + "status": "New", + "controlId": 4, + "subItems": [ + { + "type": "child", + "title": "Basic features", + "status": "New", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Default", + "key": "vertical_range_slider_default_appearance", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_default_appearance.dart", + "description": "" + }, + { + "type": "sample", + "title": "Divisors, labels, and ticks", + "key": "vertical_range_slider_divisor_label_tick", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_divisor_label_ticks.dart", + "description": "" + }, + { + "type": "sample", + "title": "Date interval", + "key": "vertical_range_slider_date_time_label", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_date_time_label.dart", + "description": "" + }, + { + "type": "sample", + "title": "Tooltip position", + "key": "vertical_range_slider_tooltip_position", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart", + "description": "" + }, + { + "type": "sample", + "title": "Step", + "key": "vertical_range_slider_step", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_step.dart", + "description": "" + }, + { + "type": "sample", + "title": "Interval selection", + "key": "vertical_range_slider_interval_selection", + "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_interval_selection.dart", + "description": "" + } + ] + }, + { + "type": "child", + "status": "New", + "title": "Customization", + "displayType": "tab", + "subItems": [ + { + "type": "sample", + "title": "Thumb icon customization", + "key": "vertical_range_slider_thumb_icon_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sliders/vertica_range_slider/customization/thumb_customization/vertical_range_slider_thumb_icon_customization.dart" + }, + { + "type": "sample", + "title": "Size customization", + "key": "vertical_range_slider_size_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sliders/vertical_range_slider/customization/size_customization/vertical_range_slider_size_customization.dart" + }, + { + "type": "sample", + "title": "Color customization", + "key": "vertical_range_slider_color_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_color_customization.dart" + }, + { + "type": "sample", + "title": "Shape customization", + "key": "vertical_range_slider_shape_customization", + "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_shape_customization.dart" + } + ] + } + ] + }, { "title": "Range Selector", "description": "Visualize data and select a date or numeric range", "image": "images/range_selector.png", "displayType": "tab", - "controlId": 3, - "status": "Preview", + "controlId": 5, + "isBeta": true, "subItems": [ { "type": "sample", @@ -2689,10 +3291,9 @@ "title": "Radial Slider", "description": "Selects a numeric value in a radial scale. Designed using Radial Gauge widget.", "image": "images/radial_slider.png", - "status": "Updated", "category": "Sliders", "displayType": "tab", - "controlId": 4, + "controlId": 6, "subItems": [ { "type": "child", @@ -2755,7 +3356,6 @@ "type": "sample", "title": "Gradient Fill", "key": "radial_slider_gradient", - "showInWeb": false, "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/radial_slider/customization/gradient.dart", "description": "" } @@ -2767,10 +3367,9 @@ "title": "Radial Range Slider", "description": "Selects a numeric range in a radial scale. Designed using Radial Gauge widget.", "image": "images/radial_range_slider.png", - "status": "Updated", "category": "Sliders", "displayType": "tab", - "controlId": 5, + "controlId": 7, "subItems": [ { "type": "child", @@ -2832,7 +3431,6 @@ { "type": "sample", "title": "Gradient Fill", - "showInWeb": false, "key": "radial_range_slider_gradient", "codeLink": "https://github.com/syncfusion/flutter-examples/tree/master/lib/samples/radial_range_slider/customization/gradient.dart", "description": "" @@ -2853,7 +3451,7 @@ "description": "Captures the signature and save it as an image to sync across devices and documents", "image": "images/SignaturePad.png", "displayType": "tab", - "status": "Preview", + "isBeta": true, "controlId": 1, "subItems": [ { diff --git a/lib/sample_list.dart b/lib/sample_list.dart index 52a6ea94..7707ec05 100644 --- a/lib/sample_list.dart +++ b/lib/sample_list.dart @@ -1,23 +1,25 @@ import 'package:flutter/foundation.dart'; + import 'samples/barcodes/data_matrix.dart'; import 'samples/barcodes/one_dimensional.dart'; import 'samples/barcodes/qr_code.dart'; import 'samples/calendar/agenda_view.dart'; +import 'samples/calendar/airfare.dart'; import 'samples/calendar/appointment_editor.dart'; +import 'samples/calendar/calendar_loadmore.dart'; import 'samples/calendar/customization.dart'; import 'samples/calendar/getting_started.dart'; +import 'samples/calendar/heatmap.dart'; import 'samples/calendar/recurrence.dart'; import 'samples/calendar/schedule_view.dart'; import 'samples/calendar/shift_scheduler.dart'; -import 'samples/calendar/heatmap.dart'; -import 'samples/calendar/airfare.dart'; -import 'samples/calendar/timeline_views.dart'; import 'samples/calendar/special_regions.dart'; +import 'samples/calendar/timeline_views.dart'; import 'samples/chart/cartesian_charts/axis_features/axis_animation.dart'; import 'samples/chart/cartesian_charts/axis_features/axis_crossing.dart'; import 'samples/chart/cartesian_charts/axis_features/edge_label_placement.dart'; -import 'samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart'; import 'samples/chart/cartesian_charts/axis_features/handling_label_collision.dart'; +import 'samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart'; import 'samples/chart/cartesian_charts/axis_features/multiple_axis_chart.dart'; import 'samples/chart/cartesian_charts/axis_features/opposed_axes.dart'; import 'samples/chart/cartesian_charts/axis_features/plot_band.dart'; @@ -28,16 +30,18 @@ import 'samples/chart/cartesian_charts/axis_types/category/indexed_category_axis import 'samples/chart/cartesian_charts/axis_types/category/label_placement.dart'; import 'samples/chart/cartesian_charts/axis_types/date_time/date_time_axis_with_label_format.dart'; import 'samples/chart/cartesian_charts/axis_types/date_time/default_date_time_axis.dart'; +import 'samples/chart/cartesian_charts/axis_types/date_time_category/date_time_category_with_label_format.dart'; +import 'samples/chart/cartesian_charts/axis_types/date_time_category/default_date_time_category.dart'; import 'samples/chart/cartesian_charts/axis_types/logarithmic/default_logarithmic_axis.dart'; import 'samples/chart/cartesian_charts/axis_types/logarithmic/inversed_logarithmic_axis.dart'; import 'samples/chart/cartesian_charts/axis_types/numeric/default_numeric_axis.dart'; import 'samples/chart/cartesian_charts/axis_types/numeric/inversed_numeric_axis.dart'; import 'samples/chart/cartesian_charts/axis_types/numeric/numeric_axis_with_label_format.dart'; import 'samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart'; +import 'samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart'; import 'samples/chart/cartesian_charts/chart_types/area/area_with_emptypoints.dart'; import 'samples/chart/cartesian_charts/chart_types/area/default_area_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/area/vertical_area_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart'; import 'samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart'; import 'samples/chart/cartesian_charts/chart_types/bar/bar_with_rounded_corners.dart'; @@ -53,11 +57,11 @@ import 'samples/chart/cartesian_charts/chart_types/bubble/default_bubble_chart.d import 'samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/column/back_to_back_column.dart'; import 'samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart'; +import 'samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart'; import 'samples/chart/cartesian_charts/chart_types/column/column_with_rounded_corners.dart'; import 'samples/chart/cartesian_charts/chart_types/column/column_with_track.dart'; import 'samples/chart/cartesian_charts/chart_types/column/customized_column_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/column/default_column_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart'; import 'samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/financial_charts/hilo_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/financial_charts/hilo_open_close_chart.dart'; @@ -75,14 +79,18 @@ import 'samples/chart/cartesian_charts/chart_types/range_column/vertical_range_c import 'samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/scatter/default_scatter_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/scatter/scatter_with_various_shapes.dart'; -import 'samples/chart/cartesian_charts/chart_types/spline_area.dart'; -import 'samples/chart/cartesian_charts/chart_types/spline_range_area.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/default_spline_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/spline_types.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/spline_with_dashes.dart'; import 'samples/chart/cartesian_charts/chart_types/spline/vertical_spline_chart.dart'; +import 'samples/chart/cartesian_charts/chart_types/spline_area.dart'; +import 'samples/chart/cartesian_charts/chart_types/spline_range_area.dart'; +import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart'; +import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart'; +import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart'; +import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_area_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_bar_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_column_chart.dart'; @@ -92,17 +100,14 @@ import 'samples/chart/cartesian_charts/chart_types/step_line/animation_step_line import 'samples/chart/cartesian_charts/chart_types/step_line/default_step_line_chart.dart'; import 'samples/chart/cartesian_charts/chart_types/step_line/step_line_with_dashes.dart'; import 'samples/chart/cartesian_charts/chart_types/step_line/vertical_step_line_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart'; import 'samples/chart/cartesian_charts/chart_types/waterfall/vertical_waterfall.dart'; -import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart'; -import 'samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart'; -import 'samples/chart/cartesian_charts/data_source/list.dart'; +import 'samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart'; import 'samples/chart/cartesian_charts/data_source/json.dart'; +import 'samples/chart/cartesian_charts/data_source/list.dart'; import 'samples/chart/cartesian_charts/export.dart'; -import 'samples/chart/cartesian_charts/legend/legend_various_options.dart'; import 'samples/chart/cartesian_charts/legend/chart_with_customized_legend.dart'; +import 'samples/chart/cartesian_charts/legend/legend_various_options.dart'; +import 'samples/chart/cartesian_charts/on_demand_loading/infinite_scrolling.dart'; import 'samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart'; import 'samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart'; import 'samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart'; @@ -112,8 +117,8 @@ import 'samples/chart/cartesian_charts/real_time_charts/update_data_source.dart' import 'samples/chart/cartesian_charts/series_features/animation/series_animation.dart'; import 'samples/chart/cartesian_charts/series_features/annotation/chart_with_annotation.dart'; import 'samples/chart/cartesian_charts/series_features/annotation/chart_with_watermark.dart'; -import 'samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart'; import 'samples/chart/cartesian_charts/series_features/data_label/data_label_template.dart'; +import 'samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart'; import 'samples/chart/cartesian_charts/series_features/empty_points.dart'; import 'samples/chart/cartesian_charts/series_features/gradients/horizantal_gradient.dart'; import 'samples/chart/cartesian_charts/series_features/gradients/vertical_gradient.dart'; @@ -131,66 +136,70 @@ import 'samples/chart/cartesian_charts/technical_indicators/stochastic_indicator import 'samples/chart/cartesian_charts/technical_indicators/tma_indicator.dart'; import 'samples/chart/cartesian_charts/trendline/default_trendline.dart'; import 'samples/chart/cartesian_charts/trendline/trendline_forecast.dart'; +import 'samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart'; +import 'samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart'; import 'samples/chart/cartesian_charts/user_interactions/crosshair.dart'; -import 'samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart'; -import 'samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart'; import 'samples/chart/cartesian_charts/user_interactions/events/events.dart'; import 'samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart'; +import 'samples/chart/cartesian_charts/user_interactions/pagination.dart'; import 'samples/chart/cartesian_charts/user_interactions/selection/dynamic_selection.dart'; import 'samples/chart/cartesian_charts/user_interactions/selection/selection_modes.dart'; import 'samples/chart/cartesian_charts/user_interactions/tooltip/default_tooltip.dart'; import 'samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_position.dart'; import 'samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_template.dart'; +import 'samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart'; +import 'samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart'; import 'samples/chart/cartesian_charts/user_interactions/zooming_and_panning/pinch_zooming.dart'; import 'samples/chart/cartesian_charts/user_interactions/zooming_and_panning/selection_zooming.dart'; -import 'samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart'; import 'samples/chart/cartesian_charts/user_interactions/zooming_and_panning/zooming_with_custom_buttons.dart'; import 'samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart'; import 'samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart'; import 'samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart'; +import 'samples/chart/circular_charts/chart_types/doughnut/doughnut_with_gradient.dart'; import 'samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart'; import 'samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart'; import 'samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart'; +import 'samples/chart/circular_charts/chart_types/pie/pie_with_gradient.dart'; import 'samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart'; +import 'samples/chart/circular_charts/chart_types/pie/pie_with_image.dart'; import 'samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart'; import 'samples/chart/circular_charts/chart_types/pie/pie_with_various_radius.dart'; +import 'samples/chart/circular_charts/chart_types/pie/point_render_mode.dart'; import 'samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart'; import 'samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart'; import 'samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart'; +import 'samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_gradient.dart'; import 'samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart'; import 'samples/chart/circular_charts/export.dart'; -import 'samples/chart/circular_charts/user_interactions/selection.dart'; +import 'samples/chart/circular_charts/legend/chart_with_legend.dart'; +import 'samples/chart/circular_charts/legend/legend_with_various_options.dart'; import 'samples/chart/circular_charts/user_interactions/dynamic_selection.dart'; +import 'samples/chart/circular_charts/user_interactions/selection.dart'; import 'samples/chart/circular_charts/user_interactions/tooltip.dart'; import 'samples/chart/funnel_charts/default_funnel_chart.dart'; import 'samples/chart/funnel_charts/funnel_with_legend.dart'; import 'samples/chart/funnel_charts/funnel_with_smart_labels.dart'; -import 'samples/chart/circular_charts/legend/chart_with_legend.dart'; -import 'samples/chart/circular_charts/legend/legend_with_various_options.dart'; import 'samples/chart/pyramid_charts/default_pyramid_chart.dart'; import 'samples/chart/pyramid_charts/pyramid_with_legend.dart'; import 'samples/chart/pyramid_charts/pyramid_with_smart_labels.dart'; -import 'samples/sparkline/chart_types.dart'; -import 'samples/sparkline/axis_types.dart'; -import 'samples/sparkline/customization.dart'; -import 'samples/sparkline/sparkline_in_grid.dart'; -import 'samples/sparkline/live_update.dart'; -import 'samples/datagrid/auto_row_height/datagrid_auto_row_height.dart'; +import 'samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart'; +import 'samples/datagrid/apperance/styling/datagrid_styling.dart'; import 'samples/datagrid/columns/datagrid_column_types.dart'; import 'samples/datagrid/columns/datagrid_custom_header.dart'; -import 'samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart'; +import 'samples/datagrid/columns/datagrid_stacked_header.dart'; import 'samples/datagrid/data_source/datagrid_json_data_source.dart'; import 'samples/datagrid/data_source/datagrid_list_data_source.dart'; -import 'samples/datagrid/getting_started/datagrid_getting_started.dart'; import 'samples/datagrid/freeze_panes/datagrid_freeze_panes.dart'; +import 'samples/datagrid/getting_started/datagrid_getting_started.dart'; +import 'samples/datagrid/loadmore/datagrid_infinite_scrolling.dart'; +import 'samples/datagrid/loadmore/datagrid_load_more.dart'; +import 'samples/datagrid/paging/datagrid_paging.dart'; +import 'samples/datagrid/pull_to_refresh/datagrid_pull_to_refresh.dart'; import 'samples/datagrid/real_time_update/datagrid_real_time_update.dart'; +import 'samples/datagrid/row_height/datagrid_row_height.dart'; import 'samples/datagrid/selection/datagrid_selection.dart'; -import 'samples/datagrid/apperance/styling/datagrid_styling.dart'; -import 'samples/datagrid/paging/datagrid_paging.dart'; import 'samples/datagrid/sorting/datagrid_sorting.dart'; -import 'samples/datagrid/columns/datagrid_stacked_header.dart'; -import 'samples/datagrid/loadmore/datagrid_infinite_scrolling.dart'; -import 'samples/datagrid/loadmore/datagrid_load_more.dart'; +import 'samples/datagrid/swiping/datagrid_swiping.dart'; import 'samples/date_picker/blackout_date_picker.dart'; import 'samples/date_picker/customized_date_picker.dart'; import 'samples/date_picker/date_picker_getting_started.dart'; @@ -208,19 +217,20 @@ import 'samples/gauge/annotation/direct_compass.dart'; import 'samples/gauge/annotation/temparature_tracker.dart'; import 'samples/gauge/annotation/text_annotation.dart'; import 'samples/gauge/axis_feature/custom_labels.dart'; +import 'samples/gauge/axis_feature/custom_scale.dart'; import 'samples/gauge/axis_feature/default_gauge_view.dart'; import 'samples/gauge/axis_feature/multiple_axis.dart'; -import 'samples/gauge/axis_feature/custom_scale.dart'; import 'samples/gauge/axis_feature/radial_label_customization.dart'; import 'samples/gauge/axis_feature/range_colors.dart'; import 'samples/gauge/axis_feature/tick_customization.dart'; import 'samples/gauge/export/export.dart'; import 'samples/gauge/pointer_interaction/radial_range_slider.dart'; import 'samples/gauge/pointer_interaction/radial_slider.dart'; +import 'samples/gauge/pointers/marker_pointer.dart'; import 'samples/gauge/pointers/multiple_needle.dart'; import 'samples/gauge/pointers/range_pointer.dart'; -import 'samples/gauge/pointers/marker_pointer.dart'; import 'samples/gauge/pointers/text_pointer.dart'; +import 'samples/gauge/pointers/widget_pointer.dart'; import 'samples/gauge/ranges/multiple_ranges.dart'; import 'samples/gauge/ranges/range_datalabels.dart'; import 'samples/gauge/ranges/range_thickness.dart'; @@ -228,46 +238,56 @@ import 'samples/gauge/showcase/clock_sample.dart'; import 'samples/gauge/showcase/distance_tracker.dart'; import 'samples/gauge/showcase/gauge_compass.dart'; import 'samples/gauge/showcase/temperature_monitor.dart'; +import 'samples/linear_gauge/api/api_customization.dart'; +import 'samples/linear_gauge/axis/axis_track.dart'; +import 'samples/linear_gauge/axis/label_customization.dart'; +import 'samples/linear_gauge/axis/tick_customization.dart'; +import 'samples/linear_gauge/pointers/bar_pointer.dart'; +import 'samples/linear_gauge/pointers/shape_pointer.dart'; +import 'samples/linear_gauge/pointers/widget_pointer.dart'; +import 'samples/linear_gauge/ranges/range_customization.dart'; +import 'samples/linear_gauge/showcase/battery_indicator.dart'; +import 'samples/linear_gauge/showcase/heat_meter.dart'; +import 'samples/linear_gauge/showcase/height_calculator.dart'; +import 'samples/linear_gauge/showcase/progress_bar.dart'; +import 'samples/linear_gauge/showcase/sleep_watch_score.dart'; +import 'samples/linear_gauge/showcase/steps_counter.dart'; +import 'samples/linear_gauge/showcase/task_tracker.dart'; +import 'samples/linear_gauge/showcase/thermometer.dart'; +import 'samples/linear_gauge/showcase/volume_settings.dart'; +import 'samples/linear_gauge/showcase/water_indicator.dart'; import 'samples/maps/shape_layer/bubble/bubble.dart'; import 'samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart'; +import 'samples/maps/shape_layer/legend/legend.dart'; import 'samples/maps/shape_layer/marker/marker.dart'; import 'samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart'; import 'samples/maps/shape_layer/selection/selection.dart'; +import 'samples/maps/shape_layer/sublayer/sublayer.dart'; import 'samples/maps/shape_layer/tooltip/tooltip.dart'; import 'samples/maps/shape_layer/zooming/zooming.dart'; -import 'samples/maps/shape_layer/sublayer/sublayer.dart'; -import 'samples/maps/shape_layer/legend/legend.dart'; -import 'samples/maps/tile_layer/osm/osm.dart'; import 'samples/maps/tile_layer/bing_map/bing_map.dart'; +import 'samples/maps/tile_layer/open_street_map/open_street_map.dart'; import 'samples/maps/tile_layer/vector_layer/arcs.dart'; +import 'samples/maps/tile_layer/vector_layer/polygon.dart'; import 'samples/maps/tile_layer/vector_layer/polylines.dart'; import 'samples/pdf/annotations.dart'; import 'samples/pdf/certificate.dart'; import 'samples/pdf/conformance.dart'; +import 'samples/pdf/digital_signature.dart'; import 'samples/pdf/encryption.dart'; import 'samples/pdf/find_text.dart'; +import 'samples/pdf/form.dart'; import 'samples/pdf/header_and_footer.dart'; import 'samples/pdf/invoice.dart'; import 'samples/pdf/text_extraction.dart'; -import 'samples/xlsio/expenses_report/expenses_report.dart'; -import 'samples/xlsio/invoice/invoice.dart'; -import 'samples/xlsio/yearly_sales/yearly_sales.dart'; -import 'samples/xlsio/balance_sheet/balance_sheet.dart'; -import 'samples/pdf_viewer/pdf_viewer_getting_started.dart'; import 'samples/pdf_viewer/pdf_viewer_custom_toolbar.dart'; +import 'samples/pdf_viewer/pdf_viewer_getting_started.dart'; import 'samples/progress_bar/angles.dart'; import 'samples/progress_bar/custom_labels.dart'; import 'samples/progress_bar/determinate_styles.dart'; import 'samples/progress_bar/segment_styles.dart'; import 'samples/progress_bar/track_with_marker.dart'; import 'samples/progress_bar/types.dart'; -import 'samples/radial_slider/basic_features/angles.dart'; -import 'samples/radial_slider/basic_features/labels_and_ticks.dart'; -import 'samples/radial_slider/basic_features/state.dart'; -import 'samples/radial_slider/customization/custom_text.dart'; -import 'samples/radial_slider/customization/gradient.dart'; -import 'samples/radial_slider/customization/styles.dart'; -import 'samples/radial_slider/customization/thumb.dart'; import 'samples/radial_range_slider/basic_features/angles.dart'; import 'samples/radial_range_slider/basic_features/labels_and_ticks.dart'; import 'samples/radial_range_slider/basic_features/state.dart'; @@ -275,17 +295,25 @@ import 'samples/radial_range_slider/customization/custom_text.dart'; import 'samples/radial_range_slider/customization/gradient.dart'; import 'samples/radial_range_slider/customization/styles.dart'; import 'samples/radial_range_slider/customization/thumb.dart'; +import 'samples/radial_slider/basic_features/angles.dart'; +import 'samples/radial_slider/basic_features/labels_and_ticks.dart'; +import 'samples/radial_slider/basic_features/state.dart'; +import 'samples/radial_slider/customization/custom_text.dart'; +import 'samples/radial_slider/customization/gradient.dart'; +import 'samples/radial_slider/customization/styles.dart'; +import 'samples/radial_slider/customization/thumb.dart'; +import 'samples/signature_pad/getting_started/signature_pad_getting_started.dart'; import 'samples/sliders/range_selector/range_selector_default_appearance.dart'; +import 'samples/sliders/range_selector/range_selector_with_bar_chart.dart'; +import 'samples/sliders/range_selector/range_selector_with_histogram_chart.dart'; import 'samples/sliders/range_selector/range_selector_with_selection.dart'; import 'samples/sliders/range_selector/range_selector_with_zooming.dart'; -import 'samples/sliders/range_selector/range_selector_with_histogram_chart.dart'; -import 'samples/sliders/range_selector/range_selector_with_bar_chart.dart'; import 'samples/sliders/range_slider/customization/color_customization/color_customization.dart'; import 'samples/sliders/range_slider/customization/shape_customization/shape_customization.dart'; import 'samples/sliders/range_slider/customization/size_customization/size_customization.dart'; import 'samples/sliders/range_slider/customization/thumb_customization/range_slider_thumb_icon_customization.dart'; -import 'samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart'; import 'samples/sliders/range_slider/default_appearance/range_slider_date_time_label.dart'; +import 'samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart'; import 'samples/sliders/range_slider/default_appearance/range_slider_divisor_label_tick.dart'; import 'samples/sliders/range_slider/default_appearance/range_slider_interval_selection.dart'; import 'samples/sliders/range_slider/default_appearance/range_slider_step.dart'; @@ -299,7 +327,41 @@ import 'samples/sliders/slider/customization/color_customization/slider_color_cu import 'samples/sliders/slider/customization/shape_customization/slider_shape_customization.dart'; import 'samples/sliders/slider/customization/size_customization/slider_size_customization.dart'; import 'samples/sliders/slider/customization/thumb_customization/thumb_icon_customization.dart'; -import 'samples/signature_pad/getting_started/signature_pad_getting_started.dart'; +import 'samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_color_customization.dart'; +import 'samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_shape_customization.dart'; +import 'samples/sliders/vertical_range_slider/customization/size_customization/vertical_range_slider_size_customization.dart'; +import 'samples/sliders/vertical_range_slider/customization/thumb_customization/vertical_range_slider_thumb_icon_customization.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_date_time_label.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_default_appearance.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_divisor_label_tick.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_interval_selection.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_step.dart'; +import 'samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart'; +import 'samples/sliders/vertical_slider/basic_features/default_vertical_slider.dart'; +import 'samples/sliders/vertical_slider/basic_features/vertical_slider_date_interval.dart'; +import 'samples/sliders/vertical_slider/basic_features/vertical_slider_divisor_label_tick.dart'; +import 'samples/sliders/vertical_slider/basic_features/vertical_slider_step.dart'; +import 'samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart'; +import 'samples/sliders/vertical_slider/customization/color_customization/vertical_slider_color_customization.dart'; +import 'samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_shape_customization.dart'; +import 'samples/sliders/vertical_slider/customization/size_customization/vertical_slider_size_customization.dart'; +import 'samples/sliders/vertical_slider/customization/thumb_customization/vertical_slider_thumb_icon_customization.dart'; +import 'samples/sparkline/axis_types.dart'; +import 'samples/sparkline/chart_types.dart'; +import 'samples/sparkline/customization.dart'; +import 'samples/sparkline/live_update.dart'; +import 'samples/sparkline/sparkline_in_grid.dart'; +import 'samples/treemap/custom_background/custom_background.dart'; +import 'samples/treemap/flat/flat.dart'; +import 'samples/treemap/hierarchical/hierarchical.dart'; +import 'samples/treemap/range_color_mapping/range_color_mapping.dart'; +import 'samples/treemap/selection/selection.dart'; +import 'samples/treemap/value_color_mapping/value_color_mapping.dart'; +import 'samples/xlsio/attendance_tracker/attendance_tracker.dart'; +import 'samples/xlsio/balance_sheet/balance_sheet.dart'; +import 'samples/xlsio/expenses_report/expenses_report.dart'; +import 'samples/xlsio/invoice/invoice.dart'; +import 'samples/xlsio/yearly_sales/yearly_sales.dart'; /// Contains the output widget of sample /// appropriate key and output widget mapped @@ -374,6 +436,9 @@ Map getSampleWidget() { 'category_label_placement': (Key key) => CategoryTicks(key), 'default_datetime_axis': (Key key) => DateTimeDefault(key), 'datetime_axis_with_label_format': (Key key) => DateTimeLabel(key), + 'default_datetime_category_axis': (Key key) => DateTimeCategoryDefault(key), + 'default_datetime_category_axis_label': (Key key) => + DateTimeCategoryLabel(key), 'default_logarithmic_axis': (Key key) => LogarithmicAxisDefault(key), 'inversed_logarithmic_axis': (Key key) => LogarithmicAxisInversed(key), 'hilo_chart': (Key key) => HiloChart(key), @@ -444,6 +509,8 @@ Map getSampleWidget() { 'events': (Key key) => Events(key), 'navigate_with_events': (Key key) => NavigationWithEvents(key), 'chart_interactivity': (Key key) => InteractiveChart(key), + 'pagination': (Key key) => Pagination(key), + 'auto_scrolling': (Key key) => AutoScrollingChart(key), //Dynamic updates 'add_remove_points': (Key key) => AddDataPoints(key), @@ -462,23 +529,30 @@ Map getSampleWidget() { 'local_list_data': (Key key) => LocalData(key), 'local_json_data': (Key key) => JsonData(key), + //On demand loading + 'infinite_scrolling': (Key key) => InfiniteScrolling(key), //Pie 'default_pie_chart': (Key key) => PieDefault(key), 'pie_with_grouping': (Key key) => PieGrouping(key), 'pie_with_smart_labels': (Key key) => PieSmartLabels(key), 'pie_with_various_radius': (Key key) => PieRadius(key), 'semi_pie_chart': (Key key) => SemiPieChart(key), + 'pie_with_gradient': (Key key) => PieGradient(key), + 'pie_with_imageShader': (Key key) => PieImageShader(key), + 'pie_point_render_mode': (Key key) => PiePointRenderMode(key), //Doughnut 'default_doughnut_chart': (Key key) => DoughnutDefault(key), 'doughnut_with_center_elevation': (Key key) => DoughnutElevation(key), 'doughnut_with_color_mapping': (Key key) => DoughnutCustomization(key), 'doughnut_with_rounded_corners': (Key key) => DoughnutRounded(key), 'semi_doughnut_chart': (Key key) => SemiDoughnutChart(key), + 'doughnut_with_gradient': (Key key) => DoughnutGradient(key), //Radialbar 'customized_radialbar_chart': (Key key) => RadialBarCustomized(key), 'default_radialbar_chart': (Key key) => RadialBarDefault(key), 'radialbar_with_legend': (Key key) => RadialBarAngle(key), + 'radialbar_with_gradient': (Key key) => RadialBarGradient(key), //Funnel 'default_funnel_chart': (Key key) => FunnelDefault(key), @@ -509,6 +583,7 @@ Map getSampleWidget() { 'timeline_views_calendar': (Key key) => TimelineViewsCalendar(key), 'heat_map_calendar': (Key key) => HeatMapCalendar(key), 'air_fare_calendar': (Key key) => AirFareCalendar(key), + 'loadmore_calendar': (Key key) => LoadMoreCalendar(key), // Date picker Samples 'getting_started_date_picker': (Key key) => GettingStartedDatePicker(key), @@ -542,6 +617,7 @@ Map getSampleWidget() { 'range_pointer': (Key key) => RangePointerExample(key), 'radial_marker': (Key key) => MarkerPointerExample(key), 'text_pointer': (Key key) => RadialTextPointer(key), + 'radial_widget_pointer': (Key key) => WidgetPointerExample(key), 'multiple_ranges': (Key key) => MultipleRangesExample(key), 'range_datalabels': (Key key) => RangeDataLabelExample(key), 'range_thickness': (Key key) => RangeThicknessExample(key), @@ -551,6 +627,26 @@ Map getSampleWidget() { 'gauge_overview': (Key key) => GaugeTemperatureMonitorExample(key), 'gauge_compass': (Key key) => GaugeCompassExample(key), + // Linear gauge + 'axis_track': (Key key) => AxisTrack(key), + 'ticks_customization': (Key key) => TickCustomization(key), + 'label_customization': (Key key) => GaugeLabelCustomization(key), + 'shape_pointer': (Key key) => ShapePointer(key), + 'bar_pointer': (Key key) => BarPointer(key), + 'widget_pointer': (Key key) => WidgetPointer(key), + 'custom_range': (Key key) => RangeCustomization(key), + 'battery_indicator': (Key key) => BatteryIndicator(key), + 'progress_bar': (Key key) => ProgressBar(key), + 'volume_settings': (Key key) => VolumeSettings(key), + 'sleep_watch': (Key key) => SleepWatch(key), + 'task_tracker': (Key key) => TaskTracking(key), + 'steps_counter': (Key key) => StepsCounter(key), + 'height_calculator': (Key key) => HeightCalculator(key), + 'water_indicator': (Key key) => WaterLevelIndicator(key), + 'thermometer': (Key key) => Thermometer(key), + 'heat_meter': (Key key) => HeatMeter(key), + 'api_gauge': (Key key) => ApiCustomization(key), + // PDF samples 'invoice': (Key key) => InvoicePdf(key), 'certificate': (Key key) => CourseCompletionCertificatePdf(key), @@ -560,6 +656,8 @@ Map getSampleWidget() { 'find_text': (Key key) => FindTextPdf(key), 'encryption': (Key key) => EncryptPdf(key), 'conformance': (Key key) => ConformancePdf(key), + 'form': (Key key) => FormFillingPdf(key), + 'digital_signature': (Key key) => SignPdf(key), // PDF Viewer samples 'pdf_viewer_getting_started': (Key key) => GettingStartedPdfViewer(key), @@ -570,6 +668,7 @@ Map getSampleWidget() { 'invoice_excel': (Key key) => InvoiceXlsIO(key), 'yearly_sales': (Key key) => YearlySalesXlsIO(key), 'balance_sheet': (Key key) => BalanceSheetXlsIO(key), + 'attendance_tracker': (Key key) => AttendanceTrackerXlsIO(key), // Barcode samples 'one_dimensional_types': (Key key) => OneDimensionalBarcodes(key: key), @@ -621,6 +720,64 @@ Map getSampleWidget() { 'size_customization': (Key key) => SfRangeSliderSizeCustomizationPage(key), + //Vertical Slider samples + 'default_vertical_slider': (Key key) => DefaultVerticalSliderPage(key), + + 'vertical_slider_date_interval': (Key key) => + VerticalDateIntervalSliderPage(key), + + 'vertical_slider_divisor_label_tick': (Key key) => + VerticalSliderLabelCustomizationPage(key), + + 'vertical_slider_step': (Key key) => VerticalStepSliderPage(key), + + 'vertical_slider_tooltip_position': (Key key) => + VerticalSliderTooltipTypeSliderPage(key), + + 'vertical_slider_color_customization': (Key key) => + VerticalSliderColorCustomizationPage(key), + + 'vertical_slider_size_customization': (Key key) => + VerticalSliderSizeCustomizationPage(key), + + 'vertical_thumb_icon_customization': (Key key) => + VerticalThumbCustomizationSliderPage(key), + + 'vertical_slider_shape_customization': (Key key) => + VerticalShapeCustomizedSliderPage(key), + + //Vertical Range Slider Samples + + 'vertical_range_slider_default_appearance': (Key key) => + VerticalDefaultRangeSliderPage(key), + + 'vertical_range_slider_divisor_label_tick': (Key key) => + VerticalScaleRangeSliderPage(key), + + 'vertical_range_slider_date_time_label': (Key key) => + VerticalDateRangeSliderPage(key), + + 'vertical_range_slider_step': (Key key) => + VerticalSliderStepDurationPage(key), + + 'vertical_range_slider_interval_selection': (Key key) => + VerticalRangeSliderIntervalSelectionPage(key), + + 'vertical_range_slider_tooltip_position': (Key key) => + VerticalTooltipRangeSliderPage(key), + + 'vertical_range_slider_thumb_icon_customization': (Key key) => + VerticalThumbCustomizationRangeSliderPage(key), + + 'vertical_range_slider_color_customization': (Key key) => + VerticalColorCustomizedRangeSliderPage(key), + + 'vertical_range_slider_shape_customization': (Key key) => + VerticalShapeCustomizedRangeSliderPage(key), + + 'vertical_range_slider_size_customization': (Key key) => + VerticalSfRangeSliderSizeCustomizationPage(key), + // Range Selector Samples 'range_selector_default_appearance': (Key key) => DefaultRangeSelectorPage(key), @@ -647,7 +804,7 @@ Map getSampleWidget() { 'styling_datagrid': (Key key) => StylingDataGrid(key: key), - 'auto_row_height_datagrid': (Key key) => AutoRowHeightDataGrid(key: key), + 'row_height_datagrid': (Key key) => RowHeightDataGrid(key: key), 'conditional_styling_datagrid': (Key key) => ConditionalStylingDataGrid(key: key), @@ -671,7 +828,11 @@ Map getSampleWidget() { 'load_more_datagrid': (Key key) => LoadMoreDataGrid(key: key), - //Maps: Shape Layer Samples + 'pull_to_refresh_datagrid': (Key key) => PullToRefreshDataGrid(key: key), + + 'swiping_datagrid': (Key key) => SwipingDataGrid(key: key), + + // Maps: Shape Layer Samples 'range_color_mapping': (Key key) => MapRangeColorMappingPage(key), 'equal_color_mapping': (Key key) => MapEqualColorMappingPage(key), @@ -690,8 +851,8 @@ Map getSampleWidget() { 'sublayer': (Key key) => MapSublayerPage(key), - //Maps: Tile Layer Samples - 'osm': (Key key) => MapOSMPage(key), + // Maps: Tile Layer Samples + 'open_street_map': (Key key) => MapOSMPage(key), 'bing_map': (Key key) => MapBingPage(key), @@ -699,7 +860,9 @@ Map getSampleWidget() { 'polylines': (Key key) => MapPolylinesPage(key), - //SignaturePad + 'polygon': (Key key) => MapPolygonPage(key), + + // SignaturePad 'signature_pad_getting_started': (Key key) => GettingStartedSignaturePad(key), @@ -731,6 +894,22 @@ Map getSampleWidget() { RadialRangeSliderCustomText(key), 'radial_range_slider_gradient': (Key key) => RadialRangeSliderGradient(key), 'radial_range_slider_styles': (Key key) => RadialRangeSliderStyles(key), - 'radial_range_slider_thumb': (Key key) => RadialRangeSliderThumb(key) + 'radial_range_slider_thumb': (Key key) => RadialRangeSliderThumb(key), + + //Treemap + 'squarified_treemap_flat': (Key key) => + TreemapLayoutSample(key, LayoutType.squarified), + 'slice_treemap_flat': (Key key) => + TreemapLayoutSample(key, LayoutType.slice), + 'dice_treemap_flat': (Key key) => TreemapLayoutSample(key, LayoutType.dice), + 'squarified_treemap_hierarchical': (Key key) => + HierarchicalTreemapSample(key), + 'squarified_range_color_mapping': (Key key) => + TreemapRangeColorMappingSample(key), + 'squarified_value_color_mapping': (Key key) => + TreemapValueColorMappingSample(key), + 'squarified_treemap_custom_background': (Key key) => + TreemapCustomBackgroundSample(key), + 'squarified_treemap_selection': (Key key) => TreemapSelectionSample(key), }; } diff --git a/lib/samples/barcodes/data_matrix.dart b/lib/samples/barcodes/data_matrix.dart index 56056274..3bf17e4d 100644 --- a/lib/samples/barcodes/data_matrix.dart +++ b/lib/samples/barcodes/data_matrix.dart @@ -18,9 +18,9 @@ class DataMatrixGenerator extends SampleView { class _DataMatrixGeneratorState extends SampleViewState { _DataMatrixGeneratorState(); - String _inputValue; + late String _inputValue; - TextEditingController _textEditingController; + late TextEditingController _textEditingController; @override void initState() { @@ -28,7 +28,7 @@ class _DataMatrixGeneratorState extends SampleViewState { _inputValue = 'http://www.syncfusion.com'; _textEditingController = TextEditingController.fromValue( TextEditingValue( - text: model.isWeb ? 'http://www.syncfusion.com' : _inputValue, + text: model.isWebFullView ? 'http://www.syncfusion.com' : _inputValue, ), ); } @@ -40,20 +40,22 @@ class _DataMatrixGeneratorState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { EdgeInsets _padding = const EdgeInsets.all(0); double _margin; - if (!model.isWeb) { + if (!model.isWebFullView) { _margin = (MediaQuery.of(context).size.width - MediaQuery.of(context).size.width * 0.6) / 2; _padding = EdgeInsets.fromLTRB(_margin, 0, _margin, 0); } return Scaffold( - backgroundColor: model.isWeb ? Colors.transparent : model.cardThemeColor, + backgroundColor: + model.isWebFullView ? Colors.transparent : model.cardThemeColor, body: Padding( padding: const EdgeInsets.fromLTRB(5, 0, 5, 5), - child: Container(child: _getDataMatrixGenerator(_inputValue, _padding)), + child: + Container(child: _buildDataMatrixGenerator(_inputValue, _padding)), ), ); } @@ -106,14 +108,14 @@ class _DataMatrixGeneratorState extends SampleViewState { } /// Returns the data matrix barcode generator - Widget _getDataMatrixGenerator([String _inputValue, EdgeInsets _padding]) { + Widget _buildDataMatrixGenerator(String _inputValue, EdgeInsets _padding) { return Center( child: Container( - height: model.isWeb ? 300 : double.infinity, + height: model.isWebFullView ? 300 : double.infinity, child: Padding( - padding: _padding ?? const EdgeInsets.all(30), + padding: _padding, child: SfBarcodeGenerator( - value: _inputValue ?? 'http://www.syncfusion.com', + value: _inputValue, textAlign: TextAlign.justify, textSpacing: 10, showValue: false, diff --git a/lib/samples/barcodes/one_dimensional.dart b/lib/samples/barcodes/one_dimensional.dart index e1edeac4..13d9fadf 100644 --- a/lib/samples/barcodes/one_dimensional.dart +++ b/lib/samples/barcodes/one_dimensional.dart @@ -10,7 +10,7 @@ import '../../model/sample_view.dart'; /// Widget of the one dimensional barcodes. class OneDimensionalBarcodes extends SampleView { /// Creates one dimensional barcodes. - const OneDimensionalBarcodes({Key key}) : super(key: key); + const OneDimensionalBarcodes({Key? key}) : super(key: key); @override _OneDimensionalBarcodesState createState() => _OneDimensionalBarcodesState(); } @@ -19,7 +19,7 @@ class _OneDimensionalBarcodesState extends SampleViewState { _OneDimensionalBarcodesState(); @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { EdgeInsets _padding = const EdgeInsets.fromLTRB(0, 20, 0, 0); if (MediaQuery.of(context).orientation == Orientation.portrait) { _padding = const EdgeInsets.fromLTRB(0, 20, 0, 0); @@ -31,7 +31,8 @@ class _OneDimensionalBarcodesState extends SampleViewState { _padding = EdgeInsets.fromLTRB(_margin, 20, _margin, 0); } return Scaffold( - backgroundColor: model.isWeb ? Colors.transparent : model.cardThemeColor, + backgroundColor: + model.isWebFullView ? Colors.transparent : model.cardThemeColor, body: Padding( padding: const EdgeInsets.fromLTRB(5, 0, 5, 5), child: Padding( @@ -48,12 +49,12 @@ class _OneDimensionalBarcodesState extends SampleViewState { child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, - children: _getSampleWidget(context)), + children: _buildSampleWidget(context)), ); } /// Returns the one dimensional barcodes for web view. - List _getWidgetForWeb(BuildContext context) { + List _buildWidgetForWeb(BuildContext context) { final ThemeData _themeData = Theme.of(context); final Color _color = _themeData.brightness == Brightness.dark ? const Color(0xFF666666) @@ -297,7 +298,7 @@ class _OneDimensionalBarcodesState extends SampleViewState { textSpacing: 3, value: '123456', showValue: true, - symbology: UPCE(module: model.isWeb ? 2 : 1), + symbology: UPCE(module: model.isWebFullView ? 2 : 1), )), )), ), @@ -582,7 +583,7 @@ class _OneDimensionalBarcodesState extends SampleViewState { } /// Returns the one dimensional barcodes for mobile view. - List _getWidgetForMobile(BuildContext context) { + List _buildWidgetForMobile(BuildContext context) { final ThemeData _themeData = Theme.of(context); final Color _color = _themeData.brightness == Brightness.dark ? const Color(0xFF666666) @@ -812,7 +813,6 @@ class _OneDimensionalBarcodesState extends SampleViewState { child: Container( child: SfBarcodeGenerator( textAlign: TextAlign.justify, - // backgroundColor: Colors.red, textSpacing: 3, value: '123456', showValue: true, @@ -855,7 +855,6 @@ class _OneDimensionalBarcodesState extends SampleViewState { child: Container( child: SfBarcodeGenerator( textAlign: TextAlign.justify, - // backgroundColor: Colors.red, textSpacing: 3, value: '11223344', showValue: true, @@ -1096,9 +1095,9 @@ class _OneDimensionalBarcodesState extends SampleViewState { ]; } - List _getSampleWidget(BuildContext context) { - return model.isWeb - ? _getWidgetForWeb(context) - : _getWidgetForMobile(context); + List _buildSampleWidget(BuildContext context) { + return model.isWebFullView + ? _buildWidgetForWeb(context) + : _buildWidgetForMobile(context); } } diff --git a/lib/samples/barcodes/qr_code.dart b/lib/samples/barcodes/qr_code.dart index 78617ec0..216ee797 100644 --- a/lib/samples/barcodes/qr_code.dart +++ b/lib/samples/barcodes/qr_code.dart @@ -31,12 +31,12 @@ class _QRCodeGeneratorState extends SampleViewState { 'Low' ]; - ErrorCorrectionLevel _errorCorrectionLevel; - String _selectedErrorCorrectionLevel; - QRInputMode _inputMode; - String _selectedInputMode; - String _inputValue; - TextEditingController _textEditingController; + late ErrorCorrectionLevel _errorCorrectionLevel; + late String _selectedErrorCorrectionLevel; + late QRInputMode _inputMode; + late String _selectedInputMode; + late String _inputValue; + late TextEditingController _textEditingController; @override void initState() { @@ -48,7 +48,7 @@ class _QRCodeGeneratorState extends SampleViewState { _inputMode = QRInputMode.binary; _textEditingController = TextEditingController.fromValue( TextEditingValue( - text: model.isWeb ? 'http://www.syncfusion.com' : _inputValue, + text: model.isWebFullView ? 'http://www.syncfusion.com' : _inputValue, ), ); } @@ -60,10 +60,10 @@ class _QRCodeGeneratorState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { EdgeInsets _padding = const EdgeInsets.all(0); double _margin; - if (!model.isWeb) { + if (!model.isWebFullView) { _margin = (MediaQuery.of(context).size.width - MediaQuery.of(context).size.width * 0.6) / 2; @@ -71,11 +71,12 @@ class _QRCodeGeneratorState extends SampleViewState { } return Scaffold( - backgroundColor: model.isWeb ? Colors.transparent : model.cardThemeColor, + backgroundColor: + model.isWebFullView ? Colors.transparent : model.cardThemeColor, body: Padding( padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), child: Container( - child: _getQRCodeGenerator( + child: _buildQRCodeGenerator( _inputValue, _errorCorrectionLevel, _inputMode, _padding)), ), ); @@ -164,7 +165,7 @@ class _QRCodeGeneratorState extends SampleViewState { style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onInputModeChanged(value.toString()); stateSetter(() {}); }), @@ -207,7 +208,7 @@ class _QRCodeGeneratorState extends SampleViewState { style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onErrorCorrectionLevelChanged(value.toString()); stateSetter(() {}); }), @@ -263,26 +264,25 @@ class _QRCodeGeneratorState extends SampleViewState { } /// Returns the QR barcode - Widget _getQRCodeGenerator( - [String _inputValue, + Widget _buildQRCodeGenerator( + String _inputValue, ErrorCorrectionLevel _correctionLevel, QRInputMode _inputMode, - EdgeInsets _padding]) { + EdgeInsets _padding) { return Center( child: Container( - height: model.isWeb ? 300 : double.infinity, + height: model.isWebFullView ? 300 : double.infinity, child: Padding( - padding: _padding ?? const EdgeInsets.all(30), + padding: _padding, child: SfBarcodeGenerator( - value: _inputValue ?? 'http://www.syncfusion.com', + value: _inputValue, textAlign: TextAlign.justify, textSpacing: 10, showValue: false, symbology: QRCode( - inputMode: _inputMode ?? QRInputMode.binary, + inputMode: _inputMode, codeVersion: QRCodeVersion.auto, - errorCorrectionLevel: - _correctionLevel ?? ErrorCorrectionLevel.quartile), + errorCorrectionLevel: _correctionLevel), ), )), ); diff --git a/lib/samples/calendar/agenda_view.dart b/lib/samples/calendar/agenda_view.dart index 7c61d348..5ffb7adc 100644 --- a/lib/samples/calendar/agenda_view.dart +++ b/lib/samples/calendar/agenda_view.dart @@ -13,7 +13,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class AgendaViewCalendar extends SampleView { - /// Cr + /// Create default agenda view calendar const AgendaViewCalendar(Key key) : super(key: key); @override @@ -23,13 +23,12 @@ class AgendaViewCalendar extends SampleView { class _AgendaViewCalendarState extends SampleViewState { _AgendaViewCalendarState(); - _MeetingDataSource _events; - CalendarController _calendarController; - Orientation _deviceOrientation; + late _MeetingDataSource _events; + final CalendarController _calendarController = CalendarController(); + late Orientation _deviceOrientation; @override void initState() { - _calendarController = CalendarController(); _calendarController.selectedDate = DateTime.now(); _events = _MeetingDataSource(_getAppointments()); super.initState(); @@ -69,7 +68,7 @@ class _AgendaViewCalendarState extends SampleViewState { /// required information. List<_Meeting> _getAppointments() { /// Creates the required appointment subject details as a list. - List subjectCollection = []; + final List subjectCollection = []; subjectCollection.add('General Meeting'); subjectCollection.add('Plan Execution'); subjectCollection.add('Project Plan'); @@ -82,7 +81,7 @@ class _AgendaViewCalendarState extends SampleViewState { subjectCollection.add('Performance Check'); /// Creates the required appointment color details as a list. - List colorCollection = []; + final List colorCollection = []; colorCollection.add(const Color(0xFF0F8644)); colorCollection.add(const Color(0xFF8B1FA9)); colorCollection.add(const Color(0xFFD20100)); @@ -142,10 +141,10 @@ class _AgendaViewCalendarState extends SampleViewState { /// current date when the calendar displays the current month, and selects the /// first date of the month for rest of the months. void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { - SchedulerBinding.instance.addPostFrameCallback((_) { + SchedulerBinding.instance?.addPostFrameCallback((_) { final DateTime currentViewDate = visibleDatesChangedDetails .visibleDates[visibleDatesChangedDetails.visibleDates.length ~/ 2]; - if (model.isWeb) { + if (model.isWebFullView) { if (DateTime.now() .isAfter(visibleDatesChangedDetails.visibleDates[0]) && DateTime.now().isBefore(visibleDatesChangedDetails.visibleDates[ @@ -169,18 +168,18 @@ class _AgendaViewCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getAgendaViewCalendar( - [CalendarDataSource calendarDataSource, - ViewChangedCallback onViewChanged, - CalendarController controller]) { + [CalendarDataSource? calendarDataSource, + ViewChangedCallback? onViewChanged, + CalendarController? controller]) { return SfCalendar( view: CalendarView.month, controller: controller, showDatePickerButton: true, - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, onViewChanged: onViewChanged, dataSource: calendarDataSource, monthViewSettings: MonthViewSettings( - showAgenda: true, numberOfWeeksInView: model.isWeb ? 2 : 6), + showAgenda: true, numberOfWeeksInView: model.isWebFullView ? 2 : 6), timeSlotViewSettings: TimeSlotViewSettings( minimumAppointmentDuration: const Duration(minutes: 60)), ); @@ -219,12 +218,12 @@ class _MeetingDataSource extends CalendarDataSource { } @override - String getStartTimeZone(int index) { + String? getStartTimeZone(int index) { return source[index].startTimeZone; } @override - String getEndTimeZone(int index) { + String? getEndTimeZone(int index) { return source[index].endTimeZone; } @@ -234,7 +233,7 @@ class _MeetingDataSource extends CalendarDataSource { } @override - String getRecurrenceRule(int index) { + String? getRecurrenceRule(int index) { return source[index].recurrenceRule; } } @@ -256,14 +255,14 @@ class _Meeting { this.recurrenceRule); String eventName; - String organizer; - String contactID; - int capacity; + String? organizer; + String? contactID; + int? capacity; DateTime from; DateTime to; Color background; bool isAllDay; - String startTimeZone; - String endTimeZone; - String recurrenceRule; + String? startTimeZone; + String? endTimeZone; + String? recurrenceRule; } diff --git a/lib/samples/calendar/airfare.dart b/lib/samples/calendar/airfare.dart index 836e4b31..93a3f917 100644 --- a/lib/samples/calendar/airfare.dart +++ b/lib/samples/calendar/airfare.dart @@ -14,7 +14,7 @@ import 'package:syncfusion_flutter_core/core.dart'; import '../../model/sample_view.dart'; /// Smallest fare value -const String _kBestPrice = "\$100.17"; +const String _kBestPrice = '\$100.17'; /// Widget of air fare calendar class AirFareCalendar extends SampleView { @@ -29,26 +29,20 @@ class AirFareCalendar extends SampleView { class _AirFareCalendarCalendarState extends SampleViewState { _AirFareCalendarCalendarState(); - ScrollController _controller; - List _airFareDataCollection; - List _airlineId; - List _fares; - DateTime _minDate; + final ScrollController _controller = ScrollController(); + List _airFareDataCollection = []; + final List _airlineId = [1, 2, 3, 4]; + final List _fares = []; + final DateTime _minDate = DateTime.now(); /// Global key used to maintain the state, when we change the parent of the /// widget - GlobalKey _globalKey; - double _screenHeight; - Orientation _deviceOrientation; + final GlobalKey _globalKey = GlobalKey(); + late double _screenHeight; + late Orientation _deviceOrientation; @override void initState() { - _globalKey = GlobalKey(); - _controller = ScrollController(); - _airFareDataCollection = []; - _airlineId = []; - _fares = []; - _minDate = DateTime.now(); _addFareDataDetails(); _addAirFareData(); super.initState(); @@ -56,40 +50,39 @@ class _AirFareCalendarCalendarState extends SampleViewState { /// Creates required data for the air fare data. void _addFareDataDetails() { - _airlineId = [1, 2, 3, 4]; - _fares.add("\$134.50"); - _fares.add("\$305.00"); - _fares.add("\$152.66"); - _fares.add("\$267.09"); - _fares.add("\$189.20"); - _fares.add("\$212.10"); - _fares.add("\$350.50"); - _fares.add("\$222.39"); - _fares.add("\$238.83"); - _fares.add("\$147.27"); - _fares.add("\$115.43"); - _fares.add("\$198.06"); - _fares.add("\$189.83"); - _fares.add("\$110.71"); - _fares.add("\$152.10"); - _fares.add("\$199.62"); - _fares.add("\$146.15"); - _fares.add("\$237.04"); - _fares.add("\$100.17"); - _fares.add("\$101.72"); - _fares.add("\$266.69"); - _fares.add("\$332.48"); - _fares.add("\$256.77"); - _fares.add("\$449.68"); - _fares.add("\$100.17"); - _fares.add("\$153.31"); - _fares.add("\$249.92"); - _fares.add("\$254.59"); - _fares.add("\$332.48"); - _fares.add("\$256.77"); - _fares.add("\$449.68"); - _fares.add("\$107.18"); - _fares.add("\$219.04"); + _fares.add('\$134.50'); + _fares.add('\$305.00'); + _fares.add('\$152.66'); + _fares.add('\$267.09'); + _fares.add('\$189.20'); + _fares.add('\$212.10'); + _fares.add('\$350.50'); + _fares.add('\$222.39'); + _fares.add('\$238.83'); + _fares.add('\$147.27'); + _fares.add('\$115.43'); + _fares.add('\$198.06'); + _fares.add('\$189.83'); + _fares.add('\$110.71'); + _fares.add('\$152.10'); + _fares.add('\$199.62'); + _fares.add('\$146.15'); + _fares.add('\$237.04'); + _fares.add('\$100.17'); + _fares.add('\$101.72'); + _fares.add('\$266.69'); + _fares.add('\$332.48'); + _fares.add('\$256.77'); + _fares.add('\$449.68'); + _fares.add('\$100.17'); + _fares.add('\$153.31'); + _fares.add('\$249.92'); + _fares.add('\$254.59'); + _fares.add('\$332.48'); + _fares.add('\$256.77'); + _fares.add('\$449.68'); + _fares.add('\$107.18'); + _fares.add('\$219.04'); } /// Returns color for the airplane data. @@ -128,7 +121,8 @@ class _AirFareCalendarCalendarState extends SampleViewState { super.didChangeDependencies(); } - Widget build([BuildContext context]) { + @override + Widget build(BuildContext context) { final Widget calendar = Theme( /// The key set here to maintain the state, @@ -141,7 +135,7 @@ class _AirFareCalendarCalendarState extends SampleViewState { body: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: (model.isWeb && _screenHeight < 800) || + child: (model.isWebFullView && _screenHeight < 800) || _deviceOrientation == Orientation.landscape ? Scrollbar( isAlwaysShown: true, @@ -165,7 +159,7 @@ class _AirFareCalendarCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getAirFareCalendar() { return SfCalendar( - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, view: CalendarView.month, monthCellBuilder: _monthCellBuilder, showDatePickerButton: true, @@ -176,7 +170,7 @@ class _AirFareCalendarCalendarState extends SampleViewState { /// Returns the builder for month cell. Widget _monthCellBuilder( BuildContext buildContext, MonthCellDetails details) { - Random random = Random(); + final Random random = Random(); final bool isToday = isSameDate(details.date, DateTime.now()); final AirFare airFare = _airFareDataCollection[random.nextInt(100)]; final Color defaultColor = @@ -266,9 +260,15 @@ class _AirFareCalendarCalendarState extends SampleViewState { /// Object to hold the air fare data. class AirFare { + /// Holds the data of air fares const AirFare(this.fare, this.color, this.airline); + /// holds the string fare data final String fare; + + /// Color of the fare final Color color; + + /// Holds string of airline final String airline; } diff --git a/lib/samples/calendar/appointment_editor.dart b/lib/samples/calendar/appointment_editor.dart index 6ec1b4a3..08918c86 100644 --- a/lib/samples/calendar/appointment_editor.dart +++ b/lib/samples/calendar/appointment_editor.dart @@ -9,6 +9,7 @@ import 'package:intl/intl.dart'; ///calendar import import 'package:syncfusion_flutter_calendar/calendar.dart'; +import 'package:syncfusion_flutter_core/core.dart'; ///Local import import '../../model/model.dart'; @@ -28,19 +29,17 @@ class CalendarAppointmentEditor extends SampleView { class _CalendarAppointmentEditorState extends SampleViewState { _CalendarAppointmentEditorState(); - List _subjectCollection; - List _appointments; - bool _isMobile; + late List _subjectCollection; + late List _appointments; + late bool _isMobile; - List _colorCollection; - List _colorNames; + late List _colorCollection; + late List _colorNames; int _selectedColorIndex = 0; - List _timeZoneCollection; - _DataSource _events; - Appointment _selectedAppointment; - DateTime _startDate; - DateTime _endDate; - bool _isAllDay; + late List _timeZoneCollection; + late _DataSource _events; + Appointment? _selectedAppointment; + bool _isAllDay = false; String _subject = ''; final List _allowedViews = [ @@ -51,22 +50,18 @@ class _CalendarAppointmentEditorState extends SampleViewState { CalendarView.schedule ]; - ScrollController controller; - CalendarController calendarController; + final ScrollController controller = ScrollController(); + final CalendarController calendarController = CalendarController(); /// Global key used to maintain the state, /// when we change the parent of the widget - GlobalKey _globalKey; - CalendarView _view; + final GlobalKey _globalKey = GlobalKey(); + CalendarView _view = CalendarView.month; @override void initState() { - _globalKey = GlobalKey(); _isMobile = false; - controller = ScrollController(); - calendarController = CalendarController(); - calendarController.view = CalendarView.month; - _view = CalendarView.month; + calendarController.view = _view; _appointments = _getAppointmentDetails(); _events = _DataSource(_appointments); _selectedAppointment = null; @@ -98,7 +93,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget _calendar = Theme( /// The key set here to maintain the state, @@ -111,7 +106,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { return Scaffold( resizeToAvoidBottomInset: false, body: calendarController.view == CalendarView.month && - model.isWeb && + model.isWebFullView && _screenHeight < 800 ? Scrollbar( isAlwaysShown: true, @@ -134,15 +129,15 @@ class _CalendarAppointmentEditorState extends SampleViewState { /// view or switched to different calendar view. void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { if (_view == calendarController.view || - !model.isWeb || + !model.isWebFullView || (_view != CalendarView.month && calendarController.view != CalendarView.month)) { return; } - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { + SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { setState(() { - _view = calendarController.view; + _view = calendarController.view!; /// Update the current view when the calendar view changed to /// month view or from month view. @@ -164,27 +159,27 @@ class _CalendarAppointmentEditorState extends SampleViewState { /// Navigates the calendar to day view, /// when we tap on month cells in mobile. - if (!model.isWeb && calendarController.view == CalendarView.month) { + if (!model.isWebFullView && calendarController.view == CalendarView.month) { calendarController.view = CalendarView.day; } else { if (calendarTapDetails.appointments != null && calendarTapDetails.targetElement == CalendarElement.appointment) { - _selectedAppointment = calendarTapDetails.appointments[0]; + _selectedAppointment = calendarTapDetails.appointments![0]; } - final DateTime selectedDate = calendarTapDetails.date; + final DateTime selectedDate = calendarTapDetails.date!; final CalendarElement targetElement = calendarTapDetails.targetElement; /// To open the appointment editor for web, /// when the screen width is greater than 767. - if (model.isWeb && !_isMobile) { + if (model.isWebFullView && !_isMobile) { final bool _isAppointmentTapped = calendarTapDetails.targetElement == CalendarElement.appointment; showDialog( context: context, builder: (BuildContext context) { final List appointment = []; - Appointment newAppointment; + Appointment? newAppointment; /// Creates a new appointment, which is displayed on the tapped /// calendar element, when the editor is opened. @@ -193,13 +188,11 @@ class _CalendarAppointmentEditorState extends SampleViewState { CalendarElement.allDayPanel; _selectedColorIndex = 0; _subject = ''; - final DateTime date = calendarTapDetails.date; - _startDate = date; - _endDate = date.add(const Duration(hours: 1)); + final DateTime date = calendarTapDetails.date!; newAppointment = Appointment( - startTime: _startDate, - endTime: _endDate, + startTime: date, + endTime: date.add(const Duration(hours: 1)), color: _colorCollection[_selectedColorIndex], isAllDay: _isAllDay, subject: _subject == '' ? '(No title)' : _subject, @@ -209,7 +202,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { _events.appointments.add(appointment[0]); SchedulerBinding.instance - .addPostFrameCallback((Duration duration) { + ?.addPostFrameCallback((Duration duration) { _events.notifyListeners( CalendarDataSourceAction.add, appointment); }); @@ -225,7 +218,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { _events.appointments .removeAt(_events.appointments.indexOf(newAppointment)); _events.notifyListeners(CalendarDataSourceAction.remove, - []..add(newAppointment)); + [newAppointment]); } return true; }, @@ -234,8 +227,8 @@ class _CalendarAppointmentEditorState extends SampleViewState { alignment: Alignment.center, width: _isAppointmentTapped ? 400 : 500, height: _isAppointmentTapped - ? _selectedAppointment.location == null || - _selectedAppointment.location.isEmpty + ? _selectedAppointment!.location == null || + _selectedAppointment!.location!.isEmpty ? 150 : 200 : 390, @@ -257,7 +250,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { targetElement, selectedDate, model, - _selectedAppointment, + _selectedAppointment!, _colorCollection, _colorNames, _events, @@ -269,7 +262,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { _events, _colorCollection, _colorNames, - _selectedAppointment, + _selectedAppointment!, _timeZoneCollection), )))), ); @@ -465,14 +458,14 @@ class _CalendarAppointmentEditorState extends SampleViewState { /// Returns the calendar based on the properties passed. SfCalendar _getAppointmentEditorCalendar( - [CalendarController _calendarController, - CalendarDataSource _calendarDataSource, + [CalendarController? _calendarController, + CalendarDataSource? _calendarDataSource, dynamic calendarTapCallback, - ViewChangedCallback viewChangedCallback, + ViewChangedCallback? viewChangedCallback, dynamic scheduleViewBuilder]) { return SfCalendar( controller: _calendarController, - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, allowedViews: _allowedViews, showDatePickerButton: true, scheduleViewMonthHeaderBuilder: scheduleViewBuilder, @@ -495,11 +488,11 @@ typedef _PickerChanged = void Function( /// Details for the [_PickerChanged]. class _PickerChangedDetails { - _PickerChangedDetails({this.index, this.resourceId}); + _PickerChangedDetails({this.index = -1, this.resourceId}); final int index; - final Object resourceId; + final Object? resourceId; } /// An object to set the appointment collection data source to collection, and @@ -516,9 +509,17 @@ class _DataSource extends CalendarDataSource { /// Formats the tapped appointment time text, to display on the pop-up view. String _getAppointmentTimeText(Appointment selectedAppointment) { if (selectedAppointment.isAllDay) { - return DateFormat('EEEE, MMM dd') - .format(selectedAppointment.startTime) - .toString(); + if ((isSameDate( + selectedAppointment.startTime, selectedAppointment.endTime))) { + return DateFormat('EEEE, MMM dd') + .format(selectedAppointment.startTime) + .toString(); + } + return DateFormat('EEEE, MMM dd').format(selectedAppointment.startTime) + + ' - ' + + DateFormat('EEEE, MMM dd') + .format(selectedAppointment.endTime) + .toString(); } else if (selectedAppointment.startTime.day != selectedAppointment.endTime.day || selectedAppointment.startTime.month != @@ -599,10 +600,10 @@ Widget displayAppointmentDetails( IconButton( icon: Icon(Icons.delete, color: defaultColor), onPressed: () { - events.appointments - .removeAt(events.appointments.indexOf(selectedAppointment)); + events.appointments! + .removeAt(events.appointments!.indexOf(selectedAppointment)); events.notifyListeners(CalendarDataSourceAction.remove, - []..add(selectedAppointment)); + [selectedAppointment]); Navigator.pop(context); }, ), @@ -620,7 +621,10 @@ Widget displayAppointmentDetails( color: selectedAppointment.color, size: 20, ), - title: Text(selectedAppointment.subject ?? '(No Text)', + title: Text( + selectedAppointment.subject.isNotEmpty + ? selectedAppointment.subject + : '(No Text)', style: TextStyle( fontSize: 20, color: defaultTextColor, @@ -636,7 +640,7 @@ Widget displayAppointmentDetails( ), )), selectedAppointment.resourceIds == null || - selectedAppointment.resourceIds.isEmpty + selectedAppointment.resourceIds!.isEmpty ? Container() : ListTile( leading: Icon( @@ -646,13 +650,14 @@ Widget displayAppointmentDetails( ), title: Text( _getSelectedResourceText( - selectedAppointment.resourceIds, events.resources), + selectedAppointment.resourceIds!, events.resources!), style: TextStyle( fontSize: 15, color: defaultTextColor, fontWeight: FontWeight.w400)), ), - selectedAppointment.location == null || selectedAppointment.location.isEmpty + selectedAppointment.location == null || + selectedAppointment.location!.isEmpty ? Container() : ListTile( leading: Icon( @@ -672,7 +677,7 @@ Widget displayAppointmentDetails( /// Returns the selected resource display name based on the ids passed. String _getSelectedResourceText( List resourceIds, List resourceCollection) { - String resourceNames; + String? resourceNames; for (int i = 0; i < resourceIds.length; i++) { final String name = resourceCollection .firstWhere((resource) => resource.id == resourceIds[i]) @@ -680,7 +685,7 @@ String _getSelectedResourceText( resourceNames = resourceNames == null ? name : resourceNames + ', ' + name; } - return resourceNames; + return resourceNames!; } /// The color picker element for the appointment editor with the available @@ -688,7 +693,7 @@ String _getSelectedResourceText( class _CalendarColorPicker extends StatefulWidget { _CalendarColorPicker(this.colorCollection, this.selectedColorIndex, this.colorNames, this.model, - {this.onChanged}); + {required this.onChanged}); final List colorCollection; @@ -705,7 +710,7 @@ class _CalendarColorPicker extends StatefulWidget { } class _CalendarColorPickerState extends State<_CalendarColorPicker> { - int _selectedColorIndex; + int _selectedColorIndex = -1; @override void initState() { @@ -765,7 +770,8 @@ class _CalendarColorPickerState extends State<_CalendarColorPicker> { /// Picker to display the available resource collection, and returns the /// selected resource id. class _ResourcePicker extends StatefulWidget { - _ResourcePicker(this.resourceCollection, this.model, {this.onChanged}); + _ResourcePicker(this.resourceCollection, this.model, + {required this.onChanged}); final List resourceCollection; @@ -829,7 +835,7 @@ class _ResourcePickerState extends State<_ResourcePicker> { class _CalendarTimeZonePicker extends StatefulWidget { const _CalendarTimeZonePicker(this.backgroundColor, this.timeZoneCollection, this.selectedTimeZoneIndex, this.model, - {this.onChanged}); + {required this.onChanged}); final Color backgroundColor; @@ -848,7 +854,7 @@ class _CalendarTimeZonePicker extends StatefulWidget { } class _CalendarTimeZonePickerState extends State<_CalendarTimeZonePicker> { - int _selectedTimeZoneIndex; + int _selectedTimeZoneIndex = -1; @override void initState() { @@ -908,6 +914,7 @@ class _CalendarTimeZonePickerState extends State<_CalendarTimeZonePicker> { /// Builds the appointment editor with minimal elements in a pop-up based on the /// tapped calendar element. class PopUpAppointmentEditor extends StatefulWidget { + /// Holds the data of appointment editor const PopUpAppointmentEditor( this.model, this.newAppointment, @@ -918,20 +925,28 @@ class PopUpAppointmentEditor extends StatefulWidget { this.selectedAppointment, this.timeZoneCollection); + /// Model of appointment editor final SampleModel model; - final Appointment newAppointment; + /// new appointment value + final Appointment? newAppointment; + /// List of appointments final List appointment; + /// Holds the events value final CalendarDataSource events; + /// Holds list of colors final List colorCollection; + /// holds the names of colors final List colorNames; + /// Selected appointment value final Appointment selectedAppointment; + /// Colllection list of time zones final List timeZoneCollection; @override @@ -941,17 +956,17 @@ class PopUpAppointmentEditor extends StatefulWidget { class _PopUpAppointmentEditorState extends State { int _selectedColorIndex = 0; int _selectedTimeZoneIndex = 0; - DateTime _startDate; - DateTime _endDate; - TimeOfDay _startTime; - TimeOfDay _endTime; - bool _isAllDay; + late DateTime _startDate; + late DateTime _endDate; + late TimeOfDay _startTime; + late TimeOfDay _endTime; + bool _isAllDay = false; String _subject = ''; - String _notes = ''; - String _location = ''; - List _resourceIds; - List _selectedResources; - List _unSelectedResources; + String? _notes; + String? _location; + List? _resourceIds; + List _selectedResources = []; + List _unSelectedResources = []; @override void initState() { @@ -972,10 +987,11 @@ class _PopUpAppointmentEditorState extends State { _isAllDay = widget.selectedAppointment.isAllDay; _selectedColorIndex = widget.colorCollection.indexOf(widget.selectedAppointment.color); - _selectedTimeZoneIndex = widget.selectedAppointment.startTimeZone == '' + _selectedTimeZoneIndex = widget.selectedAppointment.startTimeZone == null || + widget.selectedAppointment.startTimeZone == '' ? 0 : widget.timeZoneCollection - .indexOf(widget.selectedAppointment.startTimeZone); + .indexOf(widget.selectedAppointment.startTimeZone!); _subject = widget.selectedAppointment.subject == '(No title)' ? '' : widget.selectedAppointment.subject; @@ -985,7 +1001,7 @@ class _PopUpAppointmentEditorState extends State { _selectedColorIndex = _selectedColorIndex == -1 ? 0 : _selectedColorIndex; _selectedTimeZoneIndex = _selectedTimeZoneIndex == -1 ? 0 : _selectedTimeZoneIndex; - _resourceIds = widget.selectedAppointment.resourceIds; + _resourceIds = widget.selectedAppointment.resourceIds?.sublist(0); _startTime = TimeOfDay(hour: _startDate.hour, minute: _startDate.minute); _endTime = TimeOfDay(hour: _endDate.hour, minute: _endDate.minute); @@ -1009,17 +1025,13 @@ class _PopUpAppointmentEditorState extends State { final Widget _startDatePicker = RawMaterialButton( padding: const EdgeInsets.symmetric(horizontal: 5), - child: Text(DateFormat('MMM dd, yyyy').format(_startDate), - style: - TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), - textAlign: TextAlign.left), onPressed: () async { - final DateTime date = await showDatePicker( + final DateTime? date = await showDatePicker( context: context, initialDate: _startDate, firstDate: DateTime(1900), lastDate: DateTime(2100), - builder: (BuildContext context, Widget child) { + builder: (BuildContext context, Widget? child) { /// Theme widget used to apply the theme and primary color to the /// date picker. return Theme( @@ -1031,7 +1043,7 @@ class _PopUpAppointmentEditorState extends State { accentColor: widget.model.backgroundColor, primaryColor: widget.model.backgroundColor, ), - child: child, + child: child!, ); }); @@ -1045,21 +1057,20 @@ class _PopUpAppointmentEditorState extends State { }); } }, + child: Text(DateFormat('MMM dd, yyyy').format(_startDate), + style: + TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), + textAlign: TextAlign.left), ); final Widget _startTimePicker = RawMaterialButton( padding: const EdgeInsets.symmetric(horizontal: 5), - child: Text( - DateFormat('hh:mm a').format(_startDate), - style: TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), - textAlign: TextAlign.left, - ), onPressed: () async { - final TimeOfDay time = await showTimePicker( + final TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay(hour: _startTime.hour, minute: _startTime.minute), - builder: (BuildContext context, Widget child) { + builder: (BuildContext context, Widget? child) { /// Theme widget used to apply the theme and primary color to the /// time picker. return Theme( @@ -1071,7 +1082,7 @@ class _PopUpAppointmentEditorState extends State { accentColor: widget.model.backgroundColor, primaryColor: widget.model.backgroundColor, ), - child: child, + child: child!, ); }); @@ -1086,21 +1097,21 @@ class _PopUpAppointmentEditorState extends State { }); } }, - ); - - final Widget _endTimePicker = RawMaterialButton( - padding: const EdgeInsets.symmetric(horizontal: 5), child: Text( - DateFormat('hh:mm a').format(_endDate), + DateFormat('hh:mm a').format(_startDate), style: TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), textAlign: TextAlign.left, ), + ); + + final Widget _endTimePicker = RawMaterialButton( + padding: const EdgeInsets.symmetric(horizontal: 5), onPressed: () async { - final TimeOfDay time = await showTimePicker( + final TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay(hour: _endTime.hour, minute: _endTime.minute), - builder: (BuildContext context, Widget child) { + builder: (BuildContext context, Widget? child) { /// Theme widget used to apply the theme and primary color to the /// date picker. return Theme( @@ -1112,7 +1123,7 @@ class _PopUpAppointmentEditorState extends State { accentColor: widget.model.backgroundColor, primaryColor: widget.model.backgroundColor, ), - child: child, + child: child!, ); }); @@ -1130,21 +1141,22 @@ class _PopUpAppointmentEditorState extends State { }); } }, + child: Text( + DateFormat('hh:mm a').format(_endDate), + style: TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), + textAlign: TextAlign.left, + ), ); final Widget _endDatePicker = RawMaterialButton( padding: const EdgeInsets.symmetric(horizontal: 5), - child: Text(DateFormat('MMM dd, yyyy').format(_endDate), - style: - TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), - textAlign: TextAlign.left), onPressed: () async { - final DateTime date = await showDatePicker( + final DateTime? date = await showDatePicker( context: context, initialDate: _endDate, firstDate: DateTime(1900), lastDate: DateTime(2100), - builder: (BuildContext context, Widget child) { + builder: (BuildContext context, Widget? child) { /// Theme widget used to apply the theme and primary color to the /// date picker. return Theme( @@ -1156,7 +1168,7 @@ class _PopUpAppointmentEditorState extends State { accentColor: widget.model.backgroundColor, primaryColor: widget.model.backgroundColor, ), - child: child, + child: child!, ); }); @@ -1173,6 +1185,10 @@ class _PopUpAppointmentEditorState extends State { }); } }, + child: Text(DateFormat('MMM dd, yyyy').format(_endDate), + style: + TextStyle(fontWeight: FontWeight.w500, color: defaultTextColor), + textAlign: TextAlign.left), ); return ListView(padding: const EdgeInsets.all(0.0), children: [ @@ -1183,14 +1199,15 @@ class _PopUpAppointmentEditorState extends State { icon: Icon(Icons.close, color: defaultColor), onPressed: () { if (widget.newAppointment != null && - widget.events.appointments + widget.events.appointments! .contains(widget.newAppointment)) { /// To remove the created appointment, when the appointment editor /// closed without saving the appointment. - widget.events.appointments.removeAt(widget.events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.newAppointment)); widget.events.notifyListeners(CalendarDataSourceAction.remove, - []..add(widget.newAppointment)); + [widget.newAppointment!]); } Navigator.pop(context); @@ -1314,7 +1331,7 @@ class _PopUpAppointmentEditorState extends State { _notes = value; }, keyboardType: TextInputType.multiline, - maxLines: widget.model.isWeb ? 1 : null, + maxLines: widget.model.isWebFullView ? 1 : null, style: TextStyle( fontSize: 15, color: defaultTextColor, @@ -1328,7 +1345,7 @@ class _PopUpAppointmentEditorState extends State { ), ), )), - widget.events.resources == null || widget.events.resources.isEmpty + widget.events.resources == null || widget.events.resources!.isEmpty ? Container() : Container( margin: EdgeInsets.only(bottom: 5), @@ -1344,13 +1361,6 @@ class _PopUpAppointmentEditorState extends State { )), title: RawMaterialButton( padding: const EdgeInsets.only(left: 5), - child: Container( - alignment: Alignment.centerLeft, - child: _getResourceEditor(TextStyle( - fontSize: 15, - color: defaultColor, - fontWeight: FontWeight.w300)), - ), onPressed: () { showDialog( context: context, @@ -1360,9 +1370,10 @@ class _PopUpAppointmentEditorState extends State { _unSelectedResources, widget.model, onChanged: (_PickerChangedDetails details) { - _resourceIds == null - ? _resourceIds = [details.resourceId] - : _resourceIds.add(details.resourceId); + _resourceIds = _resourceIds == null + ? [details.resourceId!] + : (_resourceIds!.sublist(0) + ..add(details.resourceId!)); _selectedResources = _getSelectedResources( _resourceIds, widget.events.resources); _unSelectedResources = _getUnSelectedResources( @@ -1374,6 +1385,13 @@ class _PopUpAppointmentEditorState extends State { /// update the color picker changes })); }, + child: Container( + alignment: Alignment.centerLeft, + child: _getResourceEditor(TextStyle( + fontSize: 15, + color: defaultColor, + fontWeight: FontWeight.w300)), + ), ), )), Container( @@ -1388,15 +1406,6 @@ class _PopUpAppointmentEditorState extends State { color: widget.colorCollection[_selectedColorIndex])), title: RawMaterialButton( padding: const EdgeInsets.only(left: 5), - child: Container( - alignment: Alignment.centerLeft, - child: Text( - widget.colorNames[_selectedColorIndex], - style: TextStyle( - fontWeight: FontWeight.w500, color: defaultTextColor), - textAlign: TextAlign.start, - ), - ), onPressed: () { showDialog( context: context, @@ -1416,6 +1425,15 @@ class _PopUpAppointmentEditorState extends State { /// update the color picker changes })); }, + child: Container( + alignment: Alignment.centerLeft, + child: Text( + widget.colorNames[_selectedColorIndex], + style: TextStyle( + fontWeight: FontWeight.w500, color: defaultTextColor), + textAlign: TextAlign.start, + ), + ), ), )), Container( @@ -1429,12 +1447,6 @@ class _PopUpAppointmentEditorState extends State { padding: EdgeInsets.only(right: 10), child: RawMaterialButton( padding: EdgeInsets.symmetric(horizontal: 5), - child: Text( - 'MORE OPTIONS', - style: TextStyle( - fontWeight: FontWeight.w500, - color: defaultTextColor), - ), onPressed: () { Navigator.pop(context); showDialog( @@ -1463,13 +1475,12 @@ class _PopUpAppointmentEditorState extends State { return WillPopScope( onWillPop: () async { if (widget.newAppointment != null) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.newAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - [] - ..add(widget.newAppointment)); + [widget.newAppointment!]); } return true; }, @@ -1485,6 +1496,12 @@ class _PopUpAppointmentEditorState extends State { ); }); }, + child: Text( + 'MORE OPTIONS', + style: TextStyle( + fontWeight: FontWeight.w500, + color: defaultTextColor), + ), )), Padding( padding: EdgeInsets.only(left: 10), @@ -1493,29 +1510,24 @@ class _PopUpAppointmentEditorState extends State { borderRadius: BorderRadius.all(Radius.circular(4)), ), fillColor: widget.model.backgroundColor, - child: const Text( - 'SAVE', - style: TextStyle( - color: Colors.white, fontWeight: FontWeight.w500), - ), onPressed: () { if (widget.selectedAppointment != null || widget.newAppointment != null) { - if (widget.events.appointments.isNotEmpty && - widget.events.appointments + if (widget.events.appointments!.isNotEmpty && + widget.events.appointments! .contains(widget.selectedAppointment)) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.selectedAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - []..add(widget.selectedAppointment)); + [widget.selectedAppointment]); } if (widget.appointment.isNotEmpty && widget.appointment .contains(widget.newAppointment)) { widget.appointment.removeAt(widget.appointment - .indexOf(widget.newAppointment)); + .indexOf(widget.newAppointment!)); } } @@ -1536,13 +1548,18 @@ class _PopUpAppointmentEditorState extends State { resourceIds: _resourceIds, )); - widget.events.appointments.add(widget.appointment[0]); + widget.events.appointments!.add(widget.appointment[0]); widget.events.notifyListeners( CalendarDataSourceAction.add, widget.appointment); Navigator.pop(context); }, + child: const Text( + 'SAVE', + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.w500), + ), ), ), ], @@ -1553,12 +1570,12 @@ class _PopUpAppointmentEditorState extends State { /// Return the resource editor to edit the resource collection for an /// appointment - Widget _getResourceEditor([TextStyle hintTextStyle]) { + Widget _getResourceEditor(TextStyle hintTextStyle) { if (_selectedResources == null || _selectedResources.isEmpty) { return Text('Add people', style: hintTextStyle); } - List chipWidgets = []; + final List chipWidgets = []; for (int i = 0; i < _selectedResources.length; i++) { final CalendarResource selectedResource = _selectedResources[i]; chipWidgets.add(Chip( @@ -1573,7 +1590,7 @@ class _PopUpAppointmentEditorState extends State { label: Text(selectedResource.displayName), onDeleted: () { _selectedResources.removeAt(i); - _resourceIds.removeAt(i); + _resourceIds!.removeAt(i); _unSelectedResources = _getUnSelectedResources( _selectedResources, widget.events.resources); setState(() {}); @@ -1592,6 +1609,7 @@ class _PopUpAppointmentEditorState extends State { /// Builds the appointment editor with all the required elements in a pop-up /// based on the tapped calendar element. class AppointmentEditorWeb extends StatefulWidget { + /// Holds the information of appointments const AppointmentEditorWeb( this.model, this.selectedAppointment, @@ -1599,23 +1617,31 @@ class AppointmentEditorWeb extends StatefulWidget { this.colorNames, this.events, this.timeZoneCollection, - [this.appointment, - this.newAppointment]); + this.appointment, + [this.newAppointment]); + /// Current sample model final SampleModel model; - final Appointment newAppointment; + /// new appointment calue + final Appointment? newAppointment; + /// List of appointments final List appointment; + /// Selcted appointment value final Appointment selectedAppointment; + /// List of colors final List colorCollection; + /// Collection of color names final List colorNames; + /// Holds the Events values final CalendarDataSource events; + /// Collection of time zones final List timeZoneCollection; @override @@ -1625,18 +1651,18 @@ class AppointmentEditorWeb extends StatefulWidget { class _AppointmentEditorWebState extends State { int _selectedColorIndex = 0; int _selectedTimeZoneIndex = 0; - DateTime _startDate; - TimeOfDay _startTime; - DateTime _endDate; - TimeOfDay _endTime; - bool _isAllDay; + late DateTime _startDate; + late TimeOfDay _startTime; + late DateTime _endDate; + late TimeOfDay _endTime; + bool _isAllDay = false; String _subject = ''; - String _notes = ''; - String _location = ''; + String? _notes; + String? _location; bool _isTimeZoneEnabled = false; - List _resourceIds; - List _selectedResources; - List _unSelectedResources; + List? _resourceIds; + List _selectedResources = []; + List _unSelectedResources = []; @override void initState() { @@ -1657,10 +1683,11 @@ class _AppointmentEditorWebState extends State { _isAllDay = widget.selectedAppointment.isAllDay; _selectedColorIndex = widget.colorCollection.indexOf(widget.selectedAppointment.color); - _selectedTimeZoneIndex = widget.selectedAppointment.startTimeZone == '' + _selectedTimeZoneIndex = widget.selectedAppointment.startTimeZone == null || + widget.selectedAppointment.startTimeZone == '' ? 0 : widget.timeZoneCollection - .indexOf(widget.selectedAppointment.startTimeZone); + .indexOf(widget.selectedAppointment.startTimeZone!); _subject = widget.selectedAppointment.subject == '(No title)' ? '' : widget.selectedAppointment.subject; @@ -1670,12 +1697,12 @@ class _AppointmentEditorWebState extends State { _selectedColorIndex = _selectedColorIndex == -1 ? 0 : _selectedColorIndex; _selectedTimeZoneIndex = _selectedTimeZoneIndex == -1 ? 0 : _selectedTimeZoneIndex; - _resourceIds = widget.selectedAppointment.resourceIds; + _resourceIds = widget.selectedAppointment.resourceIds?.sublist(0); _startTime = TimeOfDay(hour: _startDate.hour, minute: _startDate.minute); _endTime = TimeOfDay(hour: _endDate.hour, minute: _endDate.minute); _isTimeZoneEnabled = widget.selectedAppointment.startTimeZone != null && - widget.selectedAppointment.startTimeZone.isNotEmpty; + widget.selectedAppointment.startTimeZone!.isNotEmpty; _selectedResources = _getSelectedResources(_resourceIds, widget.events.resources); _unSelectedResources = @@ -1684,8 +1711,8 @@ class _AppointmentEditorWebState extends State { /// Return the resource editor to edit the resource collection for an /// appointment - Widget _getResourceEditor([TextStyle hintTextStyle]) { - if (_selectedResources == null || _selectedResources.isEmpty) { + Widget _getResourceEditor(TextStyle hintTextStyle) { + if (_selectedResources.isEmpty) { return Padding( padding: EdgeInsets.only(top: 25, bottom: 5), child: Text( @@ -1695,7 +1722,7 @@ class _AppointmentEditorWebState extends State { ); } - List chipWidgets = []; + final List chipWidgets = []; for (int i = 0; i < _selectedResources.length; i++) { final CalendarResource selectedResource = _selectedResources[i]; chipWidgets.add(Chip( @@ -1710,7 +1737,7 @@ class _AppointmentEditorWebState extends State { label: Text(selectedResource.displayName), onDeleted: () { _selectedResources.removeAt(i); - _resourceIds.removeAt(i); + _resourceIds!.removeAt(i); _unSelectedResources = _getUnSelectedResources( _selectedResources, widget.events.resources); setState(() {}); @@ -1750,7 +1777,7 @@ class _AppointmentEditorWebState extends State { : Colors.white, ), height: widget.events.resources != null && - widget.events.resources.isNotEmpty + widget.events.resources!.isNotEmpty ? _isTimeZoneEnabled ? 560 : 500 @@ -1778,16 +1805,16 @@ class _AppointmentEditorWebState extends State { icon: Icon(Icons.close, color: defaultColor), onPressed: () { if (widget.newAppointment != null && - widget.events.appointments + widget.events.appointments! .contains(widget.newAppointment)) { /// To remove the created appointment when the pop-up closed /// without saving the appointment. - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.newAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - []..add(widget.newAppointment)); + [widget.newAppointment!]); } Navigator.pop(context); @@ -1950,9 +1977,14 @@ class _AppointmentEditorWebState extends State { children: [ ButtonTheme( minWidth: 50.0, - child: FlatButton( + child: MaterialButton( + elevation: 0, + focusElevation: 0, + highlightElevation: 0, + disabledElevation: 0, + hoverElevation: 0, onPressed: () async { - final DateTime date = + final DateTime? date = await showDatePicker( context: context, initialDate: _startDate, @@ -1960,7 +1992,7 @@ class _AppointmentEditorWebState extends State { lastDate: DateTime(2100), builder: (BuildContext context, - Widget child) { + Widget? child) { return Theme( data: ThemeData( brightness: widget @@ -1978,7 +2010,7 @@ class _AppointmentEditorWebState extends State { primaryColor: widget .model .backgroundColor), - child: child, + child: child!, ); }); @@ -2003,7 +2035,7 @@ class _AppointmentEditorWebState extends State { }); } }, - shape: const CircleBorder(), + shape: CircleBorder(), padding: const EdgeInsets.all(0.0), child: Icon( Icons.date_range, @@ -2015,17 +2047,17 @@ class _AppointmentEditorWebState extends State { ? Text('') : ButtonTheme( minWidth: 50.0, - child: FlatButton( - child: Icon( - Icons.access_time, - color: defaultColor, - size: 20, - ), - shape: const CircleBorder(), + child: MaterialButton( + elevation: 0, + focusElevation: 0, + highlightElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + shape: CircleBorder(), padding: - const EdgeInsets.all(0), + const EdgeInsets.all(0.0), onPressed: () async { - final TimeOfDay time = + final TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay( @@ -2035,7 +2067,7 @@ class _AppointmentEditorWebState extends State { .minute), builder: (BuildContext context, - Widget child) { + Widget? child) { return Theme( data: ThemeData( brightness: widget @@ -2054,7 +2086,7 @@ class _AppointmentEditorWebState extends State { .model .backgroundColor, ), - child: child, + child: child!, ); }); @@ -2082,6 +2114,11 @@ class _AppointmentEditorWebState extends State { }); } }, + child: Icon( + Icons.access_time, + color: defaultColor, + size: 20, + ), )) ], ), @@ -2142,16 +2179,16 @@ class _AppointmentEditorWebState extends State { children: [ ButtonTheme( minWidth: 50.0, - child: FlatButton( - child: Icon( - Icons.date_range, - color: defaultColor, - size: 20, - ), - shape: const CircleBorder(), - padding: const EdgeInsets.all(0), + child: MaterialButton( + elevation: 0, + focusElevation: 0, + highlightElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + shape: CircleBorder(), + padding: const EdgeInsets.all(0.0), onPressed: () async { - final DateTime date = + final DateTime? date = await showDatePicker( context: context, initialDate: _endDate, @@ -2159,7 +2196,7 @@ class _AppointmentEditorWebState extends State { lastDate: DateTime(2100), builder: (BuildContext context, - Widget child) { + Widget? child) { return Theme( data: ThemeData( brightness: widget @@ -2178,7 +2215,7 @@ class _AppointmentEditorWebState extends State { .model .backgroundColor, ), - child: child, + child: child!, ); }); @@ -2207,22 +2244,27 @@ class _AppointmentEditorWebState extends State { }); } }, + child: Icon( + Icons.date_range, + color: defaultColor, + size: 20, + ), )), _isAllDay ? Text('') : ButtonTheme( minWidth: 50.0, - child: FlatButton( - child: Icon( - Icons.access_time, - color: defaultColor, - size: 20, - ), - shape: const CircleBorder(), + child: MaterialButton( + elevation: 0, + focusElevation: 0, + highlightElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + shape: CircleBorder(), padding: const EdgeInsets.all(0), onPressed: () async { - final TimeOfDay time = + final TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay( @@ -2232,7 +2274,7 @@ class _AppointmentEditorWebState extends State { .minute), builder: (BuildContext context, - Widget child) { + Widget? child) { return Theme( data: ThemeData( brightness: widget @@ -2251,7 +2293,7 @@ class _AppointmentEditorWebState extends State { .model .backgroundColor, ), - child: child, + child: child!, ); }); @@ -2284,6 +2326,11 @@ class _AppointmentEditorWebState extends State { }); } }, + child: Icon( + Icons.access_time, + color: defaultColor, + size: 20, + ), )) ], ), @@ -2315,7 +2362,10 @@ class _AppointmentEditorWebState extends State { focusColor: widget.model.backgroundColor, activeColor: widget.model.backgroundColor, value: _isAllDay, - onChanged: (bool value) { + onChanged: (bool? value) { + if (value == null) { + return; + } setState(() { _isAllDay = value; if (_isAllDay) { @@ -2338,7 +2388,10 @@ class _AppointmentEditorWebState extends State { focusColor: widget.model.backgroundColor, activeColor: widget.model.backgroundColor, value: _isTimeZoneEnabled, - onChanged: (bool value) { + onChanged: (bool? value) { + if (value == null) { + return; + } setState(() { _isTimeZoneEnabled = value; if (!_isTimeZoneEnabled && @@ -2381,25 +2434,6 @@ class _AppointmentEditorWebState extends State { Expanded( child: RawMaterialButton( padding: const EdgeInsets.only(left: 5.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - widget.timeZoneCollection[ - _selectedTimeZoneIndex], - style: TextStyle( - fontSize: 13, - color: defaultColor, - fontWeight: FontWeight.w400), - ), - const Icon( - Icons.arrow_drop_down, - size: 24, - ) - ], - ), onPressed: () { showDialog( context: context, @@ -2419,13 +2453,32 @@ class _AppointmentEditorWebState extends State { /// update the time zone changes })); }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.timeZoneCollection[ + _selectedTimeZoneIndex], + style: TextStyle( + fontSize: 13, + color: defaultColor, + fontWeight: FontWeight.w400), + ), + const Icon( + Icons.arrow_drop_down, + size: 24, + ) + ], + ), )), ], ), ), )) : Container(), - widget.events.resources == null || widget.events.resources.isEmpty + widget.events.resources == null || widget.events.resources!.isEmpty ? Container() : Container( child: ListTile( @@ -2470,9 +2523,10 @@ class _AppointmentEditorWebState extends State { _unSelectedResources, widget.model, onChanged: (_PickerChangedDetails details) { - _resourceIds == null - ? _resourceIds = [details.resourceId] - : _resourceIds.add(details.resourceId); + _resourceIds = _resourceIds == null + ? [details.resourceId!] + : (_resourceIds!.sublist(0) + ..add(details.resourceId!)); _selectedResources = _getSelectedResources( _resourceIds, widget.events.resources); _unSelectedResources = _getUnSelectedResources( @@ -2511,7 +2565,7 @@ class _AppointmentEditorWebState extends State { _notes = value; }, keyboardType: TextInputType.multiline, - maxLines: widget.model.isWeb ? 1 : null, + maxLines: widget.model.isWebFullView ? 1 : null, style: TextStyle( fontSize: 13, color: defaultTextColor, @@ -2555,25 +2609,6 @@ class _AppointmentEditorWebState extends State { Expanded( child: RawMaterialButton( padding: const EdgeInsets.only(left: 5), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - widget.colorNames[_selectedColorIndex], - style: TextStyle( - fontSize: 13, - color: defaultTextColor, - fontWeight: FontWeight.w400), - ), - const Icon( - Icons.arrow_drop_down, - size: 24, - ) - ], - ), onPressed: () { showDialog( context: context, @@ -2594,6 +2629,25 @@ class _AppointmentEditorWebState extends State { /// update the color picker changes })); }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.colorNames[_selectedColorIndex], + style: TextStyle( + fontSize: 13, + color: defaultTextColor, + fontWeight: FontWeight.w400), + ), + const Icon( + Icons.arrow_drop_down, + size: 24, + ) + ], + ), ), ), ], @@ -2610,23 +2664,23 @@ class _AppointmentEditorWebState extends State { Padding( padding: EdgeInsets.only(right: 10), child: RawMaterialButton( - child: Text( - 'CANCEL', - style: TextStyle( - fontWeight: FontWeight.w500, - color: defaultTextColor), - ), onPressed: () { if (widget.newAppointment != null) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.newAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - []..add(widget.newAppointment)); + [widget.newAppointment!]); } Navigator.pop(context); }, + child: Text( + 'CANCEL', + style: TextStyle( + fontWeight: FontWeight.w500, + color: defaultTextColor), + ), ), ), Padding( @@ -2636,44 +2690,36 @@ class _AppointmentEditorWebState extends State { borderRadius: BorderRadius.all(Radius.circular(4)), ), fillColor: widget.model.backgroundColor, - child: const Text( - 'SAVE', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Colors.white), - ), onPressed: () { if (widget.selectedAppointment != null || widget.newAppointment != null) { - if (widget.events.appointments.isNotEmpty && - widget.events.appointments + if (widget.events.appointments!.isNotEmpty && + widget.events.appointments! .contains(widget.selectedAppointment)) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.selectedAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - [] - ..add(widget.selectedAppointment)); + [widget.selectedAppointment]); } if (widget.appointment.isNotEmpty && widget.appointment .contains(widget.newAppointment)) { widget.appointment.removeAt(widget.appointment - .indexOf(widget.newAppointment)); + .indexOf(widget.newAppointment!)); } if (widget.newAppointment != null && - widget.events.appointments.isNotEmpty && - widget.events.appointments + widget.events.appointments!.isNotEmpty && + widget.events.appointments! .contains(widget.newAppointment)) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.newAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - [] - ..add(widget.newAppointment)); + [widget.newAppointment!]); } } @@ -2697,7 +2743,7 @@ class _AppointmentEditorWebState extends State { _subject == '' ? '(No title)' : _subject, resourceIds: _resourceIds)); - widget.events.appointments + widget.events.appointments! .add(widget.appointment[0]); widget.events.notifyListeners( @@ -2706,6 +2752,12 @@ class _AppointmentEditorWebState extends State { Navigator.pop(context); }, + child: const Text( + 'SAVE', + style: TextStyle( + fontWeight: FontWeight.w500, + color: Colors.white), + ), ), ), ], @@ -2725,8 +2777,8 @@ ColorScheme _getColorScheme(SampleModel model, bool isDatePicker) { /// background color. if (model.themeData.brightness == Brightness.dark) { return ColorScheme.dark( - surface: isDatePicker ? model.backgroundColor : Colors.grey[850], primary: model.backgroundColor, + surface: isDatePicker ? model.backgroundColor : Colors.grey[850]!, ); } @@ -2739,6 +2791,7 @@ ColorScheme _getColorScheme(SampleModel model, bool isDatePicker) { /// Builds the appointment editor with all the required elements based on the /// tapped calendar element for mobile. class AppointmentEditor extends StatefulWidget { + /// Holds the value of appointment editor const AppointmentEditor( this.model, this.selectedAppointment, @@ -2750,23 +2803,32 @@ class AppointmentEditor extends StatefulWidget { this.timeZoneCollection, [this.selectedResource]); + /// Current sample model final SampleModel model; - final Appointment selectedAppointment; + /// Selected appointment + final Appointment? selectedAppointment; + /// Calendar element final CalendarElement targetElement; + /// Seelcted date value final DateTime selectedDate; + /// Collection of colors final List colorCollection; + /// List of colors name final List colorNames; + /// Holds the events value final CalendarDataSource events; + /// Collection of time zone values final List timeZoneCollection; - final CalendarResource selectedResource; + /// Selected calendar resource + final CalendarResource? selectedResource; @override _AppointmentEditorState createState() => _AppointmentEditorState(); @@ -2775,17 +2837,17 @@ class AppointmentEditor extends StatefulWidget { class _AppointmentEditorState extends State { int _selectedColorIndex = 0; int _selectedTimeZoneIndex = 0; - DateTime _startDate; - TimeOfDay _startTime; - DateTime _endDate; - TimeOfDay _endTime; - bool _isAllDay; + late DateTime _startDate; + late TimeOfDay _startTime; + late DateTime _endDate; + late TimeOfDay _endTime; + bool _isAllDay = false; String _subject = ''; - String _notes = ''; - String _location = ''; - List _resourceIds; - List _selectedResources; - List _unSelectedResources; + String? _notes; + String? _location; + List? _resourceIds; + List _selectedResources = []; + List _unSelectedResources = []; @override void initState() { @@ -2802,21 +2864,23 @@ class _AppointmentEditorState extends State { /// Updates the required editor's default field void _updateAppointmentProperties() { if (widget.selectedAppointment != null) { - _startDate = widget.selectedAppointment.startTime; - _endDate = widget.selectedAppointment.endTime; - _isAllDay = widget.selectedAppointment.isAllDay; + _startDate = widget.selectedAppointment!.startTime; + _endDate = widget.selectedAppointment!.endTime; + _isAllDay = widget.selectedAppointment!.isAllDay; _selectedColorIndex = - widget.colorCollection.indexOf(widget.selectedAppointment.color); - _selectedTimeZoneIndex = widget.selectedAppointment.startTimeZone == '' - ? 0 - : widget.timeZoneCollection - .indexOf(widget.selectedAppointment.startTimeZone); - _subject = widget.selectedAppointment.subject == '(No title)' + widget.colorCollection.indexOf(widget.selectedAppointment!.color); + _selectedTimeZoneIndex = + widget.selectedAppointment!.startTimeZone == null || + widget.selectedAppointment!.startTimeZone == '' + ? 0 + : widget.timeZoneCollection + .indexOf(widget.selectedAppointment!.startTimeZone!); + _subject = widget.selectedAppointment!.subject == '(No title)' ? '' - : widget.selectedAppointment.subject; - _notes = widget.selectedAppointment.notes; - _location = widget.selectedAppointment.location; - _resourceIds = widget.selectedAppointment.resourceIds; + : widget.selectedAppointment!.subject; + _notes = widget.selectedAppointment!.notes; + _location = widget.selectedAppointment!.location; + _resourceIds = widget.selectedAppointment!.resourceIds?.sublist(0); } else { _isAllDay = widget.targetElement == CalendarElement.allDayPanel; _selectedColorIndex = 0; @@ -2830,7 +2894,7 @@ class _AppointmentEditorState extends State { _endDate = date.add(const Duration(hours: 1)); if (widget.selectedResource != null) { - _resourceIds = [widget.selectedResource.id]; + _resourceIds = [widget.selectedResource!.id]; } } @@ -2904,83 +2968,78 @@ class _AppointmentEditorState extends State { Expanded( flex: 7, child: GestureDetector( - child: Text( - DateFormat('EEE, MMM dd yyyy') - .format(_startDate), - textAlign: TextAlign.left), - onTap: () async { - final DateTime date = await showDatePicker( - context: context, - initialDate: _startDate, - firstDate: DateTime(1900), - lastDate: DateTime(2100), - builder: - (BuildContext context, Widget child) { - return Theme( - data: ThemeData( - brightness: - widget.model.themeData.brightness, - colorScheme: - _getColorScheme(widget.model, true), - accentColor: - widget.model.backgroundColor, - primaryColor: - widget.model.backgroundColor, - ), - child: child, - ); - }); - - if (date != null && date != _startDate) { - setState(() { - final Duration difference = - _endDate.difference(_startDate); - _startDate = DateTime( - date.year, - date.month, - date.day, - _startTime.hour, - _startTime.minute, - 0); - _endDate = _startDate.add(difference); - _endTime = TimeOfDay( - hour: _endDate.hour, - minute: _endDate.minute); + onTap: () async { + final DateTime? date = await showDatePicker( + context: context, + initialDate: _startDate, + firstDate: DateTime(1900), + lastDate: DateTime(2100), + builder: (BuildContext context, Widget? child) { + return Theme( + data: ThemeData( + brightness: + widget.model.themeData.brightness, + colorScheme: + _getColorScheme(widget.model, true), + accentColor: widget.model.backgroundColor, + primaryColor: + widget.model.backgroundColor, + ), + child: child!, + ); }); - } - }), + + if (date != null && date != _startDate) { + setState(() { + final Duration difference = + _endDate.difference(_startDate); + _startDate = DateTime( + date.year, + date.month, + date.day, + _startTime.hour, + _startTime.minute, + 0); + _endDate = _startDate.add(difference); + _endTime = TimeOfDay( + hour: _endDate.hour, + minute: _endDate.minute); + }); + } + }, + child: Text( + DateFormat('EEE, MMM dd yyyy').format(_startDate), + textAlign: TextAlign.left), + ), ), Expanded( flex: 3, child: _isAllDay ? const Text('') : GestureDetector( - child: Text( - DateFormat('hh:mm a').format(_startDate), - textAlign: TextAlign.right, - ), onTap: () async { - final TimeOfDay time = await showTimePicker( - context: context, - initialTime: TimeOfDay( - hour: _startTime.hour, - minute: _startTime.minute), - builder: (BuildContext context, - Widget child) { - return Theme( - data: ThemeData( - brightness: widget - .model.themeData.brightness, - colorScheme: _getColorScheme( - widget.model, false), - accentColor: - widget.model.backgroundColor, - primaryColor: - widget.model.backgroundColor, - ), - child: child, - ); - }); + final TimeOfDay? time = + await showTimePicker( + context: context, + initialTime: TimeOfDay( + hour: _startTime.hour, + minute: _startTime.minute), + builder: (BuildContext context, + Widget? child) { + return Theme( + data: ThemeData( + brightness: widget.model + .themeData.brightness, + colorScheme: _getColorScheme( + widget.model, false), + accentColor: widget + .model.backgroundColor, + primaryColor: widget + .model.backgroundColor, + ), + child: child!, + ); + }); if (time != null && time != _startTime) { setState(() { @@ -3000,7 +3059,12 @@ class _AppointmentEditorState extends State { minute: _endDate.minute); }); } - })), + }, + child: Text( + DateFormat('hh:mm a').format(_startDate), + textAlign: TextAlign.right, + ), + )), ])), ListTile( contentPadding: const EdgeInsets.fromLTRB(5, 2, 5, 2), @@ -3011,85 +3075,81 @@ class _AppointmentEditorState extends State { Expanded( flex: 7, child: GestureDetector( - child: Text( - DateFormat('EEE, MMM dd yyyy').format(_endDate), - textAlign: TextAlign.left, - ), - onTap: () async { - final DateTime date = await showDatePicker( - context: context, - initialDate: _endDate, - firstDate: DateTime(1900), - lastDate: DateTime(2100), - builder: - (BuildContext context, Widget child) { - return Theme( - data: ThemeData( - brightness: - widget.model.themeData.brightness, - colorScheme: - _getColorScheme(widget.model, true), - accentColor: - widget.model.backgroundColor, - primaryColor: - widget.model.backgroundColor, - ), - child: child, - ); - }); - - if (date != null && date != _endDate) { - setState(() { - final Duration difference = - _endDate.difference(_startDate); - _endDate = DateTime( - date.year, - date.month, - date.day, - _endTime.hour, - _endTime.minute, - 0); - if (_endDate.isBefore(_startDate)) { - _startDate = _endDate.subtract(difference); - _startTime = TimeOfDay( - hour: _startDate.hour, - minute: _startDate.minute); - } + onTap: () async { + final DateTime? date = await showDatePicker( + context: context, + initialDate: _endDate, + firstDate: DateTime(1900), + lastDate: DateTime(2100), + builder: (BuildContext context, Widget? child) { + return Theme( + data: ThemeData( + brightness: + widget.model.themeData.brightness, + colorScheme: + _getColorScheme(widget.model, true), + accentColor: widget.model.backgroundColor, + primaryColor: + widget.model.backgroundColor, + ), + child: child!, + ); }); - } - }), + + if (date != null && date != _endDate) { + setState(() { + final Duration difference = + _endDate.difference(_startDate); + _endDate = DateTime( + date.year, + date.month, + date.day, + _endTime.hour, + _endTime.minute, + 0); + if (_endDate.isBefore(_startDate)) { + _startDate = _endDate.subtract(difference); + _startTime = TimeOfDay( + hour: _startDate.hour, + minute: _startDate.minute); + } + }); + } + }, + child: Text( + DateFormat('EEE, MMM dd yyyy').format(_endDate), + textAlign: TextAlign.left, + ), + ), ), Expanded( flex: 3, child: _isAllDay ? const Text('') : GestureDetector( - child: Text( - DateFormat('hh:mm a').format(_endDate), - textAlign: TextAlign.right, - ), onTap: () async { - final TimeOfDay time = await showTimePicker( - context: context, - initialTime: TimeOfDay( - hour: _endTime.hour, - minute: _endTime.minute), - builder: (BuildContext context, - Widget child) { - return Theme( - data: ThemeData( - brightness: widget - .model.themeData.brightness, - colorScheme: _getColorScheme( - widget.model, false), - accentColor: - widget.model.backgroundColor, - primaryColor: - widget.model.backgroundColor, - ), - child: child, - ); - }); + final TimeOfDay? time = + await showTimePicker( + context: context, + initialTime: TimeOfDay( + hour: _endTime.hour, + minute: _endTime.minute), + builder: (BuildContext context, + Widget? child) { + return Theme( + data: ThemeData( + brightness: widget.model + .themeData.brightness, + colorScheme: _getColorScheme( + widget.model, false), + accentColor: widget + .model.backgroundColor, + primaryColor: widget + .model.backgroundColor, + ), + child: child!, + ); + }); if (time != null && time != _endTime) { setState(() { @@ -3112,7 +3172,12 @@ class _AppointmentEditorState extends State { } }); } - })), + }, + child: Text( + DateFormat('hh:mm a').format(_endDate), + textAlign: TextAlign.right, + ), + )), ])), ListTile( contentPadding: const EdgeInsets.fromLTRB(5, 2, 5, 2), @@ -3141,7 +3206,7 @@ class _AppointmentEditorState extends State { })); }, ), - widget.events.resources == null || widget.events.resources.isEmpty + widget.events.resources == null || widget.events.resources!.isEmpty ? Container() : ListTile( contentPadding: const EdgeInsets.fromLTRB(5, 2, 5, 2), @@ -3159,9 +3224,10 @@ class _AppointmentEditorState extends State { _unSelectedResources, widget.model, onChanged: (_PickerChangedDetails details) { - _resourceIds == null - ? _resourceIds = [details.resourceId] - : _resourceIds.add(details.resourceId); + _resourceIds = _resourceIds == null + ? [details.resourceId!] + : (_resourceIds!.sublist(0) + ..add(details.resourceId!)); _selectedResources = _getSelectedResources( _resourceIds, widget.events.resources); _unSelectedResources = _getUnSelectedResources( @@ -3209,7 +3275,7 @@ class _AppointmentEditorState extends State { height: 1.0, thickness: 1, ), - widget.model.isWeb + widget.model.isWebFullView ? ListTile( contentPadding: const EdgeInsets.all(5), leading: Icon( @@ -3234,7 +3300,7 @@ class _AppointmentEditorState extends State { ), ) : Container(), - widget.model.isWeb + widget.model.isWebFullView ? const Divider( height: 1.0, thickness: 1, @@ -3253,7 +3319,7 @@ class _AppointmentEditorState extends State { _notes = value; }, keyboardType: TextInputType.multiline, - maxLines: widget.model.isWeb ? 1 : null, + maxLines: widget.model.isWebFullView ? 1 : null, style: TextStyle( fontSize: 18, color: defaultColor, @@ -3269,7 +3335,7 @@ class _AppointmentEditorState extends State { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { return Theme( data: widget.model.themeData, child: Scaffold( @@ -3298,12 +3364,12 @@ class _AppointmentEditorState extends State { onPressed: () { final List appointment = []; if (widget.selectedAppointment != null) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.selectedAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - []..add(widget.selectedAppointment)); + [widget.selectedAppointment!]); } appointment.add(Appointment( startTime: _startDate, @@ -3322,7 +3388,7 @@ class _AppointmentEditorState extends State { subject: _subject == '' ? '(No title)' : _subject, resourceIds: _resourceIds)); - widget.events.appointments.add(appointment[0]); + widget.events.appointments!.add(appointment[0]); widget.events.notifyListeners( CalendarDataSourceAction.add, appointment); @@ -3336,11 +3402,9 @@ class _AppointmentEditorState extends State { children: [ _getAppointmentEditor( context, - widget.model.themeData != null && - widget.model.themeData.brightness == - Brightness.dark + (widget.model.themeData.brightness == Brightness.dark ? Colors.grey[850] - : Colors.white, + : Colors.white)!, widget.model.themeData.brightness != null && widget.model.themeData.brightness == Brightness.dark @@ -3349,37 +3413,36 @@ class _AppointmentEditorState extends State { ], ), ), - floatingActionButton: widget.model.isWeb + floatingActionButton: widget.model.isWebFullView ? null : widget.selectedAppointment == null ? const Text('') : FloatingActionButton( onPressed: () { if (widget.selectedAppointment != null) { - widget.events.appointments.removeAt(widget - .events.appointments + widget.events.appointments!.removeAt(widget + .events.appointments! .indexOf(widget.selectedAppointment)); widget.events.notifyListeners( CalendarDataSourceAction.remove, - [] - ..add(widget.selectedAppointment)); + [widget.selectedAppointment!]); Navigator.pop(context); } }, + backgroundColor: widget.model.backgroundColor, child: const Icon(Icons.delete_outline, color: Colors.white), - backgroundColor: widget.model.backgroundColor, ))); } /// Return the resource editor to edit the resource collection for an /// appointment - Widget _getResourceEditor([TextStyle hintTextStyle]) { + Widget _getResourceEditor(TextStyle hintTextStyle) { if (_selectedResources == null || _selectedResources.isEmpty) { return Text('Add people', style: hintTextStyle); } - List chipWidgets = []; + final List chipWidgets = []; for (int i = 0; i < _selectedResources.length; i++) { final CalendarResource selectedResource = _selectedResources[i]; chipWidgets.add(Chip( @@ -3394,7 +3457,7 @@ class _AppointmentEditorState extends State { label: Text(selectedResource.displayName), onDeleted: () { _selectedResources.removeAt(i); - _resourceIds.removeAt(i); + _resourceIds?.removeAt(i); _unSelectedResources = _getUnSelectedResources( _selectedResources, widget.events.resources); setState(() {}); @@ -3418,15 +3481,18 @@ CalendarResource _getResourceFromId( /// Returns the selected resources based on the id collection passed List _getSelectedResources( - List _resourceIds, List resourceCollection) { - if (_resourceIds == null || _resourceIds.isEmpty) { - return null; + List? resourceIds, List? resourceCollection) { + final List _selectedResources = []; + if (resourceIds == null || + resourceIds.isEmpty || + resourceCollection == null || + resourceCollection.isEmpty) { + return _selectedResources; } - final List _selectedResources = []; - for (int i = 0; i < _resourceIds.length; i++) { + for (int i = 0; i < resourceIds.length; i++) { final CalendarResource resourceName = - _getResourceFromId(_resourceIds[i], resourceCollection); + _getResourceFromId(resourceIds[i], resourceCollection); _selectedResources.add(resourceName); } @@ -3436,13 +3502,16 @@ List _getSelectedResources( /// Returns the available resource, by filtering the resource collection from /// the selected resource collection. List _getUnSelectedResources( - List selectedResources, - List resourceCollection) { - if (selectedResources == null || selectedResources.isEmpty) { - return resourceCollection; + List? selectedResources, + List? resourceCollection) { + if (selectedResources == null || + selectedResources.isEmpty || + resourceCollection == null || + resourceCollection.isEmpty) { + return resourceCollection ?? []; } - List collection = resourceCollection.sublist(0); + final List collection = resourceCollection.sublist(0); for (int i = 0; i < resourceCollection.length; i++) { final CalendarResource resource = resourceCollection[i]; for (int j = 0; j < selectedResources.length; j++) { diff --git a/lib/samples/calendar/calendar_loadmore.dart b/lib/samples/calendar/calendar_loadmore.dart new file mode 100644 index 00000000..d4fe0885 --- /dev/null +++ b/lib/samples/calendar/calendar_loadmore.dart @@ -0,0 +1,347 @@ +///Dart imports +import 'dart:math'; + +///Package imports +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +///calendar import +import 'package:syncfusion_flutter_calendar/calendar.dart'; + +///Local import +import '../../model/sample_view.dart'; + +/// Widget of getting started calendar +class LoadMoreCalendar extends SampleView { + /// Creates default getting started calendar + const LoadMoreCalendar(Key key) : super(key: key); + + @override + _LoadMoreCalendarState createState() => _LoadMoreCalendarState(); +} + +Map> _dataCollection = >{}; + +class _LoadMoreCalendarState extends SampleViewState { + _LoadMoreCalendarState(); + + final _MeetingDataSource _events = _MeetingDataSource(<_Meeting>[]); + final CalendarController _calendarController = CalendarController(); + CalendarView _view = CalendarView.month; + + final List _allowedViews = [ + CalendarView.day, + CalendarView.week, + CalendarView.workWeek, + CalendarView.month, + CalendarView.schedule, + CalendarView.timelineDay, + CalendarView.timelineWeek, + CalendarView.timelineWorkWeek, + CalendarView.timelineMonth, + ]; + + final ScrollController _controller = ScrollController(); + + /// Global key used to maintain the state, when we change the parent of the + /// widget + final GlobalKey _globalKey = GlobalKey(); + + @override + void initState() { + _calendarController.view = _view; + _addAppointmentDetails(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final Widget calendar = Theme( + + /// The key set here to maintain the state, + /// when we change the parent of the widget + key: _globalKey, + data: model.themeData.copyWith(accentColor: model.backgroundColor), + child: _getLoadMoreCalendar(_calendarController, _onViewChanged, + _events, _scheduleViewBuilder)); + + final double screenHeight = MediaQuery.of(context).size.height; + return Scaffold( + body: Row(children: [ + Expanded( + child: _calendarController.view == CalendarView.month && + model.isWebFullView && + screenHeight < 800 + ? Scrollbar( + isAlwaysShown: true, + controller: _controller, + child: ListView( + controller: _controller, + children: [ + Container( + color: model.cardThemeColor, + height: 600, + child: calendar, + ) + ], + )) + : Container(color: model.cardThemeColor, child: calendar), + ) + ]), + ); + } + + /// Handle the view changed and it used to update the UI on web platform + /// whether the calendar view changed from month view or to month view. + void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { + if (_view == _calendarController.view) { + return; + } + + if ((_calendarController.view == CalendarView.month || + _view == CalendarView.month) && + model.isWebFullView) { + _view = _calendarController.view!; + SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { + setState(() { + /// Update the web UI when the calendar view changed from month view + /// or to month view. + }); + }); + } + + _view = _calendarController.view!; + } + + /// Creates the required appointment details as a list. + void _addAppointmentDetails() { + final List _subjectCollection = []; + _subjectCollection.add('General Meeting'); + _subjectCollection.add('Plan Execution'); + _subjectCollection.add('Project Plan'); + _subjectCollection.add('Consulting'); + _subjectCollection.add('Support'); + _subjectCollection.add('Development Meeting'); + _subjectCollection.add('Scrum'); + _subjectCollection.add('Project Completion'); + _subjectCollection.add('Release updates'); + _subjectCollection.add('Performance Check'); + + final List _colorCollection = []; + _colorCollection.add(const Color(0xFF0F8644)); + _colorCollection.add(const Color(0xFF8B1FA9)); + _colorCollection.add(const Color(0xFFD20100)); + _colorCollection.add(const Color(0xFFFC571D)); + _colorCollection.add(const Color(0xFF36B37B)); + _colorCollection.add(const Color(0xFF01A1EF)); + _colorCollection.add(const Color(0xFF3D4FB5)); + _colorCollection.add(const Color(0xFFE47C73)); + _colorCollection.add(const Color(0xFF636363)); + _colorCollection.add(const Color(0xFF0A8043)); + + final Random random = Random(); + _dataCollection = >{}; + final DateTime today = DateTime.now(); + final DateTime rangeStartDate = DateTime(today.year, today.month, today.day) + .add(const Duration(days: -1000)); + final DateTime rangeEndDate = DateTime(today.year, today.month, today.day) + .add(const Duration(days: 1000)); + for (DateTime i = rangeStartDate; + i.isBefore(rangeEndDate); + i = i.add(Duration(days: 1 + random.nextInt(2)))) { + final DateTime date = i; + final int count = 1 + random.nextInt(3); + for (int j = 0; j < count; j++) { + final DateTime startDate = DateTime( + date.year, date.month, date.day, 8 + random.nextInt(8), 0, 0); + final int duration = random.nextInt(3); + final _Meeting meeting = _Meeting( + _subjectCollection[random.nextInt(7)], + startDate, + startDate.add(Duration(hours: duration == 0 ? 1 : duration)), + _colorCollection[random.nextInt(9)], + false); + + if (_dataCollection.containsKey(date)) { + final List<_Meeting> meetings = _dataCollection[date]!; + meetings.add(meeting); + _dataCollection[date] = meetings; + } else { + _dataCollection[date] = [meeting]; + } + } + } + } + + /// Returns the calendar widget based on the properties passed. + SfCalendar _getLoadMoreCalendar( + [CalendarController? calendarController, + ViewChangedCallback? viewChangedCallback, + CalendarDataSource? calendarDataSource, + dynamic scheduleViewBuilder]) { + return SfCalendar( + controller: calendarController, + dataSource: calendarDataSource, + allowedViews: _allowedViews, + onViewChanged: viewChangedCallback, + scheduleViewMonthHeaderBuilder: scheduleViewBuilder, + showNavigationArrow: model.isWebFullView, + blackoutDatesTextStyle: TextStyle( + decoration: model.isWebFullView ? null : TextDecoration.lineThrough, + color: Colors.red), + loadMoreWidgetBuilder: + (BuildContext context, LoadMoreCallback loadMoreAppointments) { + return FutureBuilder( + future: loadMoreAppointments(), + builder: (context, snapShot) { + return Container( + height: _calendarController.view == CalendarView.schedule + ? 50 + : double.infinity, + width: double.infinity, + alignment: Alignment.center, + child: CircularProgressIndicator( + valueColor: + AlwaysStoppedAnimation(model.backgroundColor))); + }, + ); + }, + monthViewSettings: MonthViewSettings( + appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, + appointmentDisplayCount: 4), + timeSlotViewSettings: TimeSlotViewSettings( + minimumAppointmentDuration: const Duration(minutes: 60))); + } +} + +/// Returns the month name based on the month value passed from date. +String _getMonthDate(int month) { + if (month == 01) { + return 'January'; + } else if (month == 02) { + return 'February'; + } else if (month == 03) { + return 'March'; + } else if (month == 04) { + return 'April'; + } else if (month == 05) { + return 'May'; + } else if (month == 06) { + return 'June'; + } else if (month == 07) { + return 'July'; + } else if (month == 08) { + return 'August'; + } else if (month == 09) { + return 'September'; + } else if (month == 10) { + return 'October'; + } else if (month == 11) { + return 'November'; + } else { + return 'December'; + } +} + +/// Returns the builder for schedule view. +Widget _scheduleViewBuilder( + BuildContext buildContext, ScheduleViewMonthHeaderDetails details) { + final String monthName = _getMonthDate(details.date.month); + return Stack( + children: [ + Image( + image: ExactAssetImage('images/' + monthName + '.png'), + fit: BoxFit.cover, + width: details.bounds.width, + height: details.bounds.height), + Positioned( + left: 55, + right: 0, + top: 20, + bottom: 0, + child: Text( + monthName + ' ' + details.date.year.toString(), + style: TextStyle(fontSize: 18), + ), + ) + ], + ); +} + +/// An object to set the appointment collection data source to collection, which +/// used to map the custom appointment data to the calendar appointment, and +/// allows to add, remove or reset the appointment collection. +class _MeetingDataSource extends CalendarDataSource { + _MeetingDataSource(this.source); + + List<_Meeting> source; + + @override + List get appointments => source; + + @override + DateTime getStartTime(int index) { + return source[index].from; + } + + @override + DateTime getEndTime(int index) { + return source[index].to; + } + + @override + bool isAllDay(int index) { + return source[index].isAllDay; + } + + @override + String getSubject(int index) { + return source[index].eventName; + } + + @override + Color getColor(int index) { + return source[index].background; + } + + @override + Future handleLoadMore(DateTime startDate, DateTime endDate) async { + await Future.delayed(Duration(seconds: 1)); + final List<_Meeting> meetings = <_Meeting>[]; + DateTime date = DateTime(startDate.year, startDate.month, startDate.day); + final DateTime appEndDate = + DateTime(endDate.year, endDate.month, endDate.day, 23, 59, 59); + while (date.isBefore(appEndDate)) { + final List<_Meeting>? data = _dataCollection[date]; + if (data == null) { + date = date.add(Duration(days: 1)); + continue; + } + + for (final _Meeting meeting in data) { + if (appointments.contains(meeting)) { + continue; + } + + meetings.add(meeting); + } + date = date.add(Duration(days: 1)); + } + + appointments.addAll(meetings); + notifyListeners(CalendarDataSourceAction.add, meetings); + } +} + +/// Custom business object class which contains properties to hold the detailed +/// information about the event data which will be rendered in calendar. +class _Meeting { + _Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); + + String eventName; + DateTime from; + DateTime to; + Color background; + bool isAllDay; +} diff --git a/lib/samples/calendar/customization.dart b/lib/samples/calendar/customization.dart index d8fa26bd..1f892efc 100644 --- a/lib/samples/calendar/customization.dart +++ b/lib/samples/calendar/customization.dart @@ -13,6 +13,7 @@ import 'package:syncfusion_flutter_calendar/calendar.dart'; ///Local import import '../../model/sample_view.dart'; +import '../../samples/calendar/getting_started.dart'; /// Widget of customization calendar class CustomizationCalendar extends SampleView { @@ -26,11 +27,12 @@ class CustomizationCalendar extends SampleView { class _CustomizationCalendarState extends SampleViewState { _CustomizationCalendarState(); - List _subjectCollection; - List _iconCollection; - List _colorCollection; - _MeetingDataSource _events; - CalendarController _calendarController; + final List _subjectCollection = []; + final List _colorCollection = []; + final List _iconCollection = []; + final List _locationCollection = []; + final _MeetingDataSource _events = _MeetingDataSource(<_Meeting>[]); + final CalendarController _calendarController = CalendarController(); final List _allowedViews = [ CalendarView.week, @@ -42,28 +44,23 @@ class _CustomizationCalendarState extends SampleViewState { CalendarView.timelineMonth, ]; - ScrollController _controller; + final ScrollController _controller = ScrollController(); - CalendarView _currentView; + CalendarView _currentView = CalendarView.week; /// Global key used to maintain the state, when we change the parent of the /// widget - GlobalKey _globalKey; + final GlobalKey _globalKey = GlobalKey(); @override void initState() { - _calendarController = CalendarController(); - _currentView = CalendarView.week; _calendarController.view = _currentView; - _globalKey = GlobalKey(); - _controller = ScrollController(); addAppointmentDetails(); - _events = _MeetingDataSource(<_Meeting>[]); super.initState(); } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget calendar = Theme( /// The key set here to maintain the state, @@ -78,7 +75,7 @@ class _CustomizationCalendarState extends SampleViewState { body: Row(children: [ Expanded( child: _calendarController.view == CalendarView.month && - model.isWeb && + model.isWebFullView && screenHeight < 800 ? Scrollbar( isAlwaysShown: true, @@ -110,29 +107,29 @@ class _CustomizationCalendarState extends SampleViewState { /// Remove the scroll bar on sample while change the view from /// month view or change the view to month view. if (_currentView != _calendarController.view && - model.isWeb && + model.isWebFullView && (_currentView == CalendarView.month || _calendarController.view == CalendarView.month)) { - SchedulerBinding.instance.addPostFrameCallback((Duration duration) { + SchedulerBinding.instance?.addPostFrameCallback((Duration duration) { setState(() {}); }); } - _currentView = _calendarController.view; + _currentView = _calendarController.view!; if (_currentView == CalendarView.day || _currentView == CalendarView.week || _currentView == CalendarView.workWeek) { final Map events = {}; events['Environmental Discussion'] = - 'The day that creates awareness to promote the healthy planet and reduce air pollution crisis on nature earth'; + 'The day that encourages awareness to promote the healthy planet and reduce air pollution crisis on nature earth'; events['Health Checkup'] = 'The day that raises awareness on different health issues. It marks the anniversary of the foundation of WHO'; events['Cancer awareness'] = - 'The day that creates awareness on cancer and its preventive measures. Early detection saves life'; + 'The day that promotes awareness on cancer and its preventive measures. Early detection saves life'; events['Happiness'] = 'The general idea is to promote happiness and smile around the world'; events['Tourism'] = - 'The day that creates awareness to the role of tourism and its effect on social and economic values'; + 'The day that raises awareness to the role of tourism and its effect on social and economic values'; final List colors = [ Color(0xFF56AB56), Color(0xFF357CD2), @@ -154,7 +151,7 @@ class _CustomizationCalendarState extends SampleViewState { for (int i = 0; i < 5; i++) { final String key = keys[i]; appointment.add(_Meeting(key, date, date.add(Duration(hours: 6)), - colors[i], false, events[key], images[i], null)); + colors[i], false, events[key]!, images[i], null, '')); date = date.add(Duration(days: 1)); } } @@ -166,7 +163,7 @@ class _CustomizationCalendarState extends SampleViewState { final DateTime date = visibleDatesChangedDetails.visibleDates[i]; final int count = _currentView != CalendarView.month ? 1 - : 1 + random.nextInt(model.isWeb ? 2 : 3); + : 1 + random.nextInt(model.isWebFullView ? 2 : 3); for (int j = 0; j < count; j++) { final DateTime startDate = DateTime( date.year, date.month, date.day, 8 + random.nextInt(8), 0, 0); @@ -178,7 +175,8 @@ class _CustomizationCalendarState extends SampleViewState { false, '', '', - null)); + null, + '')); } } } else { @@ -190,7 +188,7 @@ class _CustomizationCalendarState extends SampleViewState { i.isBefore(rangeEndDate); i = i.add(const Duration(days: 1))) { final DateTime date = i; - final int count = 1 + random.nextInt(3); + final int count = 1 + random.nextInt(6); for (int j = 0; j < count; j++) { final DateTime startDate = DateTime( date.year, date.month, date.day, 8 + random.nextInt(8), 0, 0); @@ -198,12 +196,14 @@ class _CustomizationCalendarState extends SampleViewState { appointment.add(_Meeting( _subjectCollection[index], startDate, - startDate.add(Duration(hours: random.nextInt(3))), + startDate + .add(Duration(hours: random.nextInt(j % 4 == 0 ? 36 : 3))), _colorCollection[random.nextInt(9)], false, '', '', - _iconCollection[index])); + _iconCollection[index], + _locationCollection[random.nextInt(4)])); } } } @@ -219,7 +219,6 @@ class _CustomizationCalendarState extends SampleViewState { /// Creates the required appointment details as a list. void addAppointmentDetails() { - _subjectCollection = []; _subjectCollection.add('General Meeting'); _subjectCollection.add('Plan Execution'); _subjectCollection.add('Project Plan'); @@ -231,7 +230,6 @@ class _CustomizationCalendarState extends SampleViewState { _subjectCollection.add('Release updates'); _subjectCollection.add('Performance Check'); - _iconCollection = []; _iconCollection.add(Icons.people_outlined); _iconCollection.add(Icons.supervisor_account_outlined); _iconCollection.add(Icons.sticky_note_2_outlined); @@ -243,7 +241,6 @@ class _CustomizationCalendarState extends SampleViewState { _iconCollection.add(Icons.new_releases_outlined); _iconCollection.add(Icons.speed_outlined); - _colorCollection = []; _colorCollection.add(const Color(0xFF0F8644)); _colorCollection.add(const Color(0xFF8B1FA9)); _colorCollection.add(const Color(0xFFD20100)); @@ -254,6 +251,12 @@ class _CustomizationCalendarState extends SampleViewState { _colorCollection.add(const Color(0xFFE47C73)); _colorCollection.add(const Color(0xFF636363)); _colorCollection.add(const Color(0xFF0A8043)); + + _locationCollection.add('Paris'); + _locationCollection.add('New York'); + _locationCollection.add('London'); + _locationCollection.add('Chicago'); + _locationCollection.add('Singapore'); } Widget _getAppointmentUI( @@ -347,8 +350,8 @@ class _CustomizationCalendarState extends SampleViewState { model.isMobileResolution ? Container() : Text( - 'Time: ${DateFormat('hh:mm a').format(meeting.from)} - ' + - '${DateFormat('hh:mm a').format(meeting.to)}', + 'Time: ${DateFormat('hh:mm a').format(meeting.from)} - ' + '${DateFormat('hh:mm a').format(meeting.to)}', style: TextStyle( color: Colors.white, fontSize: 10, @@ -477,81 +480,103 @@ class _CustomizationCalendarState extends SampleViewState { ); } + final String format = + (meeting.to.difference(meeting.from).inHours < 24) ? 'HH:mm' : 'dd MMM'; + final Color iconColor = model.themeData == null || + model.themeData.brightness == Brightness.light + ? Colors.black87 + : Colors.white; + return Container( - child: Row( - children: [ - Container( - width: 20, - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(5), bottomLeft: Radius.circular(5)), - color: meeting.background, + padding: EdgeInsets.fromLTRB(0, 0, 8, 0), + color: model.themeData == null || + model.themeData.brightness == Brightness.light + ? model.webBackgroundColor + : model.cardColor, + child: Row( + children: [ + Container( + width: 8, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(3), + bottomLeft: Radius.circular(3)), + color: meeting.background, + ), ), - ), - Expanded( + Expanded( child: Container( - alignment: Alignment.center, - color: meeting.background.withOpacity(0.8), - padding: EdgeInsets.only(left: 2), - child: Row( - children: [ - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - meeting.eventName, - style: TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w500, - ), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.ellipsis, - ), - Text( - 'Time: ${DateFormat('hh:mm a').format(meeting.from)} - ' + - '${DateFormat('hh:mm a').format(meeting.to)}', - style: TextStyle( - color: Colors.white, - fontSize: 10, - ), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.ellipsis, - ) - ], - )), - _getScheduleAppointmentIcon(meeting), - Container( - margin: EdgeInsets.all(0), - width: 30, - alignment: Alignment.center, - child: Icon( - meeting.icon, - size: 20, - color: Colors.white, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.only( + topRight: Radius.circular(3), + bottomRight: Radius.circular(3)), + ), + padding: EdgeInsets.only(left: 7), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + meeting.eventName + (model.isWebFullView ? ', ' : ''), + style: TextStyle( + color: textColor, + fontSize: model.isWebFullView ? 15 : 18, + fontFamily: 'Roboto', + fontWeight: FontWeight.normal), + maxLines: 1, + softWrap: false, + overflow: TextOverflow.ellipsis, ), + model.isWebFullView + ? Text( + meeting.location, + style: TextStyle( + color: textColor.withOpacity(0.6), + fontFamily: 'Roboto', + fontSize: 14, + ), + maxLines: 1, + softWrap: false, + overflow: TextOverflow.ellipsis, + ) + : Text(''), + ], + ), + Text( + DateFormat(format).format(meeting.from).toString() + + ' - ' + + DateFormat(format).format(meeting.to).toString(), + style: TextStyle( + color: textColor.withOpacity(0.6), + fontFamily: 'Roboto', + fontSize: 14, ), - ], - ))), - Container( - margin: EdgeInsets.all(0), - width: 20, - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.only( - topRight: Radius.circular(5), - bottomRight: Radius.circular(5)), - color: meeting.background, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), ), - ), - ], - ), - ); + _getScheduleAppointmentIcon(meeting), + Container( + margin: EdgeInsets.all(0), + width: 30, + alignment: Alignment.center, + child: Icon( + meeting.icon, + size: 20, + color: iconColor, + ), + ), + ], + )); } Widget _getScheduleAppointmentIcon(_Meeting meeting) { @@ -575,19 +600,22 @@ class _CustomizationCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getCustomizationCalendar( - [CalendarController _calendarController, - CalendarDataSource _calendarDataSource, - ViewChangedCallback viewChangedCallback, - CalendarAppointmentBuilder appointmentBuilder]) { + [CalendarController? _calendarController, + CalendarDataSource? _calendarDataSource, + ViewChangedCallback? viewChangedCallback, + CalendarAppointmentBuilder? appointmentBuilder]) { return SfCalendar( controller: _calendarController, dataSource: _calendarDataSource, allowedViews: _allowedViews, appointmentBuilder: appointmentBuilder, - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, showDatePickerButton: true, cellEndPadding: 3, onViewChanged: viewChangedCallback, + scheduleViewMonthHeaderBuilder: scheduleViewBuilder, + scheduleViewSettings: ScheduleViewSettings( + appointmentItemHeight: model.isWebFullView ? 60 : 50), monthViewSettings: MonthViewSettings( appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, showTrailingAndLeadingDates: true, @@ -634,13 +662,18 @@ class _MeetingDataSource extends CalendarDataSource { Color getColor(int index) { return source[index].background; } + + @override + String? getLocation(int index) { + return source[index].location; + } } /// Custom business object class which contains properties to hold the detailed /// information about the event data which will be rendered in calendar. class _Meeting { _Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay, - this.notes, this.image, this.icon); + this.notes, this.image, this.icon, this.location); String eventName; DateTime from; @@ -649,5 +682,6 @@ class _Meeting { bool isAllDay; String notes; String image; - IconData icon; + IconData? icon; + String location; } diff --git a/lib/samples/calendar/getting_started.dart b/lib/samples/calendar/getting_started.dart index 36ac4865..3c74b805 100644 --- a/lib/samples/calendar/getting_started.dart +++ b/lib/samples/calendar/getting_started.dart @@ -24,12 +24,12 @@ class GettingStartedCalendar extends SampleView { class _GettingStartedCalendarState extends SampleViewState { _GettingStartedCalendarState(); - List _subjectCollection; - List _colorCollection; - List _blackoutDates; - _MeetingDataSource _events; - DateTime _minDate, _maxDate; - CalendarController _calendarController; + final List _subjectCollection = []; + final List _colorCollection = []; + final _MeetingDataSource _events = _MeetingDataSource(<_Meeting>[]); + final DateTime _minDate = + DateTime.now().subtract(const Duration(days: 365 ~/ 2)), + _maxDate = DateTime.now().add(const Duration(days: 365 ~/ 2)); final List _allowedViews = [ CalendarView.day, @@ -39,35 +39,33 @@ class _GettingStartedCalendarState extends SampleViewState { CalendarView.schedule ]; + final List _viewNavigationModeList = + ['Snap', 'None'].toList(); + + /// Global key used to maintain the state, when we change the parent of the + /// widget + final GlobalKey _globalKey = GlobalKey(); + final ScrollController _controller = ScrollController(); + final CalendarController _calendarController = CalendarController(); + + List _blackoutDates = []; bool _showLeadingAndTrailingDates = true; bool _showDatePickerButton = true; bool _allowViewNavigation = true; + bool _showCurrentTimeIndicator = true; - ScrollController _controller; - - /// Global key used to maintain the state, when we change the parent of the - /// widget - GlobalKey _globalKey; + ViewNavigationMode _viewNavigationMode = ViewNavigationMode.snap; + String _viewNavigationModeString = 'Snap'; @override void initState() { - _showLeadingAndTrailingDates = true; - _showDatePickerButton = true; - _allowViewNavigation = true; - _calendarController = CalendarController(); _calendarController.view = CalendarView.month; - _globalKey = GlobalKey(); - _controller = ScrollController(); - _blackoutDates = []; addAppointmentDetails(); - _events = _MeetingDataSource(<_Meeting>[]); - _minDate = DateTime.now().subtract(const Duration(days: 365 ~/ 2)); - _maxDate = DateTime.now().add(const Duration(days: 365 ~/ 2)); super.initState(); } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget calendar = Theme( /// The key set here to maintain the state, @@ -82,7 +80,7 @@ class _GettingStartedCalendarState extends SampleViewState { body: Row(children: [ Expanded( child: _calendarController.view == CalendarView.month && - model.isWeb && + model.isWebFullView && screenHeight < 800 ? Scrollbar( isAlwaysShown: true, @@ -119,13 +117,13 @@ class _GettingStartedCalendarState extends SampleViewState { } } - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { + SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { setState(() { if (_calendarController.view == CalendarView.month || _calendarController.view == CalendarView.timelineMonth) { _blackoutDates = blockedDates; } else { - _blackoutDates?.clear(); + _blackoutDates.clear(); } }); }); @@ -140,7 +138,7 @@ class _GettingStartedCalendarState extends SampleViewState { blockedDates.contains(date)) { continue; } - final int count = 1 + random.nextInt(model.isWeb ? 2 : 3); + final int count = 1 + random.nextInt(model.isWebFullView ? 2 : 3); for (int j = 0; j < count; j++) { final DateTime startDate = DateTime( date.year, date.month, date.day, 8 + random.nextInt(8), 0, 0); @@ -188,7 +186,6 @@ class _GettingStartedCalendarState extends SampleViewState { /// Creates the required appointment details as a list. void addAppointmentDetails() { - _subjectCollection = []; _subjectCollection.add('General Meeting'); _subjectCollection.add('Plan Execution'); _subjectCollection.add('Project Plan'); @@ -200,7 +197,6 @@ class _GettingStartedCalendarState extends SampleViewState { _subjectCollection.add('Release updates'); _subjectCollection.add('Performance Check'); - _colorCollection = []; _colorCollection.add(const Color(0xFF0F8644)); _colorCollection.add(const Color(0xFF8B1FA9)); _colorCollection.add(const Color(0xFFD20100)); @@ -213,6 +209,19 @@ class _GettingStartedCalendarState extends SampleViewState { _colorCollection.add(const Color(0xFF0A8043)); } + /// Allows/Restrict switching to previous/next views through swipe interaction + void onViewNavigationModeChange(String value) { + _viewNavigationModeString = value; + if (value == 'Snap') { + _viewNavigationMode = ViewNavigationMode.snap; + } else if (value == 'None') { + _viewNavigationMode = ViewNavigationMode.none; + } + setState(() { + /// update the view navigation mode changes + }); + } + @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -322,6 +331,77 @@ class _GettingStartedCalendarState extends SampleViewState { ], ), ), + Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Text('Show current time indicator', + style: + TextStyle(fontSize: 16.0, color: model.textColor))), + Container( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Theme( + data: Theme.of(context).copyWith( + canvasColor: model.bottomSheetBackgroundColor), + child: Container( + child: Align( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + activeColor: model.backgroundColor, + value: _showCurrentTimeIndicator, + onChanged: (bool value) { + setState(() { + _showCurrentTimeIndicator = value; + stateSetter(() {}); + }); + }, + )), + )), + ), + ) + ], + ), + ), + Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 6, + child: Text('View navigation mode', + style: + TextStyle(fontSize: 16.0, color: model.textColor))), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.only(left: 60), + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: + Container(color: Color(0xFFBDBDBD), height: 1), + value: _viewNavigationModeString, + items: _viewNavigationModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Snap', + child: Text('$value', + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + onViewNavigationModeChange(value); + stateSetter(() {}); + }), + ), + ) + ], + ), + ), ], ); }); @@ -329,33 +409,36 @@ class _GettingStartedCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getGettingStartedCalendar( - [CalendarController _calendarController, - CalendarDataSource _calendarDataSource, - ViewChangedCallback viewChangedCallback, - DateTime _minDate, - DateTime _maxDate, + [CalendarController? _calendarController, + CalendarDataSource? _calendarDataSource, + ViewChangedCallback? viewChangedCallback, + DateTime? _minDate, + DateTime? _maxDate, dynamic scheduleViewBuilder]) { return SfCalendar( - controller: _calendarController, - dataSource: _calendarDataSource, - allowedViews: _allowedViews, - scheduleViewMonthHeaderBuilder: scheduleViewBuilder, - showNavigationArrow: model.isWeb, - showDatePickerButton: _showDatePickerButton, - allowViewNavigation: _allowViewNavigation, - onViewChanged: viewChangedCallback, - blackoutDates: _blackoutDates, - blackoutDatesTextStyle: TextStyle( - decoration: model.isWeb ? null : TextDecoration.lineThrough, - color: Colors.red), - minDate: _minDate, - maxDate: _maxDate, - monthViewSettings: MonthViewSettings( - appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, - showTrailingAndLeadingDates: _showLeadingAndTrailingDates, - appointmentDisplayCount: 4), - timeSlotViewSettings: TimeSlotViewSettings( - minimumAppointmentDuration: const Duration(minutes: 60))); + controller: _calendarController, + dataSource: _calendarDataSource, + allowedViews: _allowedViews, + scheduleViewMonthHeaderBuilder: scheduleViewBuilder, + showNavigationArrow: model.isWebFullView, + showDatePickerButton: _showDatePickerButton, + allowViewNavigation: _allowViewNavigation, + showCurrentTimeIndicator: _showCurrentTimeIndicator, + onViewChanged: viewChangedCallback, + blackoutDates: _blackoutDates, + blackoutDatesTextStyle: TextStyle( + decoration: model.isWebFullView ? null : TextDecoration.lineThrough, + color: Colors.red), + minDate: _minDate, + maxDate: _maxDate, + monthViewSettings: MonthViewSettings( + appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, + showTrailingAndLeadingDates: _showLeadingAndTrailingDates, + appointmentDisplayCount: 4), + timeSlotViewSettings: TimeSlotViewSettings( + minimumAppointmentDuration: const Duration(minutes: 60)), + viewNavigationMode: _viewNavigationMode, + ); } } diff --git a/lib/samples/calendar/heatmap.dart b/lib/samples/calendar/heatmap.dart index 8bef9512..87ec5b48 100644 --- a/lib/samples/calendar/heatmap.dart +++ b/lib/samples/calendar/heatmap.dart @@ -27,21 +27,14 @@ class HeatMapCalendar extends SampleView { class _HeatMapCalendarCalendarState extends SampleViewState { _HeatMapCalendarCalendarState(); - ScrollController controller; + final ScrollController controller = ScrollController(); /// Global key used to maintain the state, when we change the parent of the /// widget - GlobalKey _globalKey; + final GlobalKey _globalKey = GlobalKey(); @override - void initState() { - _globalKey = GlobalKey(); - controller = ScrollController(); - super.initState(); - } - - @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final double screenWidth = MediaQuery.of(context).size.width; final Widget _calendar = Theme( @@ -113,7 +106,7 @@ class _HeatMapCalendarCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getHeatMapCalendar() { return SfCalendar( - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, view: CalendarView.month, monthCellBuilder: _monthCellBuilder, showDatePickerButton: true, diff --git a/lib/samples/calendar/recurrence.dart b/lib/samples/calendar/recurrence.dart index 180019fa..11ea4294 100644 --- a/lib/samples/calendar/recurrence.dart +++ b/lib/samples/calendar/recurrence.dart @@ -24,9 +24,8 @@ class RecurrenceCalendar extends SampleView { class _RecurrenceCalendarState extends SampleViewState { _RecurrenceCalendarState(); - List _appointments; - List colorCollection; - CalendarController calendarController; + final CalendarController calendarController = CalendarController(); + late _AppointmentDataSource _dataSource; final List _allowedViews = [ CalendarView.day, @@ -36,46 +35,37 @@ class _RecurrenceCalendarState extends SampleViewState { CalendarView.schedule ]; - ScrollController controller; + final ScrollController controller = ScrollController(); /// Global key used to maintain the state, when we change the parent of the /// widget - GlobalKey _globalKey; - CalendarView _view; + final GlobalKey _globalKey = GlobalKey(); + CalendarView _view = CalendarView.week; @override void initState() { - _globalKey = GlobalKey(); - controller = ScrollController(); - calendarController = CalendarController(); - calendarController.view = CalendarView.week; - _view = CalendarView.week; - _appointments = []; - _addColorCollection(); - _createRecursiveAppointments(); + calendarController.view = _view; + _dataSource = _AppointmentDataSource(_getRecursiveAppointments()); super.initState(); } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget _calendar = Theme( /// The key set here to maintain the state, when we change /// the parent of the widget key: _globalKey, data: model.themeData.copyWith(accentColor: model.backgroundColor), - child: _getRecurrenceCalendar( - calendarController, - _AppointmentDataSource(_appointments), - _onViewChanged, - scheduleViewBuilder)); + child: _getRecurrenceCalendar(calendarController, _dataSource, + _onViewChanged, scheduleViewBuilder)); final double _screenHeight = MediaQuery.of(context).size.height; return Scaffold( body: Row(children: [ Expanded( child: calendarController.view == CalendarView.month && - model.isWeb && + model.isWebFullView && _screenHeight < 800 ? Scrollbar( isAlwaysShown: true, @@ -100,15 +90,15 @@ class _RecurrenceCalendarState extends SampleViewState { /// view or switched to different calendar view. void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { if (_view == calendarController.view || - !model.isWeb || + !model.isWebFullView || (_view != CalendarView.month && calendarController.view != CalendarView.month)) { return; } - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { + SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { setState(() { - _view = calendarController.view; + _view = calendarController.view!; /// Update the current view when the calendar view changed to /// month view or from month view. @@ -118,245 +108,232 @@ class _RecurrenceCalendarState extends SampleViewState { /// Creates the data source with the recurrence appointments by adding required /// information on it. - void _createRecursiveAppointments() { + List _getRecursiveAppointments() { + final List colorCollection = []; + colorCollection.add(const Color(0xFF0F8644)); + colorCollection.add(const Color(0xFF8B1FA9)); + colorCollection.add(const Color(0xFFD20100)); + colorCollection.add(const Color(0xFFFC571D)); + colorCollection.add(const Color(0xFF36B37B)); + colorCollection.add(const Color(0xFF01A1EF)); + colorCollection.add(const Color(0xFF3D4FB5)); + colorCollection.add(const Color(0xFFE47C73)); + colorCollection.add(const Color(0xFF636363)); + colorCollection.add(const Color(0xFF0A8043)); + + final List appointments = []; final Random random = Random(); //Recurrence Appointment 1 - final Appointment alternativeDayAppointment = Appointment(); final DateTime currentDate = DateTime.now(); final DateTime startTime = DateTime(currentDate.year, currentDate.month, currentDate.day, 9, 0, 0); final DateTime endTime = DateTime( currentDate.year, currentDate.month, currentDate.day, 11, 0, 0); - alternativeDayAppointment.startTime = startTime; - alternativeDayAppointment.endTime = endTime; - alternativeDayAppointment.color = colorCollection[random.nextInt(9)]; - alternativeDayAppointment.subject = 'Scrum meeting'; final RecurrenceProperties recurrencePropertiesForAlternativeDay = - RecurrenceProperties(); - recurrencePropertiesForAlternativeDay.recurrenceType = RecurrenceType.daily; - recurrencePropertiesForAlternativeDay.interval = 2; - recurrencePropertiesForAlternativeDay.recurrenceRange = - RecurrenceRange.count; - recurrencePropertiesForAlternativeDay.recurrenceCount = 20; - alternativeDayAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForAlternativeDay, - alternativeDayAppointment.startTime, - alternativeDayAppointment.endTime); - _appointments.add(alternativeDayAppointment); + RecurrenceProperties( + startDate: startTime, + recurrenceType: RecurrenceType.daily, + interval: 2, + recurrenceRange: RecurrenceRange.count, + recurrenceCount: 20); + final Appointment alternativeDayAppointment = Appointment( + startTime: startTime, + endTime: endTime, + color: colorCollection[random.nextInt(9)], + subject: 'Scrum meeting', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForAlternativeDay, startTime, endTime)); + + appointments.add(alternativeDayAppointment); //Recurrence Appointment 2 - final Appointment weeklyAppointment = Appointment(); final DateTime startTime1 = DateTime( currentDate.year, currentDate.month, currentDate.day, 13, 0, 0); final DateTime endTime1 = DateTime( currentDate.year, currentDate.month, currentDate.day, 15, 0, 0); - weeklyAppointment.startTime = startTime1; - weeklyAppointment.endTime = endTime1; - weeklyAppointment.color = colorCollection[random.nextInt(9)]; - weeklyAppointment.subject = 'product development status'; - final RecurrenceProperties recurrencePropertiesForWeeklyAppointment = - RecurrenceProperties(); - recurrencePropertiesForWeeklyAppointment.recurrenceType = - RecurrenceType.weekly; - recurrencePropertiesForWeeklyAppointment.recurrenceRange = - RecurrenceRange.count; - recurrencePropertiesForWeeklyAppointment.interval = 1; - recurrencePropertiesForWeeklyAppointment.weekDays = [] - ..add(WeekDays.monday); - recurrencePropertiesForWeeklyAppointment.recurrenceCount = 20; - weeklyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForWeeklyAppointment, - weeklyAppointment.startTime, - weeklyAppointment.endTime); - _appointments.add(weeklyAppointment); - - final Appointment monthlyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime1, + recurrenceType: RecurrenceType.weekly, + recurrenceRange: RecurrenceRange.count, + interval: 1, + weekDays: [WeekDays.monday], + recurrenceCount: 20, + ); + + final Appointment weeklyAppointment = Appointment( + startTime: startTime1, + endTime: endTime1, + color: colorCollection[random.nextInt(9)], + subject: 'product development status', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForWeeklyAppointment, startTime1, endTime1)); + + appointments.add(weeklyAppointment); + final DateTime startTime2 = DateTime( currentDate.year, currentDate.month, currentDate.day, 14, 0, 0); final DateTime endTime2 = DateTime( currentDate.year, currentDate.month, currentDate.day, 15, 0, 0); - monthlyAppointment.startTime = startTime2; - monthlyAppointment.endTime = endTime2; - monthlyAppointment.color = colorCollection[random.nextInt(9)]; - monthlyAppointment.subject = 'Sprint planning meeting'; - final RecurrenceProperties recurrencePropertiesForMonthlyAppointment = - RecurrenceProperties(); - recurrencePropertiesForMonthlyAppointment.recurrenceType = - RecurrenceType.monthly; - recurrencePropertiesForMonthlyAppointment.recurrenceRange = - RecurrenceRange.count; - recurrencePropertiesForMonthlyAppointment.interval = 1; - recurrencePropertiesForMonthlyAppointment.dayOfMonth = 1; - recurrencePropertiesForMonthlyAppointment.recurrenceCount = 10; - monthlyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForMonthlyAppointment, - monthlyAppointment.startTime, - monthlyAppointment.endTime); - _appointments.add(monthlyAppointment); - - final Appointment yearlyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime2, + recurrenceType: RecurrenceType.monthly, + recurrenceRange: RecurrenceRange.count, + interval: 1, + dayOfMonth: 1, + recurrenceCount: 10); + + final Appointment monthlyAppointment = Appointment( + startTime: startTime2, + endTime: endTime2, + color: colorCollection[random.nextInt(9)], + subject: 'Sprint planning meeting', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForMonthlyAppointment, startTime2, endTime2)); + + appointments.add(monthlyAppointment); + final DateTime startTime3 = DateTime( currentDate.year, currentDate.month, currentDate.day, 12, 0, 0); final DateTime endTime3 = DateTime( currentDate.year, currentDate.month, currentDate.day, 14, 0, 0); - yearlyAppointment.startTime = startTime3; - yearlyAppointment.endTime = endTime3; - yearlyAppointment.color = colorCollection[random.nextInt(9)]; - yearlyAppointment.isAllDay = true; - yearlyAppointment.subject = 'Stephen birthday'; - final RecurrenceProperties recurrencePropertiesForYearlyAppointment = - RecurrenceProperties(); - recurrencePropertiesForYearlyAppointment.recurrenceType = - RecurrenceType.yearly; - recurrencePropertiesForYearlyAppointment.recurrenceRange = - RecurrenceRange.noEndDate; - recurrencePropertiesForYearlyAppointment.interval = 1; - recurrencePropertiesForYearlyAppointment.dayOfMonth = 5; - yearlyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForYearlyAppointment, - yearlyAppointment.startTime, - yearlyAppointment.endTime); - _appointments.add(yearlyAppointment); - - final Appointment customDailyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime3, + recurrenceType: RecurrenceType.yearly, + recurrenceRange: RecurrenceRange.noEndDate, + interval: 1, + dayOfMonth: 5); + + final Appointment yearlyAppointment = Appointment( + startTime: startTime3, + endTime: endTime3, + color: colorCollection[random.nextInt(9)], + isAllDay: true, + subject: 'Stephen birthday', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForYearlyAppointment, startTime3, endTime3)); + + appointments.add(yearlyAppointment); + final DateTime startTime4 = DateTime( currentDate.year, currentDate.month, currentDate.day, 17, 0, 0); final DateTime endTime4 = DateTime( currentDate.year, currentDate.month, currentDate.day, 18, 0, 0); - customDailyAppointment.startTime = startTime4; - customDailyAppointment.endTime = endTime4; - customDailyAppointment.color = colorCollection[random.nextInt(9)]; - customDailyAppointment.subject = 'General meeting'; - final RecurrenceProperties recurrencePropertiesForCustomDailyAppointment = - RecurrenceProperties(); - recurrencePropertiesForCustomDailyAppointment.recurrenceType = - RecurrenceType.daily; - recurrencePropertiesForCustomDailyAppointment.recurrenceRange = - RecurrenceRange.noEndDate; - recurrencePropertiesForCustomDailyAppointment.interval = 1; - customDailyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForCustomDailyAppointment, - customDailyAppointment.startTime, - customDailyAppointment.endTime); - _appointments.add(customDailyAppointment); - - final Appointment customWeeklyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime4, + recurrenceType: RecurrenceType.daily, + recurrenceRange: RecurrenceRange.noEndDate, + interval: 1); + + final Appointment customDailyAppointment = Appointment( + startTime: startTime4, + endTime: endTime4, + color: colorCollection[random.nextInt(9)], + subject: 'General meeting', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForCustomDailyAppointment, startTime4, endTime4), + ); + + appointments.add(customDailyAppointment); + final DateTime startTime5 = DateTime( currentDate.year, currentDate.month, currentDate.day, 12, 0, 0); final DateTime endTime5 = DateTime( currentDate.year, currentDate.month, currentDate.day, 13, 0, 0); - customWeeklyAppointment.startTime = startTime5; - customWeeklyAppointment.endTime = endTime5; - customWeeklyAppointment.color = colorCollection[random.nextInt(9)]; - customWeeklyAppointment.subject = 'performance check'; - final RecurrenceProperties recurrencePropertiesForCustomWeeklyAppointment = - RecurrenceProperties(); - recurrencePropertiesForCustomWeeklyAppointment.recurrenceType = - RecurrenceType.weekly; - recurrencePropertiesForCustomWeeklyAppointment.recurrenceRange = - RecurrenceRange.endDate; - recurrencePropertiesForCustomWeeklyAppointment.interval = 1; - recurrencePropertiesForCustomWeeklyAppointment.weekDays = [ - WeekDays.monday, - WeekDays.friday - ]; - recurrencePropertiesForCustomWeeklyAppointment.endDate = - DateTime.now().add(const Duration(days: 14)); - customWeeklyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForCustomWeeklyAppointment, - customWeeklyAppointment.startTime, - customWeeklyAppointment.endTime); - _appointments.add(customWeeklyAppointment); - - final Appointment customMonthlyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime5, + recurrenceType: RecurrenceType.weekly, + recurrenceRange: RecurrenceRange.endDate, + interval: 1, + weekDays: [WeekDays.monday, WeekDays.friday], + endDate: DateTime.now().add(const Duration(days: 14))); + + final Appointment customWeeklyAppointment = Appointment( + startTime: startTime5, + endTime: endTime5, + color: colorCollection[random.nextInt(9)], + subject: 'performance check', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForCustomWeeklyAppointment, + startTime5, + endTime5)); + + appointments.add(customWeeklyAppointment); + final DateTime startTime6 = DateTime( currentDate.year, currentDate.month, currentDate.day, 16, 0, 0); final DateTime endTime6 = DateTime( currentDate.year, currentDate.month, currentDate.day, 18, 0, 0); - customMonthlyAppointment.startTime = startTime6; - customMonthlyAppointment.endTime = endTime6; - customMonthlyAppointment.color = colorCollection[random.nextInt(9)]; - customMonthlyAppointment.subject = 'Sprint end meeting'; final RecurrenceProperties recurrencePropertiesForCustomMonthlyAppointment = - RecurrenceProperties(); - recurrencePropertiesForCustomMonthlyAppointment.recurrenceType = - RecurrenceType.monthly; - recurrencePropertiesForCustomMonthlyAppointment.recurrenceRange = - RecurrenceRange.count; - recurrencePropertiesForCustomMonthlyAppointment.interval = 1; - recurrencePropertiesForCustomMonthlyAppointment.dayOfWeek = DateTime.friday; - recurrencePropertiesForCustomMonthlyAppointment.week = 4; - recurrencePropertiesForCustomMonthlyAppointment.recurrenceCount = 12; - customMonthlyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForCustomMonthlyAppointment, - customMonthlyAppointment.startTime, - customMonthlyAppointment.endTime); - _appointments.add(customMonthlyAppointment); - - final Appointment customYearlyAppointment = Appointment(); + RecurrenceProperties( + startDate: startTime6, + recurrenceType: RecurrenceType.monthly, + recurrenceRange: RecurrenceRange.count, + interval: 1, + dayOfWeek: DateTime.friday, + week: 4, + recurrenceCount: 12); + + final Appointment customMonthlyAppointment = Appointment( + startTime: startTime6, + endTime: endTime6, + color: colorCollection[random.nextInt(9)], + subject: 'Sprint end meeting', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForCustomMonthlyAppointment, + startTime6, + endTime6)); + + appointments.add(customMonthlyAppointment); + final DateTime startTime7 = DateTime( currentDate.year, currentDate.month, currentDate.day, 14, 0, 0); final DateTime endTime7 = DateTime( currentDate.year, currentDate.month, currentDate.day, 15, 0, 0); - customYearlyAppointment.startTime = startTime7; - customYearlyAppointment.endTime = endTime7; - customYearlyAppointment.color = colorCollection[random.nextInt(9)]; - customYearlyAppointment.subject = 'Alumini meet'; - final RecurrenceProperties recurrencePropertiesForCustomYearlyAppointment = - RecurrenceProperties(); - recurrencePropertiesForCustomYearlyAppointment.recurrenceType = - RecurrenceType.yearly; - recurrencePropertiesForCustomYearlyAppointment.recurrenceRange = - RecurrenceRange.count; - recurrencePropertiesForCustomYearlyAppointment.interval = 2; - recurrencePropertiesForCustomYearlyAppointment.month = DateTime.february; - recurrencePropertiesForCustomYearlyAppointment.week = 2; - recurrencePropertiesForCustomYearlyAppointment.dayOfWeek = DateTime.sunday; - recurrencePropertiesForCustomYearlyAppointment.recurrenceCount = 10; - customYearlyAppointment.recurrenceRule = SfCalendar.generateRRule( - recurrencePropertiesForCustomYearlyAppointment, - customYearlyAppointment.startTime, - customYearlyAppointment.endTime); - _appointments.add(customYearlyAppointment); - } - - /// Adds the collection of color in a list for the appointment data source for - /// calendar. - void _addColorCollection() { - colorCollection = []; - colorCollection.add(const Color(0xFF0F8644)); - colorCollection.add(const Color(0xFF8B1FA9)); - colorCollection.add(const Color(0xFFD20100)); - colorCollection.add(const Color(0xFFFC571D)); - colorCollection.add(const Color(0xFF36B37B)); - colorCollection.add(const Color(0xFF01A1EF)); - colorCollection.add(const Color(0xFF3D4FB5)); - colorCollection.add(const Color(0xFFE47C73)); - colorCollection.add(const Color(0xFF636363)); - colorCollection.add(const Color(0xFF0A8043)); + RecurrenceProperties( + startDate: startTime7, + recurrenceType: RecurrenceType.yearly, + recurrenceRange: RecurrenceRange.count, + interval: 2, + month: DateTime.february, + week: 2, + dayOfWeek: DateTime.sunday, + recurrenceCount: 10); + + final Appointment customYearlyAppointment = Appointment( + startTime: startTime7, + endTime: endTime7, + color: colorCollection[random.nextInt(9)], + subject: 'Alumini meet', + recurrenceRule: SfCalendar.generateRRule( + recurrencePropertiesForCustomYearlyAppointment, + startTime7, + endTime7)); + + appointments.add(customYearlyAppointment); + return appointments; } /// Returns the calendar widget based on the properties passed SfCalendar _getRecurrenceCalendar( - [CalendarController _calendarController, - CalendarDataSource _calendarDataSource, + [CalendarController? calendarController, + CalendarDataSource? calendarDataSource, dynamic onViewChanged, dynamic scheduleViewBuilder]) { return SfCalendar( - showNavigationArrow: model.isWeb, - controller: _calendarController, + showNavigationArrow: model.isWebFullView, + controller: calendarController, allowedViews: _allowedViews, scheduleViewMonthHeaderBuilder: scheduleViewBuilder, showDatePickerButton: true, onViewChanged: onViewChanged, - dataSource: _calendarDataSource, + dataSource: calendarDataSource, monthViewSettings: MonthViewSettings( appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, appointmentDisplayCount: 4), diff --git a/lib/samples/calendar/schedule_view.dart b/lib/samples/calendar/schedule_view.dart index a73a60ac..b3adf34b 100644 --- a/lib/samples/calendar/schedule_view.dart +++ b/lib/samples/calendar/schedule_view.dart @@ -23,23 +23,18 @@ class ScheduleViewCalendar extends SampleView { class _ScheduleViewCalendarState extends SampleViewState { _ScheduleViewCalendarState(); - List subjectCollection; - List colorCollection; - List appointments; - _DataSource events; + late _DataSource events; @override void initState() { - appointments = []; - addAppointmentDetails(); - addAppointments(); - events = _DataSource(appointments); + events = _DataSource(_getAppointments()); super.initState(); } - /// Creates the required appointment details as a list. - void addAppointmentDetails() { - subjectCollection = []; + /// Method that creates the collection the data source for calendar, with + /// required information. + List _getAppointments() { + final List subjectCollection = []; subjectCollection.add('General Meeting'); subjectCollection.add('Plan Execution'); subjectCollection.add('Project Plan'); @@ -50,7 +45,7 @@ class _ScheduleViewCalendarState extends SampleViewState { subjectCollection.add('Release updates'); subjectCollection.add('Performance Check'); - colorCollection = []; + final List colorCollection = []; colorCollection.add(const Color(0xFF0F8644)); colorCollection.add(const Color(0xFF8B1FA9)); colorCollection.add(const Color(0xFFD20100)); @@ -61,15 +56,12 @@ class _ScheduleViewCalendarState extends SampleViewState { colorCollection.add(const Color(0xFFE47C73)); colorCollection.add(const Color(0xFF636363)); colorCollection.add(const Color(0xFF0A8043)); - } - /// Method that creates the collection the data source for calendar, with - /// required information. - void addAppointments() { final Random random = Random(); final DateTime rangeStartDate = DateTime.now().add(const Duration(days: -(365 ~/ 2))); final DateTime rangeEndDate = DateTime.now().add(const Duration(days: 365)); + final List appointments = []; for (DateTime i = rangeStartDate; i.isBefore(rangeEndDate); i = i.add(Duration(days: random.nextInt(10)))) { @@ -98,6 +90,7 @@ class _ScheduleViewCalendarState extends SampleViewState { color: colorCollection[random.nextInt(9)], isAllDay: false, recurrenceRule: 'FREQ=DAILY;INTERVAL=10')); + return appointments; } @override @@ -112,7 +105,7 @@ class _ScheduleViewCalendarState extends SampleViewState { /// returns the calendar widget based on the properties passed SfCalendar getScheduleViewCalendar( - {_DataSource events, dynamic scheduleViewBuilder}) { + {_DataSource? events, dynamic scheduleViewBuilder}) { return SfCalendar( showDatePickerButton: true, scheduleViewMonthHeaderBuilder: scheduleViewBuilder, diff --git a/lib/samples/calendar/shift_scheduler.dart b/lib/samples/calendar/shift_scheduler.dart index fee96804..1757bbf8 100644 --- a/lib/samples/calendar/shift_scheduler.dart +++ b/lib/samples/calendar/shift_scheduler.dart @@ -22,22 +22,17 @@ class ShiftScheduler extends SampleView { class _ShiftSchedulerState extends SampleViewState { _ShiftSchedulerState(); - List _subjectCollection; - List _colorCollection; - List _shiftCollection; - List _employeeCollection; - List _specialTimeRegions; - List _nameCollection; - List _userImages; - _ShiftDataSource _events; - Appointment _selectedAppointment; - bool _isAllDay = false; - String _subject = ''; - DateTime _startDate, _endDate; - int _selectedColorIndex = 0; - List _colorNames; - List _timeZoneCollection; - CalendarController _calendarController; + final List _subjectCollection = []; + final List _colorCollection = []; + final List _shiftCollection = []; + final List _employeeCollection = []; + final List _specialTimeRegions = []; + final List _nameCollection = []; + final List _userImages = []; + final List _colorNames = []; + final List _timeZoneCollection = []; + + final CalendarController _calendarController = CalendarController(); final List _allowedViews = [ CalendarView.timelineDay, @@ -46,15 +41,18 @@ class _ShiftSchedulerState extends SampleViewState { CalendarView.timelineMonth ]; + bool _isAllDay = false; + String _subject = ''; + int _selectedColorIndex = 0; + + Appointment? _selectedAppointment; + + late _ShiftDataSource _events; + @override void initState() { - _calendarController = CalendarController(); _calendarController.view = CalendarView.timelineWeek; _selectedAppointment = null; - _shiftCollection = []; - _employeeCollection = []; - _specialTimeRegions = []; - _userImages = []; _addResourceDetails(); _addResources(); _addSpecialRegions(); @@ -79,27 +77,28 @@ class _ShiftSchedulerState extends SampleViewState { /// Navigates the calendar to day view, /// when we tap on month cells in mobile. - if (!model.isWeb && _calendarController.view == CalendarView.month) { + if (!model.isWebFullView && + _calendarController.view == CalendarView.month) { _calendarController.view = CalendarView.day; } else { if (calendarTapDetails.appointments != null && calendarTapDetails.targetElement == CalendarElement.appointment) { - _selectedAppointment = calendarTapDetails.appointments[0]; + _selectedAppointment = calendarTapDetails.appointments![0]; } - final DateTime selectedDate = calendarTapDetails.date; + final DateTime selectedDate = calendarTapDetails.date!; final CalendarElement targetElement = calendarTapDetails.targetElement; /// To open the appointment editor for web, /// when the screen width is greater than 767. - if (model.isWeb && !model.isMobileResolution) { + if (model.isWebFullView && !model.isMobileResolution) { final bool _isAppointmentTapped = calendarTapDetails.targetElement == CalendarElement.appointment; showDialog( context: context, builder: (BuildContext context) { final List appointment = []; - Appointment newAppointment; + Appointment? newAppointment; /// Creates a new appointment, which is displayed on the tapped /// calendar element, when the editor is opened. @@ -108,24 +107,22 @@ class _ShiftSchedulerState extends SampleViewState { CalendarElement.allDayPanel; _selectedColorIndex = 0; _subject = ''; - final DateTime date = calendarTapDetails.date; - _startDate = date; - _endDate = date.add(const Duration(hours: 1)); + final DateTime date = calendarTapDetails.date!; newAppointment = Appointment( - startTime: _startDate, - endTime: _endDate, - resourceIds: [calendarTapDetails.resource.id], + startTime: date, + endTime: date.add(const Duration(hours: 1)), + resourceIds: [calendarTapDetails.resource!.id], color: _colorCollection[_selectedColorIndex], isAllDay: _isAllDay, subject: _subject == '' ? '(No title)' : _subject, ); appointment.add(newAppointment); - _events.appointments.add(appointment[0]); + _events.appointments!.add(appointment[0]); SchedulerBinding.instance - .addPostFrameCallback((Duration duration) { + ?.addPostFrameCallback((Duration duration) { _events.notifyListeners( CalendarDataSourceAction.add, appointment); }); @@ -138,10 +135,10 @@ class _ShiftSchedulerState extends SampleViewState { if (newAppointment != null) { /// To remove the created appointment when the pop-up closed /// without saving the appointment. - _events.appointments - .removeAt(_events.appointments.indexOf(newAppointment)); + _events.appointments!.removeAt( + _events.appointments!.indexOf(newAppointment)); _events.notifyListeners(CalendarDataSourceAction.remove, - []..add(newAppointment)); + [newAppointment]); } return true; }, @@ -149,8 +146,8 @@ class _ShiftSchedulerState extends SampleViewState { child: Container( width: _isAppointmentTapped ? 400 : 500, height: _isAppointmentTapped - ? (_selectedAppointment.location == null || - _selectedAppointment.location.isEmpty + ? (_selectedAppointment!.location == null || + _selectedAppointment!.location!.isEmpty ? 200 : 250) : 450, @@ -168,7 +165,7 @@ class _ShiftSchedulerState extends SampleViewState { targetElement, selectedDate, model, - _selectedAppointment, + _selectedAppointment!, _colorCollection, _colorNames, _events, @@ -180,7 +177,7 @@ class _ShiftSchedulerState extends SampleViewState { _events, _colorCollection, _colorNames, - _selectedAppointment, + _selectedAppointment!, _timeZoneCollection), )))), ); @@ -217,7 +214,6 @@ class _ShiftSchedulerState extends SampleViewState { /// Creates the required resource details as list void _addResourceDetails() { - _nameCollection = []; _nameCollection.add('John'); _nameCollection.add('Bryan'); _nameCollection.add('Robert'); @@ -239,7 +235,6 @@ class _ShiftSchedulerState extends SampleViewState { _nameCollection.add('Addison'); _nameCollection.add('Ruby'); - _userImages = []; _userImages.add('images/People_Circle5.png'); _userImages.add('images/People_Circle8.png'); _userImages.add('images/People_Circle18.png'); @@ -256,7 +251,6 @@ class _ShiftSchedulerState extends SampleViewState { /// Creates the required appointment details as a list. void _addAppointmentDetails() { - _subjectCollection = []; _subjectCollection.add('General Meeting'); _subjectCollection.add('Plan Execution'); _subjectCollection.add('Project Plan'); @@ -268,7 +262,6 @@ class _ShiftSchedulerState extends SampleViewState { _subjectCollection.add('Release updates'); _subjectCollection.add('Performance Check'); - _colorCollection = []; _colorCollection.add(const Color(0xFF0F8644)); _colorCollection.add(const Color(0xFF8B1FA9)); _colorCollection.add(const Color(0xFFD20100)); @@ -279,7 +272,6 @@ class _ShiftSchedulerState extends SampleViewState { _colorCollection.add(const Color(0xFFE47C73)); _colorCollection.add(const Color(0xFF636363)); - _colorNames = []; _colorNames.add('Green'); _colorNames.add('Purple'); _colorNames.add('Red'); @@ -290,7 +282,6 @@ class _ShiftSchedulerState extends SampleViewState { _colorNames.add('Peach'); _colorNames.add('Gray'); - _timeZoneCollection = []; _timeZoneCollection.add('Default Time'); _timeZoneCollection.add('AUS Central Standard Time'); _timeZoneCollection.add('AUS Eastern Standard Time'); @@ -400,7 +391,7 @@ class _ShiftSchedulerState extends SampleViewState { /// Method that creates the resource collection for the calendar, with the /// required information. void _addResources() { - Random random = Random(); + final Random random = Random(); for (int i = 0; i < _nameCollection.length; i++) { _employeeCollection.add(CalendarResource( displayName: _nameCollection[i], @@ -416,7 +407,7 @@ class _ShiftSchedulerState extends SampleViewState { /// required information. void _addSpecialRegions() { final DateTime date = DateTime.now(); - Random random = Random(); + final Random random = Random(); for (int i = 0; i < _employeeCollection.length; i++) { _specialTimeRegions.add(TimeRegion( startTime: DateTime(date.year, date.month, date.day, 13, 0, 0), @@ -447,14 +438,16 @@ class _ShiftSchedulerState extends SampleViewState { /// Method that creates the collection the data source for calendar, with /// required information. void _addAppointments() { - _shiftCollection = []; final Random random = Random(); for (int i = 0; i < _employeeCollection.length; i++) { - final List _employeeIds = [_employeeCollection[i].id]; + final _employeeIds = [_employeeCollection[i].id]; if (i == _employeeCollection.length - 1) { int index = random.nextInt(5); index = index == i ? index + 1 : index; - _employeeIds.add(_employeeCollection[index].id); + final employeeId = _employeeCollection[index].id; + if (employeeId is String) { + _employeeIds.add(employeeId); + } } for (int k = 0; k < 365; k++) { @@ -508,7 +501,7 @@ class _ShiftSchedulerState extends SampleViewState { /// Returns the calendar widget based on the properties passed SfCalendar _getShiftScheduler( - [CalendarDataSource _calendarDataSource, + [CalendarDataSource? _calendarDataSource, dynamic calendarTapCallback, dynamic viewChangedCallback]) { return SfCalendar( @@ -517,7 +510,7 @@ class _ShiftSchedulerState extends SampleViewState { allowedViews: _allowedViews, timeRegionBuilder: _getSpecialRegionWidget, specialRegions: _specialTimeRegions, - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, dataSource: _calendarDataSource, onViewChanged: viewChangedCallback, onTap: calendarTapCallback, diff --git a/lib/samples/calendar/special_regions.dart b/lib/samples/calendar/special_regions.dart index 828fcf05..64ef8de8 100644 --- a/lib/samples/calendar/special_regions.dart +++ b/lib/samples/calendar/special_regions.dart @@ -22,8 +22,7 @@ class SpecialRegionsCalendar extends SampleView { class _SpecialRegionsCalendarState extends SampleViewState { _SpecialRegionsCalendarState(); - List regions; - CalendarController calendarController; + final CalendarController calendarController = CalendarController(); final List _allowedViews = [ CalendarView.day, CalendarView.week, @@ -33,26 +32,19 @@ class _SpecialRegionsCalendarState extends SampleViewState { CalendarView.timelineWorkWeek ]; - List subjectCollection; - List colorCollection; - List _appointments; - _DataSource events; + List regions = []; + late _DataSource events; @override void initState() { - _appointments = []; - calendarController = CalendarController(); calendarController.view = CalendarView.week; - _addAppointmentDetails(); - _addAppointments(); - events = _DataSource(_appointments); - _addRegions(); + events = _DataSource(_getAppointments()); + _updateRegions(); super.initState(); } /// Adds the special time region for the calendar with the required information - void _addRegions() { - regions = []; + void _updateRegions() { final DateTime date = DateTime.now().add(Duration(days: -DateTime.now().weekday)); regions.add(TimeRegion( @@ -113,9 +105,10 @@ class _SpecialRegionsCalendarState extends SampleViewState { )); } - /// Creates the required appointment details as a list. - void _addAppointmentDetails() { - subjectCollection = []; + /// Method that creates the collection the data source for calendar, with + /// required information. + List _getAppointments() { + final List subjectCollection = []; subjectCollection.add('General Meeting'); subjectCollection.add('Plan Execution'); subjectCollection.add('Project Plan'); @@ -127,7 +120,7 @@ class _SpecialRegionsCalendarState extends SampleViewState { subjectCollection.add('Release updates'); subjectCollection.add('Performance Check'); - colorCollection = []; + final List colorCollection = []; colorCollection.add(const Color(0xFF0F8644)); colorCollection.add(const Color(0xFF8B1FA9)); colorCollection.add(const Color(0xFFD20100)); @@ -138,15 +131,12 @@ class _SpecialRegionsCalendarState extends SampleViewState { colorCollection.add(const Color(0xFFE47C73)); colorCollection.add(const Color(0xFF636363)); colorCollection.add(const Color(0xFF0A8043)); - } - /// Method that creates the collection the data source for calendar, with - /// required information. - void _addAppointments() { final Random random = Random(); final DateTime rangeStartDate = DateTime.now().add(const Duration(days: -(365 ~/ 2))); final DateTime rangeEndDate = DateTime.now().add(const Duration(days: 365)); + final List appointments = []; for (DateTime i = rangeStartDate; i.isBefore(rangeEndDate); i = i.add(const Duration(days: 1))) { @@ -157,12 +147,14 @@ class _SpecialRegionsCalendarState extends SampleViewState { final DateTime startDate = DateTime(date.year, date.month, date.day, (date.weekday % 2 == 0 ? 14 : 9) + random.nextInt(3), 0, 0); - _appointments.add(Appointment( + appointments.add(Appointment( subject: subjectCollection[random.nextInt(7)], startTime: startDate, endTime: startDate.add(const Duration(hours: 1)), color: colorCollection[random.nextInt(9)])); } + + return appointments; } @override @@ -207,9 +199,9 @@ class _SpecialRegionsCalendarState extends SampleViewState { /// Return the calendar widget based on the properties passed SfCalendar _getSpecialRegionCalendar( - {List regions, _DataSource dataSource}) { + {List? regions, _DataSource? dataSource}) { return SfCalendar( - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, controller: calendarController, showDatePickerButton: true, allowedViews: _allowedViews, diff --git a/lib/samples/calendar/timeline_views.dart b/lib/samples/calendar/timeline_views.dart index 05aa664c..446ec246 100644 --- a/lib/samples/calendar/timeline_views.dart +++ b/lib/samples/calendar/timeline_views.dart @@ -23,11 +23,9 @@ class TimelineViewsCalendar extends SampleView { class _TimelineViewsCalendarState extends SampleViewState { _TimelineViewsCalendarState(); - List _subjectCollection; - List _colorCollection; - List _blackoutDates; - _MeetingDataSource _events; - CalendarController _calendarController; + final List _subjectCollection = []; + final List _colorCollection = []; + final CalendarController _calendarController = CalendarController(); final List _allowedViews = [ CalendarView.timelineDay, @@ -36,18 +34,19 @@ class _TimelineViewsCalendarState extends SampleViewState { CalendarView.timelineMonth, ]; + List _blackoutDates = []; + late _MeetingDataSource _events; + @override void initState() { - _calendarController = CalendarController(); _calendarController.view = CalendarView.timelineMonth; - _blackoutDates = []; addAppointmentDetails(); _events = _MeetingDataSource(<_Meeting>[]); super.initState(); } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { return Scaffold( body: Row(children: [ Expanded( @@ -78,12 +77,12 @@ class _TimelineViewsCalendarState extends SampleViewState { } } - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { + SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { setState(() { if (_calendarController.view == CalendarView.timelineMonth) { _blackoutDates = blockedDates; } else { - _blackoutDates?.clear(); + _blackoutDates.clear(); } }); }); @@ -98,7 +97,7 @@ class _TimelineViewsCalendarState extends SampleViewState { continue; } final int count = - model.isWeb ? 1 + random.nextInt(2) : 1 + random.nextInt(3); + model.isWebFullView ? 1 + random.nextInt(2) : 1 + random.nextInt(3); for (int j = 0; j < count; j++) { final DateTime startDate = DateTime( date.year, date.month, date.day, 8 + random.nextInt(8), 0, 0); @@ -128,7 +127,6 @@ class _TimelineViewsCalendarState extends SampleViewState { /// Creates the required appointment details as a list. void addAppointmentDetails() { - _subjectCollection = []; _subjectCollection.add('General Meeting'); _subjectCollection.add('Plan Execution'); _subjectCollection.add('Project Plan'); @@ -140,7 +138,6 @@ class _TimelineViewsCalendarState extends SampleViewState { _subjectCollection.add('Release updates'); _subjectCollection.add('Performance Check'); - _colorCollection = []; _colorCollection.add(const Color(0xFF0F8644)); _colorCollection.add(const Color(0xFF8B1FA9)); _colorCollection.add(const Color(0xFFD20100)); @@ -155,19 +152,19 @@ class _TimelineViewsCalendarState extends SampleViewState { /// Returns the calendar widget based on the properties passed. SfCalendar _getTimelineViewsCalendar( - [CalendarController _calendarController, - CalendarDataSource _calendarDataSource, - ViewChangedCallback viewChangedCallback]) { + [CalendarController? _calendarController, + CalendarDataSource? _calendarDataSource, + ViewChangedCallback? viewChangedCallback]) { return SfCalendar( controller: _calendarController, dataSource: _calendarDataSource, allowedViews: _allowedViews, - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, showDatePickerButton: true, onViewChanged: viewChangedCallback, blackoutDates: _blackoutDates, blackoutDatesTextStyle: TextStyle( - decoration: model.isWeb ? null : TextDecoration.lineThrough, + decoration: model.isWebFullView ? null : TextDecoration.lineThrough, color: Colors.red), timeSlotViewSettings: TimeSlotViewSettings( minimumAppointmentDuration: const Duration(minutes: 60))); @@ -183,7 +180,7 @@ class _MeetingDataSource extends CalendarDataSource { List<_Meeting> source; @override - List get appointments => source; + List<_Meeting> get appointments => source; @override DateTime getStartTime(int index) { @@ -206,12 +203,12 @@ class _MeetingDataSource extends CalendarDataSource { } @override - String getStartTimeZone(int index) { + String? getStartTimeZone(int index) { return source[index].startTimeZone; } @override - String getEndTimeZone(int index) { + String? getEndTimeZone(int index) { return source[index].endTimeZone; } @@ -221,7 +218,7 @@ class _MeetingDataSource extends CalendarDataSource { } @override - String getRecurrenceRule(int index) { + String? getRecurrenceRule(int index) { return source[index].recurrenceRule; } } @@ -243,14 +240,14 @@ class _Meeting { this.recurrenceRule); String eventName; - String organizer; - String contactID; - int capacity; + String? organizer; + String? contactID; + int? capacity; DateTime from; DateTime to; Color background; bool isAllDay; - String startTimeZone; - String endTimeZone; - String recurrenceRule; + String? startTimeZone; + String? endTimeZone; + String? recurrenceRule; } diff --git a/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart b/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart index 89576df0..4350db13 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart @@ -27,7 +27,7 @@ class _AxisAnimationDefaultState extends SampleViewState { _AxisAnimationDefaultState() { _timer = Timer.periodic(const Duration(milliseconds: 2000), _getChartData); } - Timer _timer; + late Timer _timer; double _count = 0; final List<_ChartData> _chartData = <_ChartData>[ @@ -75,9 +75,9 @@ class _AxisAnimationDefaultState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _animation, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _animation = value; + _animation = value!; stateSetter(() {}); }); })), @@ -89,11 +89,11 @@ class _AxisAnimationDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getAxisAnimation(); + return _buildAxisAnimation(); } /// Returns the Cartesian chart axis animation. - SfCartesianChart _getAxisAnimation() { + SfCartesianChart _buildAxisAnimation() { return SfCartesianChart( enableAxisAnimation: _animation, plotAreaBorderWidth: 0, @@ -177,7 +177,7 @@ class _AxisAnimationDefaultState extends SampleViewState { } } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart b/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart index f01ecbce..c817b9ca 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart @@ -21,14 +21,14 @@ class AxisCrossing extends SampleView { class _AxisCrossingState extends SampleViewState { _AxisCrossingState(); final List _axis = ['x', 'y'].toList(); - // final List _series = ['column', 'bar', 'spline'].toList(); String _selectedSeriesType = 'column'; //ignore: unused_field - String _selectedSeries; + late String _selectedSeries; String _selectedAxisType = 'x'; - String _selectedAxis; - double _crossAt = 0; - bool _isPlaceLabelsNearAxisLine = true; + late String _selectedAxis; + double? _crossAt = 0; + bool? _isPlaceLabelsNearAxisLine = true; + late TooltipBehavior _tooltipBehavior; @override void initState() { @@ -38,12 +38,14 @@ class _AxisCrossingState extends SampleViewState { _selectedSeries = 'column'; _crossAt = 0; _isPlaceLabelsNearAxisLine = true; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getAxisCrossingSample(); + return _buildAxisCrossingSample(); } @override @@ -104,9 +106,9 @@ class _AxisCrossingState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _isPlaceLabelsNearAxisLine, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _isPlaceLabelsNearAxisLine = value; + _isPlaceLabelsNearAxisLine = value!; stateSetter(() {}); }); })), @@ -118,7 +120,7 @@ class _AxisCrossingState extends SampleViewState { } /// Returns the spline chart with axis crossing at provided axis value. - SfCartesianChart _getAxisCrossingSample() { + SfCartesianChart _buildAxisCrossingSample() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Spline Interpolation'), @@ -146,8 +148,7 @@ class _AxisCrossingState extends SampleViewState { crossesAt: _selectedAxisType == 'y' ? _crossAt ?? 0 : 0, minorTicksPerInterval: 3), series: _getSeries(_selectedSeriesType), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } @@ -155,7 +156,7 @@ class _AxisCrossingState extends SampleViewState { /// the spline chart with axis crossing. List> _getSeries(String seriesType) { - List> chart = null; + List> chart; final List chartData = [ ChartSampleData(x: -7, y: -3), ChartSampleData(x: -4.5, y: -2), diff --git a/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart b/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart index b1a24417..8a993a38 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart @@ -63,7 +63,7 @@ class _CustomLabelsEventState extends SampleViewState { @override Widget build(BuildContext context) { - WidgetsBinding.instance.addPostFrameCallback((Duration duration) { + WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { _isYear = true; _isMonth = false; _isDay = false; @@ -75,7 +75,7 @@ class _CustomLabelsEventState extends SampleViewState { backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, 0, 5, bottomPadding), - child: Container(child: _getEventLineChart(false, _chartData)), + child: Container(child: _buildEventLineChart(false, _chartData)), ), floatingActionButton: isCardView ? null : _segmentedControl()); } @@ -136,39 +136,38 @@ class _CustomLabelsEventState extends SampleViewState { } /// Get the cartesian chart widget - SfCartesianChart _getEventLineChart(bool isTileView, - [List<_LabelData> data]) { + SfCartesianChart _buildEventLineChart(bool isTileView, + [List<_LabelData>? data]) { return SfCartesianChart( plotAreaBorderWidth: 0, - onAxisLabelRender: (AxisLabelRenderArgs args) { - if (args.axis is DateTimeAxis) { - if (_isYear && _formatter4.format(_current).toString() == args.text) { - args.text = 'Current\nYear'; - args.textStyle = - const TextStyle(fontStyle: FontStyle.italic, color: Colors.red); - } - if (_isMonth && - _formatter3.format(_current).toString() == args.text) { - args.text = 'Current\nMonth'; - args.textStyle = - const TextStyle(fontStyle: FontStyle.italic, color: Colors.red); - } - if (_isDay && _formatter.format(_current).toString() == args.text) { - args.text = 'Today'; - args.textStyle = - const TextStyle(fontStyle: FontStyle.italic, color: Colors.red); - } - if (_isHours && - _formatter1.format(_current).toString() == args.text) { - args.text = 'Current\nHour'; - args.textStyle = - const TextStyle(fontStyle: FontStyle.italic, color: Colors.red); - } - if (_isMin && _formatter2.format(_current).toString() == args.text) { - args.text = 'Now'; - args.textStyle = - const TextStyle(fontStyle: FontStyle.italic, color: Colors.red); - } + axisLabelFormatter: (AxisLabelRenderDetails details) { + if (details.axis is DateTimeAxis && + _isYear && + _formatter4.format(_current).toString() == details.text) { + return ChartAxisLabel('Current\nYear', + const TextStyle(fontStyle: FontStyle.italic, color: Colors.red)); + } else if (details.axis is DateTimeAxis && + _isMonth && + _formatter3.format(_current).toString() == details.text) { + return ChartAxisLabel('Current\nMonth', + const TextStyle(fontStyle: FontStyle.italic, color: Colors.red)); + } else if (details.axis is DateTimeAxis && + _isDay && + _formatter.format(_current).toString() == details.text) { + return ChartAxisLabel('Today', + const TextStyle(fontStyle: FontStyle.italic, color: Colors.red)); + } else if (details.axis is DateTimeAxis && + _isHours && + _formatter1.format(_current).toString() == details.text) { + return ChartAxisLabel('Current\nHour', + const TextStyle(fontStyle: FontStyle.italic, color: Colors.red)); + } else if (details.axis is DateTimeAxis && + _isMin && + _formatter2.format(_current).toString() == details.text) { + return ChartAxisLabel('Now', + const TextStyle(fontStyle: FontStyle.italic, color: Colors.red)); + } else { + return ChartAxisLabel(details.text, null); } }, primaryXAxis: DateTimeAxis( @@ -194,7 +193,7 @@ class _CustomLabelsEventState extends SampleViewState { } final Random random = Random(); - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/edge_label_placement.dart b/lib/samples/chart/cartesian_charts/axis_features/edge_label_placement.dart index a095d9e7..acc7b50d 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/edge_label_placement.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/edge_label_placement.dart @@ -22,19 +22,22 @@ class _EdgeLabelState extends SampleViewState { _EdgeLabelState(); final List _edgeList = ['hide', 'none', 'shift'].toList(); - String _selectedType; - EdgeLabelPlacement _edgeLabelPlacement; + late String _selectedType; + late EdgeLabelPlacement _edgeLabelPlacement; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedType = 'shift'; _edgeLabelPlacement = EdgeLabelPlacement.shift; + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.y'); super.initState(); } @override Widget build(BuildContext context) { - return _getEdgeLabelPlacementChart(); + return _buildEdgeLabelPlacementChart(); } @override @@ -78,7 +81,7 @@ class _EdgeLabelState extends SampleViewState { } /// Returns the spline with edge label placement chart. - SfCartesianChart _getEdgeLabelPlacementChart() { + SfCartesianChart _buildEdgeLabelPlacementChart() { return SfCartesianChart( plotAreaBorderWidth: 1, title: ChartTitle(text: isCardView ? '' : 'Fuel price in India'), @@ -108,8 +111,7 @@ class _EdgeLabelState extends SampleViewState { title: AxisTitle(text: isCardView ? '' : 'Rupees per litre'), ), series: _getEdgeLabelPlacementSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.y'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/handling_label_collision.dart b/lib/samples/chart/cartesian_charts/axis_features/handling_label_collision.dart index 53bf4cc4..7964019b 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/handling_label_collision.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/handling_label_collision.dart @@ -28,19 +28,25 @@ class _LabelActionState extends SampleViewState { 'wrap' ].toList(); String _selectedType = 'hide'; - AxisLabelIntersectAction _labelIntersectAction = + late AxisLabelIntersectAction _labelIntersectAction = AxisLabelIntersectAction.hide; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedType = 'hide'; _labelIntersectAction = AxisLabelIntersectAction.hide; + _tooltipBehavior = TooltipBehavior( + enable: true, + format: 'point.x : point.y Goals', + header: '', + canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getLabelIntersectActionChart(); + return _buildLabelIntersectActionChart(); } @override @@ -65,7 +71,7 @@ class _LabelActionState extends SampleViewState { child: Text('$value', style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onPositionTypeChange(value.toString()); stateSetter(() {}); }), @@ -76,7 +82,7 @@ class _LabelActionState extends SampleViewState { } /// Returns the column chart with label intersect action option. - SfCartesianChart _getLabelIntersectActionChart() { + SfCartesianChart _buildLabelIntersectActionChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -90,17 +96,13 @@ class _LabelActionState extends SampleViewState { interval: 40, majorTickLines: MajorTickLines(size: 0)), series: _getLabelIntersectActionSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - format: 'point.x : point.y Goals', - header: '', - canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } /// Returns the list of chart series which need to render on the column chart. List> _getLabelIntersectActionSeries() { - final List chartData = model.isWeb + final List chartData = model.isWebFullView ? [ ChartSampleData(x: 'Josef Bican', y: 805), ChartSampleData(x: 'Romário', y: 772), diff --git a/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart b/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart index 51d7e4b9..f7d7651a 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart @@ -26,20 +26,26 @@ class _ChartMaximumLabelWidthState extends SampleViewState { // ignore: unused_field bool _isEnableMaximumLabelWidth = true; // ignore: unused_field - List _isSelected; + late List _isSelected; String _selectedType = 'Maximum label width'; //ignore: unused_field - List _typeList = ['Maximum label width', 'Labels extent']; + final List _typeList = [ + 'Maximum label width', + 'Labels extent' + ]; + late TooltipBehavior _tooltipBehavior; @override void initState() { _isSelected = [true, false]; + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); super.initState(); } @override Widget build(BuildContext context) { - return _getmaximumLabelWidthChart(); + return _buildmaximumLabelWidthChart(); } @override @@ -60,7 +66,7 @@ class _ChartMaximumLabelWidthState extends SampleViewState { style: TextStyle(color: model.textColor)), ), Container( - padding: !model.isWeb + padding: !model.isWebFullView ? EdgeInsets.fromLTRB(32, 0, 0, 0) : EdgeInsets.fromLTRB(42, 0, 0, 0), child: CustomDirectionalButtons( @@ -92,9 +98,9 @@ class _ChartMaximumLabelWidthState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _isEnableLabelExtend, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _isEnableLabelExtend = value; + _isEnableLabelExtend = value!; stateSetter(() {}); }); })) @@ -110,7 +116,7 @@ class _ChartMaximumLabelWidthState extends SampleViewState { Text('Labels extent', style: TextStyle(color: model.textColor)), Container( - padding: !model.isWeb + padding: !model.isWebFullView ? EdgeInsets.fromLTRB(40, 0, 0, 0) : EdgeInsets.fromLTRB(50, 0, 0, 0), child: CustomDirectionalButtons( @@ -138,7 +144,7 @@ class _ChartMaximumLabelWidthState extends SampleViewState { } /// Returns the Cartesian chart with sorting options. - SfCartesianChart _getmaximumLabelWidthChart() { + SfCartesianChart _buildmaximumLabelWidthChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : "World's tallest buildings"), plotAreaBorderWidth: 0, @@ -146,9 +152,9 @@ class _ChartMaximumLabelWidthState extends SampleViewState { args.text = args.dataPoints[args.pointIndex].y.toString() + ' m'; }, onTooltipRender: (TooltipArgs args) { - args.text = args.dataPoints[args.pointIndex].x.toString() + + args.text = args.dataPoints![args.pointIndex!.toInt()].x.toString() + ' : ' + - args.dataPoints[args.pointIndex].y.toString() + + args.dataPoints![args.pointIndex!.toInt()].y.toString() + ' m'; }, primaryXAxis: CategoryAxis( @@ -162,8 +168,7 @@ class _ChartMaximumLabelWidthState extends SampleViewState { interval: 100, majorTickLines: MajorTickLines(size: 0)), series: _getDefaultSortingSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/multiple_axis_chart.dart b/lib/samples/chart/cartesian_charts/axis_features/multiple_axis_chart.dart index 9af8f694..78770772 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/multiple_axis_chart.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/multiple_axis_chart.dart @@ -22,11 +22,11 @@ class _MultipleAxisState extends SampleViewState { @override Widget build(BuildContext context) { - return _getMultipleAxisLineChart(); + return _buildMultipleAxisLineChart(); } /// Returns the chart with multiple axes. - SfCartesianChart _getMultipleAxisLineChart() { + SfCartesianChart _buildMultipleAxisLineChart() { return SfCartesianChart( title: ChartTitle( text: isCardView ? '' : 'Washington vs New York temperature'), diff --git a/lib/samples/chart/cartesian_charts/axis_features/opposed_axes.dart b/lib/samples/chart/cartesian_charts/axis_features/opposed_axes.dart index 03c78bd5..a2bea802 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/opposed_axes.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/opposed_axes.dart @@ -20,14 +20,22 @@ class NumericOpposed extends SampleView { /// State class of the column chart with opposed numeric axes. class _NumericOpposedState extends SampleViewState { _NumericOpposedState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getOpposedNumericAxisChart(); + return _buildOpposedNumericAxisChart(); } /// Returns the column chart with opposed numeric axes. - SfCartesianChart _getOpposedNumericAxisChart() { + SfCartesianChart _buildOpposedNumericAxisChart() { return SfCartesianChart( title: ChartTitle( text: isCardView ? '' : 'Light vehicle retail sales in US'), @@ -47,8 +55,7 @@ class _NumericOpposedState extends SampleViewState { maximum: 20000, majorTickLines: MajorTickLines(size: 0)), series: _getOpposedNumericAxisSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart b/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart index 4b8c8e00..8f790576 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart @@ -25,8 +25,9 @@ class _PlotBandDefaultState extends SampleViewState { bool isVertical = false; bool isSegment = false; bool isLine = false; + late TooltipBehavior _tooltipBehavior; - String _selectedType; + late String _selectedType; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -62,11 +63,11 @@ class _PlotBandDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getPlotBandChart(); + return _buildPlotBandChart(); } /// Return the types of plotbands. - SfCartesianChart _getPlotBandChart() { + SfCartesianChart _buildPlotBandChart() { final Color plotbandYAxisTextColor = ((isSegment || isLine) && model != null && model.themeData.brightness == Brightness.light) @@ -258,8 +259,7 @@ class _PlotBandDefaultState extends SampleViewState { ], ), series: _getPlotBandSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, onMarkerRender: (MarkerRenderArgs markerargs) { markerargs.color = plotbandYAxisTextColor; }, @@ -267,7 +267,6 @@ class _PlotBandDefaultState extends SampleViewState { } List> _getPlotBandSeries() { - isSegment ??= false; final List lineData = [ ChartSampleData(xValue: 'Jan', yValue: 23), ChartSampleData(xValue: 'Feb', yValue: 24), @@ -309,6 +308,8 @@ class _PlotBandDefaultState extends SampleViewState { isVertical = false; isSegment = false; isLine = false; + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); super.initState(); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/plot_band_recurrence.dart b/lib/samples/chart/cartesian_charts/axis_features/plot_band_recurrence.dart index 939c846a..0a0edf41 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/plot_band_recurrence.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/plot_band_recurrence.dart @@ -20,18 +20,21 @@ class PlotBandRecurrence extends SampleView { /// State class of the column chart with plotband recurrrence. class _PlotBandRecurrenceState extends SampleViewState { _PlotBandRecurrenceState(); - bool xAxis = false, yAxis = true; + bool? xAxis = false, yAxis = true; + late TooltipBehavior _tooltipBehavior; @override void initState() { xAxis = false; yAxis = true; + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); super.initState(); } @override Widget build(BuildContext context) { - return _getPlotBandRecurrenceChart(); + return _buildPlotBandRecurrenceChart(); } @override @@ -54,9 +57,9 @@ class _PlotBandRecurrenceState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: xAxis, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - xAxis = value; + xAxis = value!; stateSetter(() {}); }); })) @@ -76,9 +79,9 @@ class _PlotBandRecurrenceState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: yAxis, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - yAxis = value; + yAxis = value!; stateSetter(() {}); }); })) @@ -91,7 +94,7 @@ class _PlotBandRecurrenceState extends SampleViewState { } /// Returns the ccolumn chart with plot band recurrence. - SfCartesianChart _getPlotBandRecurrenceChart() { + SfCartesianChart _buildPlotBandRecurrenceChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'World pollution report'), legend: Legend(isVisible: !isCardView), @@ -112,7 +115,7 @@ class _PlotBandRecurrenceState extends SampleViewState { isVisible: xAxis ?? false, repeatEvery: 10, sizeType: DateTimeIntervalType.years, - size: model.isWeb ? 3 : 5, + size: model.isWebFullView ? 3 : 5, repeatUntil: DateTime(2010, 1, 1), start: DateTime(1965, 1, 1), end: DateTime(2010, 1, 1), @@ -144,10 +147,9 @@ class _PlotBandRecurrenceState extends SampleViewState { majorGridLines: MajorGridLines(color: Colors.grey), majorTickLines: MajorTickLines(size: 0), axisLine: AxisLine(width: 0), - labelStyle: const TextStyle(fontSize: 0)), + labelStyle: const TextStyle(fontSize: 0, color: Colors.transparent)), series: _getPlotBandRecurrenceSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart b/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart index 2b099e80..253c5e78 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart @@ -22,9 +22,9 @@ class _AxisCrossingState extends SampleViewState { String _xSelectedPositionType = 'outside'; String _ySelectedAlignmentType = 'end'; String _xSelectedAlignmentType = 'center'; - ChartDataLabelPosition _labelPositionX, _labelPositionY; - TickPosition _tickPositionX, _tickPositionY; - LabelAlignment _labelAlignmentX, _labelAlignmentY; + late ChartDataLabelPosition _labelPositionX, _labelPositionY; + late TickPosition _tickPositionX, _tickPositionY; + late LabelAlignment _labelAlignmentX, _labelAlignmentY; /// List the axis position types. final List _yPositionType = ['outside', 'inside'].toList(); @@ -187,11 +187,11 @@ class _AxisCrossingState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLabelCustomizationSample(); + return _buildLabelCustomizationSample(); } /// Returen the Spline series with axis label position changing. - SfCartesianChart _getLabelCustomizationSample() { + SfCartesianChart _buildLabelCustomizationSample() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'New York temperature details'), primaryXAxis: CategoryAxis( diff --git a/lib/samples/chart/cartesian_charts/axis_types/category/default_category_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/category/default_category_axis.dart index 4a0a3121..19ad7a90 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/category/default_category_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/category/default_category_axis.dart @@ -19,14 +19,21 @@ class CategoryDefault extends SampleView { /// State class of the column chart with default category x-axis. class _CategoryDefaultState extends SampleViewState { _CategoryDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultCategoryAxisChart(); + return _buildDefaultCategoryAxisChart(); } /// Returns the column chart with default category x-axis. - SfCartesianChart _getDefaultCategoryAxisChart() { + SfCartesianChart _buildDefaultCategoryAxisChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Internet Users - 2016'), plotAreaBorderWidth: 0, @@ -38,8 +45,7 @@ class _CategoryDefaultState extends SampleViewState { primaryYAxis: NumericAxis( minimum: 0, maximum: 80, isVisible: false, labelFormat: '{value}M'), series: _getDefaultCategory(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/category/indexed_category_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/category/indexed_category_axis.dart index f953e3b0..0f224a6a 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/category/indexed_category_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/category/indexed_category_axis.dart @@ -19,7 +19,7 @@ class CategoryIndexed extends SampleView { /// State class of arrange by index chart. class _CategoryIndexedState extends SampleViewState { _CategoryIndexedState(); - bool isIndexed = true; + bool? isIndexed = true; @override void initState() { @@ -29,7 +29,7 @@ class _CategoryIndexedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getIndexedCategoryAxisChart(); + return _buildIndexedCategoryAxisChart(); } @override @@ -50,9 +50,9 @@ class _CategoryIndexedState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: isIndexed, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - isIndexed = value; + isIndexed = value!; stateSetter(() {}); }); })), @@ -63,7 +63,7 @@ class _CategoryIndexedState extends SampleViewState { } /// Returns the column chart with arranged index. - SfCartesianChart _getIndexedCategoryAxisChart() { + SfCartesianChart _buildIndexedCategoryAxisChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Real GDP growth'), plotAreaBorderWidth: 0, diff --git a/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart b/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart index e309a53b..d299e413 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart @@ -21,19 +21,22 @@ class _CategoryTicksState extends SampleViewState { _CategoryTicksState(); final List _labelPosition = ['betweenTicks', 'onTicks'].toList(); - String _selectedType; - LabelPlacement _labelPlacement; + late String _selectedType; + late LabelPlacement _labelPlacement; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedType = 'betweenTicks'; _labelPlacement = LabelPlacement.betweenTicks; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getTicksCategoryAxisChart(); + return _buildTicksCategoryAxisChart(); } @override @@ -76,7 +79,7 @@ class _CategoryTicksState extends SampleViewState { } /// Returns the line chart with category label placement. - SfCartesianChart _getTicksCategoryAxisChart() { + SfCartesianChart _buildTicksCategoryAxisChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Employees task count'), plotAreaBorderWidth: 0, @@ -90,8 +93,7 @@ class _CategoryTicksState extends SampleViewState { maximum: 12, interval: 1), series: _getTicksCategoryAxisSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/date_time/date_time_axis_with_label_format.dart b/lib/samples/chart/cartesian_charts/axis_types/date_time/date_time_axis_with_label_format.dart index ebe30f2b..9d878cad 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/date_time/date_time_axis_with_label_format.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/date_time/date_time_axis_with_label_format.dart @@ -20,14 +20,24 @@ class DateTimeLabel extends SampleView { /// State class of the scatter chart with datetime axis label format class _DateTimeLabelState extends SampleViewState { _DateTimeLabelState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + format: 'point.x : point.y Mw', + header: '', + canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getLabelDateTimeAxisChart(); + return _buildLabelDateTimeAxisChart(); } /// Returns the scatter chart with datatime axis label format. - SfCartesianChart _getLabelDateTimeAxisChart() { + SfCartesianChart _buildLabelDateTimeAxisChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Earthquakes in Indonesia'), @@ -47,11 +57,7 @@ class _DateTimeLabelState extends SampleViewState { title: AxisTitle(text: isCardView ? '' : 'Magnitude (Mw)'), ), series: _getLabelDateTimeAxisSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - format: 'point.x : point.y Mw', - header: '', - canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/date_time/default_date_time_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/date_time/default_date_time_axis.dart index c028ed73..e63a89df 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/date_time/default_date_time_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/date_time/default_date_time_axis.dart @@ -19,14 +19,24 @@ class DateTimeDefault extends SampleView { /// State class of the line chart with default data time axis. class _DateTimeDefaultState extends SampleViewState { _DateTimeDefaultState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + _trackballBehavior = TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + tooltipSettings: + InteractiveTooltip(format: 'point.x : point.y', borderWidth: 0)); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultDateTimeAxisChart(); + return _buildDefaultDateTimeAxisChart(); } /// Returns the line chart with default datetime axis. - SfCartesianChart _getDefaultDateTimeAxisChart() { + SfCartesianChart _buildDefaultDateTimeAxisChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -44,11 +54,7 @@ class _DateTimeDefaultState extends SampleViewState { majorTickLines: MajorTickLines(size: 0), ), series: _getDefaultDateTimeSeries(), - trackballBehavior: TrackballBehavior( - enable: true, - activationMode: ActivationMode.singleTap, - tooltipSettings: InteractiveTooltip( - format: 'point.x : point.y', borderWidth: 0))); + trackballBehavior: _trackballBehavior); } /// Returns the line chart with default data time axis. diff --git a/lib/samples/chart/cartesian_charts/axis_types/date_time_category/date_time_category_with_label_format.dart b/lib/samples/chart/cartesian_charts/axis_types/date_time_category/date_time_category_with_label_format.dart new file mode 100644 index 00000000..49f59636 --- /dev/null +++ b/lib/samples/chart/cartesian_charts/axis_types/date_time_category/date_time_category_with_label_format.dart @@ -0,0 +1,85 @@ +/// Package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Renders the line chart with default data time axis sample. +class DateTimeCategoryLabel extends SampleView { + /// Creates the line chart with default data time axis sample. + const DateTimeCategoryLabel(Key key) : super(key: key); + + @override + _DateTimeCategoryLabelState createState() => _DateTimeCategoryLabelState(); +} + +/// State class of the line chart with default data time axis. +class _DateTimeCategoryLabelState extends SampleViewState { + _DateTimeCategoryLabelState(); + + late TooltipBehavior _tooltipBehavior; + + late List<_OrdinalSales> data; + + @override + void initState() { + data = <_OrdinalSales>[ + _OrdinalSales(DateTime(2020, 12, 02, 21, 00), 30), + _OrdinalSales(DateTime(2020, 12, 05, 12, 16), 13), + _OrdinalSales(DateTime(2020, 12, 12, 21, 00), 24), + _OrdinalSales(DateTime(2020, 12, 19, 04, 43), 35), + _OrdinalSales(DateTime(2020, 12, 24, 18, 35), 41), + ]; + _tooltipBehavior = TooltipBehavior(enable: true, header: ''); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SfCartesianChart( + plotAreaBorderWidth: 0, + primaryXAxis: DateTimeCategoryAxis( + majorGridLines: MajorGridLines(width: 0), + dateFormat: DateFormat('''MM/dd/yy\nh:mm a'''), + title: AxisTitle( + text: isCardView ? '' : 'Start time', + ), + ), + title: ChartTitle( + text: isCardView ? '' : 'Server down details in a month'), + primaryYAxis: NumericAxis( + majorTickLines: MajorTickLines(size: 0), + interval: 10, + minimum: 0, + maximum: 50, + axisLine: AxisLine(width: 0), + labelFormat: '{value}m', + title: AxisTitle( + text: isCardView ? '' : 'Duration in minutes', + ), + ), + tooltipBehavior: _tooltipBehavior, + series: >[ + ColumnSeries<_OrdinalSales, DateTime>( + dataSource: data, + name: 'Server down time', + xValueMapper: (_OrdinalSales x, int xx) => x.year, + yValueMapper: (_OrdinalSales sales, _) => sales.sales, + dataLabelSettings: DataLabelSettings( + isVisible: true, + offset: Offset(0, -5), + )), + ]); + } +} + +/// Sample ordinal data type. +class _OrdinalSales { + _OrdinalSales(this.year, this.sales); + final DateTime year; + final double sales; +} diff --git a/lib/samples/chart/cartesian_charts/axis_types/date_time_category/default_date_time_category.dart b/lib/samples/chart/cartesian_charts/axis_types/date_time_category/default_date_time_category.dart new file mode 100644 index 00000000..39fd9d09 --- /dev/null +++ b/lib/samples/chart/cartesian_charts/axis_types/date_time_category/default_date_time_category.dart @@ -0,0 +1,110 @@ +/// Package import +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Renders the line chart with default data time axis sample. +class DateTimeCategoryDefault extends SampleView { + /// Creates the line chart with default data time axis sample. + const DateTimeCategoryDefault(Key key) : super(key: key); + + @override + _DateTimeCategoryDefaultState createState() => + _DateTimeCategoryDefaultState(); +} + +/// State class of the line chart with default data time axis. +class _DateTimeCategoryDefaultState extends SampleViewState { + _DateTimeCategoryDefaultState(); + + late List<_OrdinalSales> data; + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior(enable: true); + data = <_OrdinalSales>[ + _OrdinalSales(DateTime(2017, 12, 22), 24), + _OrdinalSales(DateTime(2017, 12, 26), 70), + _OrdinalSales(DateTime(2017, 12, 27), 75), + _OrdinalSales(DateTime(2018, 1, 2), 82), + _OrdinalSales(DateTime(2018, 1, 3), 53), + _OrdinalSales(DateTime(2018, 1, 4), 54), + ]; + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return _buildDefaultDateTimeAxisChart(context); + } + + /// Returns the line chart with default datetime axis. + SfCartesianChart _buildDefaultDateTimeAxisChart(BuildContext context) { + final Color labelColor = model.themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black; + return SfCartesianChart( + plotAreaBorderWidth: 0, + primaryXAxis: DateTimeCategoryAxis( + majorGridLines: MajorGridLines(width: 0), + labelIntersectAction: isCardView + ? AxisLabelIntersectAction.multipleRows + : AxisLabelIntersectAction.rotate45, + title: AxisTitle( + text: isCardView ? '' : 'Business days', + ), + plotBands: [ + PlotBand( + isVisible: true, + start: DateTime(2017, 12, 22), + end: DateTime(2017, 12, 27), + textAngle: 0, + verticalTextAlignment: TextAnchor.start, + verticalTextPadding: '%-5', + text: 'Christmas Offer \nDec 2017', + textStyle: TextStyle(color: labelColor, fontSize: 13), + color: const Color.fromRGBO(50, 198, 255, 1), + opacity: 0.3), + PlotBand( + isVisible: true, + textAngle: 0, + start: DateTime(2018, 1, 2), + end: DateTime(2018, 1, 4), + verticalTextAlignment: TextAnchor.start, + verticalTextPadding: '%-5', + text: 'New Year Offer \nJan 2018', + textStyle: TextStyle(color: labelColor, fontSize: 13), + color: Colors.pink, + opacity: 0.2), + ]), + tooltipBehavior: _tooltipBehavior, + title: + ChartTitle(text: isCardView ? '' : 'Sales comparison of a product'), + primaryYAxis: NumericAxis( + labelFormat: '{value}M', + interval: 20, + majorTickLines: MajorTickLines(size: 0), + axisLine: AxisLine(width: 0)), + series: >[ + ColumnSeries<_OrdinalSales, DateTime>( + dataSource: data, + name: 'Sales', + xValueMapper: (_OrdinalSales x, int xx) => x.year, + yValueMapper: (_OrdinalSales sales, _) => sales.sales, + ), + ]); + } +} + +/// Sample ordinal data type. +class _OrdinalSales { + _OrdinalSales(this.year, this.sales); + + final DateTime year; + final double sales; +} diff --git a/lib/samples/chart/cartesian_charts/axis_types/logarithmic/default_logarithmic_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/logarithmic/default_logarithmic_axis.dart index 80f650a6..f3e62049 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/logarithmic/default_logarithmic_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/logarithmic/default_logarithmic_axis.dart @@ -19,14 +19,21 @@ class LogarithmicAxisDefault extends SampleView { /// State class of the line cahrt with default logarithmic axis sample. class _LogarithmicAxisDefaultState extends SampleViewState { _LogarithmicAxisDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultLogarithmicAxisChart(); + return _buildDefaultLogarithmicAxisChart(); } /// Returns the line chart with default logarithmic axis. - SfCartesianChart _getDefaultLogarithmicAxisChart() { + SfCartesianChart _buildDefaultLogarithmicAxisChart() { return SfCartesianChart( plotAreaBorderWidth: 1, title: @@ -41,8 +48,7 @@ class _LogarithmicAxisDefaultState extends SampleViewState { labelFormat: '\${value}', interval: 1), series: _getSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/logarithmic/inversed_logarithmic_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/logarithmic/inversed_logarithmic_axis.dart index cb5e0915..f035fdcf 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/logarithmic/inversed_logarithmic_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/logarithmic/inversed_logarithmic_axis.dart @@ -21,26 +21,37 @@ class LogarithmicAxisInversed extends SampleView { /// State class of the stepline cahrt with inversed logarithmic axis sample. class _LogarithmicAxisInversedState extends SampleViewState { _LogarithmicAxisInversedState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, format: 'point.y', header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getInversedLogarithmicAxisChart(); + return _buildInversedLogarithmicAxisChart(); } /// Returns the stepline chart with inversed logarithmic axis. - SfCartesianChart _getInversedLogarithmicAxisChart() { + SfCartesianChart _buildInversedLogarithmicAxisChart() { String text; return SfCartesianChart( onTooltipRender: (TooltipArgs args) { final NumberFormat format = NumberFormat.decimalPattern(); - text = format.format(args.dataPoints[args.pointIndex].y).toString(); + text = format + .format(args.dataPoints![args.pointIndex!.toInt()].y) + .toString(); args.text = text; }, - onAxisLabelRender: (AxisLabelRenderArgs args) { + axisLabelFormatter: (AxisLabelRenderDetails details) { final NumberFormat format = NumberFormat.decimalPattern(); - if (args.axisName == 'primaryYAxis') { - args.text = format.format(double.parse(args.text)).toString(); - } + return ChartAxisLabel( + details.axisName == 'primaryYAxis' + ? format.format(double.parse(details.text)).toString() + : details.text, + null); }, plotAreaBorderWidth: 0, title: @@ -59,8 +70,7 @@ class _LogarithmicAxisInversedState extends SampleViewState { interval: 1, ), series: _getInversedLogarithmicSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, format: 'point.y', header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/numeric/default_numeric_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/numeric/default_numeric_axis.dart index 2055baab..943d4962 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/numeric/default_numeric_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/numeric/default_numeric_axis.dart @@ -19,14 +19,21 @@ class NumericDefault extends SampleView { /// State class of the default numeric axis. class _NumericDefaultState extends SampleViewState { _NumericDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, format: 'Score: point.y', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return getChart(); + return _buildChart(); } /// Returns the Cartesian chart with default numeric x and y axis. - SfCartesianChart getChart() { + SfCartesianChart _buildChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Australia vs India ODI - 2019'), @@ -47,8 +54,7 @@ class _NumericDefaultState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: getDefaultNumericSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, format: 'Score: point.y', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/numeric/inversed_numeric_axis.dart b/lib/samples/chart/cartesian_charts/axis_types/numeric/inversed_numeric_axis.dart index 8a64a2d4..b6d4445b 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/numeric/inversed_numeric_axis.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/numeric/inversed_numeric_axis.dart @@ -21,8 +21,15 @@ class NumericInverse extends SampleView { /// State class of the inversed numeric axis. class _NumericInverseState extends SampleViewState { _NumericInverseState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } - bool isYInversed = true, isXInversed = true; + bool? isYInversed = true, isXInversed = true; @override Widget buildSettings(BuildContext context) { @@ -38,7 +45,7 @@ class _NumericInverseState extends SampleViewState { scale: 0.8, child: CupertinoSwitch( activeColor: model.backgroundColor, - value: isXInversed, + value: isXInversed!, onChanged: (bool value) { setState(() { isXInversed = value; @@ -58,7 +65,7 @@ class _NumericInverseState extends SampleViewState { scale: 0.8, child: CupertinoSwitch( activeColor: model.backgroundColor, - value: isYInversed, + value: isYInversed!, onChanged: (bool value) { setState(() { isYInversed = value; @@ -75,13 +82,13 @@ class _NumericInverseState extends SampleViewState { @override Widget build(BuildContext context) { - return getChart(); + return _buildChart(); } /// Returns the Cartesian chart with inversed x and y axis. /// Can change the isInversed bool value by toggle the custom button /// presented in property panel. - SfCartesianChart getChart() { + SfCartesianChart _buildChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Airports count in US'), @@ -100,8 +107,7 @@ class _NumericInverseState extends SampleViewState { isInversed: isYInversed ?? true, majorTickLines: MajorTickLines(size: 0)), series: getInversedNumericSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/axis_types/numeric/numeric_axis_with_label_format.dart b/lib/samples/chart/cartesian_charts/axis_types/numeric/numeric_axis_with_label_format.dart index d1f5674f..912f1fd4 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/numeric/numeric_axis_with_label_format.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/numeric/numeric_axis_with_label_format.dart @@ -19,13 +19,23 @@ class NumericLabel extends SampleView { /// State class of numeric axis label format. class _NumericLabelState extends SampleViewState { _NumericLabelState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + header: '', + canShowMarker: false, + format: 'point.x / point.y'); + super.initState(); + } @override Widget build(BuildContext context) { - return getChart(); + return _buildChart(); } - Widget getChart() { + Widget _buildChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: @@ -39,11 +49,7 @@ class _NumericLabelState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: getNumericLabelSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - header: '', - canShowMarker: false, - format: 'point.x / point.y'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart index 09b6478e..1b6a1f15 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart @@ -23,8 +23,8 @@ class AnimationAreaDefault extends SampleView { /// State class of animation area chart. class _AnimationAreaDefaultState extends SampleViewState { _AnimationAreaDefaultState(); - List<_ChartData> _chartData; - Timer _timer; + late List<_ChartData> _chartData; + Timer? _timer; @override Widget build(BuildContext context) { @@ -34,11 +34,11 @@ class _AnimationAreaDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationAreaChart(); + return _buildAnimationAreaChart(); } /// Return the cartesian chart with animation. - SfCartesianChart _getAnimationAreaChart() { + SfCartesianChart _buildAnimationAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: @@ -67,11 +67,11 @@ class _AnimationAreaDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer!.cancel(); } /// Return the random value in area series. - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart index 808d7dca..c940d27b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart @@ -21,21 +21,24 @@ class _AxisCrossingBaseValueState extends SampleViewState { _AxisCrossingBaseValueState(); final List _axis = ['-2 (modified)', '0 (default)'].toList(); //ignore: unused_field - String _selectedAxisType = '-2 (modified)'; - String _selectedAxis; + late String _selectedAxisType = '-2 (modified)'; + late String _selectedAxis; double _crossAt = 0; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedAxisType = '-2 (modified)'; _selectedAxis = '-2 (modified)'; _crossAt = -2; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getAxisCrossingBaseValueSample(); + return _buildAxisCrossingBaseValueSample(); } @override @@ -70,7 +73,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { } /// Returns the spline chart with axis crossing at provided axis value. - SfCartesianChart _getAxisCrossingBaseValueSample() { + SfCartesianChart _buildAxisCrossingBaseValueSample() { return SfCartesianChart( margin: EdgeInsets.fromLTRB(10, 10, 15, 10), plotAreaBorderWidth: 0, @@ -79,8 +82,9 @@ class _AxisCrossingBaseValueState extends SampleViewState { primaryXAxis: CategoryAxis( labelPlacement: LabelPlacement.onTicks, majorGridLines: MajorGridLines(width: 0), - edgeLabelPlacement: - model.isWeb ? EdgeLabelPlacement.shift : EdgeLabelPlacement.none, + edgeLabelPlacement: model.isWebFullView + ? EdgeLabelPlacement.shift + : EdgeLabelPlacement.none, labelIntersectAction: !isCardView ? AxisLabelIntersectAction.rotate45 : AxisLabelIntersectAction.wrap, @@ -92,8 +96,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { maximum: 3, majorTickLines: MajorTickLines(size: 0)), series: _getSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } @@ -101,7 +104,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { /// the bar or column chart with axis crossing. List> _getSeries() { - List> chart = null; + List> chart; final List chartData = [ ChartSampleData(x: 'Iceland', y: 1.13), ChartSampleData(x: 'Algeria', y: 1.7), diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_emptypoints.dart b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_emptypoints.dart index b149579c..5bae8c77 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_emptypoints.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_emptypoints.dart @@ -20,14 +20,21 @@ class AreaEmpty extends SampleView { /// State class for the area with empty point chart. class _AreaEmptyState extends SampleViewState { _AreaEmptyState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getEmptyPointAreaChart(); + return _buildEmptyPointAreaChart(); } /// Returns the the Cartesian area chart with emptypoints. - SfCartesianChart _getEmptyPointAreaChart() { + SfCartesianChart _buildEmptyPointAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Inflation rate of US'), @@ -43,8 +50,7 @@ class _AreaEmptyState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getEmptyPointAreaSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_gradient.dart b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_gradient.dart index aa93a237..1a8539aa 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_gradient.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_gradient.dart @@ -20,14 +20,21 @@ class AreaGradient extends SampleView { /// State class of gradient area chart. class _AreaGradientState extends SampleViewState { _AreaGradientState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getGradientAreaChart(); + return _buildGradientAreaChart(); } /// Returns the cartesian area chart with gradient. - SfCartesianChart _getGradientAreaChart() { + SfCartesianChart _buildGradientAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Annual rainfall of Paris'), @@ -44,8 +51,7 @@ class _AreaGradientState extends SampleViewState { labelFormat: '{value}mm', majorTickLines: MajorTickLines(size: 0)), series: _getGradientAreaSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/default_area_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/area/default_area_chart.dart index cc77f637..265cd56d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/default_area_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/default_area_chart.dart @@ -23,11 +23,11 @@ class _AreaDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultAreaChart(); + return _buildDefaultAreaChart(); } /// Returns the default cartesian area chart. - SfCartesianChart _getDefaultAreaChart() { + SfCartesianChart _buildDefaultAreaChart() { return SfCartesianChart( legend: Legend(isVisible: !isCardView, opacity: 0.7), title: ChartTitle(text: isCardView ? '' : 'Average sales comparison'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/vertical_area_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/area/vertical_area_chart.dart index e9514216..a082c201 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/vertical_area_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/vertical_area_chart.dart @@ -22,11 +22,11 @@ class _AreaVerticalState extends SampleViewState { @override Widget build(BuildContext context) { - return _getVerticalAreaChart(); + return _buildVerticalAreaChart(); } /// Returns the cartesian area chart in transposed form. - SfCartesianChart _getVerticalAreaChart() { + SfCartesianChart _buildVerticalAreaChart() { return SfCartesianChart( legend: Legend( isVisible: isCardView ? false : true, diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart index ea494364..7a064ee6 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart @@ -22,8 +22,8 @@ class AnimationBarDefault extends SampleView { class _AnimationBarDefaultState extends SampleViewState { _AnimationBarDefaultState(); - List<_ChartData> _chartData; - Timer _timer; + late List<_ChartData> _chartData; + Timer? _timer; @override Widget build(BuildContext context) { _getChartData(); @@ -33,10 +33,10 @@ class _AnimationBarDefaultState extends SampleViewState { }); }); - return _getAnimationBarChart(); + return _buildAnimationBarChart(); } - SfCartesianChart _getAnimationBarChart() { + SfCartesianChart _buildAnimationBarChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), @@ -58,10 +58,10 @@ class _AnimationBarDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer!.cancel(); } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart index 4a5c955a..30ceeca5 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart @@ -31,7 +31,7 @@ class _BarSpacingState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSpacingBarChart(); + return _buildSpacingBarChart(); } @override @@ -94,7 +94,7 @@ class _BarSpacingState extends SampleViewState { ); } - SfCartesianChart _getSpacingBarChart() { + SfCartesianChart _buildSpacingBarChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Exports & Imports of US'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_rounded_corners.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_rounded_corners.dart index c3db0778..529073f1 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_rounded_corners.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_rounded_corners.dart @@ -19,14 +19,21 @@ class BarRounded extends SampleView { /// State class of the rounded bar chart. class _BarRoundedState extends SampleViewState { _BarRoundedState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getRoundedBarChart(); + return _buildRoundedBarChart(); } /// Returns the rounded cartesian bar chart. - SfCartesianChart _getRoundedBarChart() { + SfCartesianChart _buildRoundedBarChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -35,8 +42,7 @@ class _BarRoundedState extends SampleViewState { primaryYAxis: NumericAxis( minimum: -2, maximum: 2, majorTickLines: MajorTickLines(size: 0)), series: _getRoundedBarSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_track.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_track.dart index bb517c37..e20e7b13 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_track.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_with_track.dart @@ -19,14 +19,21 @@ class BarTracker extends SampleView { /// State class of tracker bar chart. class _BarTrackerState extends SampleViewState { _BarTrackerState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getTrackerBarChart(); + return _buildTrackerBarChart(); } /// Returns the bar chart with trackers. - SfCartesianChart _getTrackerBarChart() { + SfCartesianChart _buildTrackerBarChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Working hours of employees'), @@ -40,8 +47,7 @@ class _BarTrackerState extends SampleViewState { maximum: 8, majorTickLines: MajorTickLines(size: 0)), series: _getTrackerBarSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/customized_bar_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/customized_bar_chart.dart index ef3f9e1c..62cc30d3 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/customized_bar_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/customized_bar_chart.dart @@ -23,7 +23,7 @@ class BarCustomization extends SampleView { } /// dashed array image renders inside of bars -ui.Image image; +ui.Image? image; /// Set image loaded info bool isImageloaded = false; @@ -31,6 +31,7 @@ bool isImageloaded = false; /// State class of the customized bar chart. class _BarCustomizationState extends SampleViewState { _BarCustomizationState(); + late TooltipBehavior _tooltipBehavior; Future _init() async { final ByteData data = await rootBundle.load('images/dashline.png'); @@ -39,10 +40,8 @@ class _BarCustomizationState extends SampleViewState { Future _loadImage(List img) async { final Completer completer = Completer(); - ui.decodeImageFromList(img, (ui.Image img) { - setState(() { - isImageloaded = true; - }); + ui.decodeImageFromList(img as Uint8List, (ui.Image img) { + isImageloaded = true; return completer.complete(img); }); return completer.future; @@ -50,17 +49,19 @@ class _BarCustomizationState extends SampleViewState { @override void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); super.initState(); _init(); } @override Widget build(BuildContext context) { - return _getCustomizedBarChart(); + return _buildCustomizedBarChart(); } /// Returns the customized cartesian bar chart. - SfCartesianChart _getCustomizedBarChart() { + SfCartesianChart _buildCustomizedBarChart() { return SfCartesianChart( title: ChartTitle( text: isCardView @@ -95,8 +96,7 @@ class _BarCustomizationState extends SampleViewState { yValueMapper: (ChartSampleData sales, _) => sales.y, ) ], - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, ); } } @@ -107,7 +107,7 @@ class _CustomBarSeriesRenderer extends BarSeriesRenderer { _CustomBarSeriesRenderer(); @override - ChartSegment createSegment() { + BarSegment createSegment() { return BarCustomPainter(); } } @@ -129,7 +129,7 @@ class BarCustomPainter extends BarSegment { ..shader = image == null ? null : ImageShader( - image, TileMode.repeated, TileMode.repeated, deviceTransform); + image!, TileMode.repeated, TileMode.repeated, deviceTransform); final double devicePixelRatio = ui.window.devicePixelRatio; diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/default_bar_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/default_bar_chart.dart index 8e35a864..e30cbe0c 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/default_bar_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/default_bar_chart.dart @@ -23,11 +23,11 @@ class _BarDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultBarChart(); + return _buildDefaultBarChart(); } /// Returns the default cartesian bar chart. - SfCartesianChart _getDefaultBarChart() { + SfCartesianChart _buildDefaultBarChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Tourism - Number of arrivals'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/box_whisker.dart b/lib/samples/chart/cartesian_charts/chart_types/box_whisker.dart index 58db6a79..9b094d22 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/box_whisker.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/box_whisker.dart @@ -7,8 +7,9 @@ import 'package:syncfusion_flutter_charts/charts.dart'; /// Local imports import '../../../../model/sample_view.dart'; -///Renders histogram chart sample +///Renders box whisker chart sample class BoxWhisker extends SampleView { + /// Creates the box whisker chart const BoxWhisker(Key key) : super(key: key); @override @@ -17,11 +18,12 @@ class BoxWhisker extends SampleView { class _BoxWhiskerState extends SampleViewState { _BoxWhiskerState(); - var _selectMode; - BoxPlotMode _boxMode; - bool _mean = true; + late var _selectMode; + late BoxPlotMode _boxMode; + late bool _mean; final List _modeType = ['normal', 'exclusive', 'inclusive'].toList(); + late TooltipBehavior _tooltipBehavior; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -69,9 +71,9 @@ class _BoxWhiskerState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _mean, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _mean = value; + _mean = value!; stateSetter(() {}); }); })), @@ -87,12 +89,13 @@ class _BoxWhiskerState extends SampleViewState { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 50), - child: _getDefaultWhiskerChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 50), + child: _buildDefaultWhiskerChart()); } /// Get the cartesian chart with histogram series - SfCartesianChart _getDefaultWhiskerChart() { + SfCartesianChart _buildDefaultWhiskerChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: 'Employees age group in various departments'), @@ -107,7 +110,7 @@ class _BoxWhiskerState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getBoxWhiskerSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } @@ -140,8 +143,6 @@ class _BoxWhiskerState extends SampleViewState { ], null, Color.fromRGBO(75, 135, 185, 0.9)), - // SalesData('Testing', [22, 33, 23, 25, 26, 28, 29, 30, 34, 33, 32, 31, 50],null, - // Color.fromRGBO(75, 135, 185, 0.9) ), SalesData('HR', [22, 24, 25, 30, 32, 34, 36, 38, 39, 41, 35, 36, 40, 56], null, Color.fromRGBO(75, 135, 185, 0.9)), SalesData('Finance ', [26, 27, 28, 30, 32, 34, 35, 37, 35, 37, 45], null, @@ -154,8 +155,6 @@ class _BoxWhiskerState extends SampleViewState { null, Color.fromRGBO(75, 135, 185, 0.9)), SalesData('Graphics', [26, 28, 29, 30, 32, 33, 35, 36, 52], null, Color.fromRGBO(75, 135, 185, 0.9)), - // SalesData( 'Training', [28, 29, 30, 31, 32, 34, 35, 36],null, - // Color.fromRGBO(123, 180, 235, 1)) ]; return >[ BoxAndWhiskerSeries( @@ -175,9 +174,10 @@ class _BoxWhiskerState extends SampleViewState { @override void initState() { - _selectMode = "normal"; + _selectMode = 'normal'; _mean = true; _boxMode = BoxPlotMode.normal; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart index c1bc9116..6861019a 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart @@ -22,7 +22,7 @@ class AnimationBubbleDefault extends SampleView { class _AnimationBubbleDefaultState extends SampleViewState { _AnimationBubbleDefaultState(); - Timer timer; + Timer? timer; @override Widget build(BuildContext context) { @@ -32,10 +32,10 @@ class _AnimationBubbleDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationBubbleChart(); + return _buildAnimationBubbleChart(); } - SfCartesianChart _getAnimationBubbleChart() { + SfCartesianChart _buildAnimationBubbleChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), @@ -60,11 +60,11 @@ class _AnimationBubbleDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - timer.cancel(); + timer!.cancel(); } /// To get the random data and return to the chart data source. - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_filled_with_gradient.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_filled_with_gradient.dart index 9c838868..25da6b7f 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_filled_with_gradient.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_filled_with_gradient.dart @@ -19,14 +19,21 @@ class BubbleGradient extends SampleView { /// State class of bubble with gradient chart class _BubbleGradientState extends SampleViewState { _BubbleGradientState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getGradientBubbleChart(); + return _buildGradientBubbleChart(); } /// Returns the cartesian bubble cahrt with gradient - SfCartesianChart _getGradientBubbleChart() { + SfCartesianChart _buildGradientBubbleChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -43,8 +50,7 @@ class _BubbleGradientState extends SampleViewState { maximum: 4, interval: 1), series: _getGradientBubbleSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } @@ -83,8 +89,8 @@ class _BubbleGradientState extends SampleViewState { pointColor: const Color.fromRGBO(200, 0, 102, 1)) ]; final List color = []; - color.add(Colors.blue[50]); - color.add(Colors.blue[200]); + color.add(Colors.blue[50]!); + color.add(Colors.blue[200]!); color.add(Colors.blue); final List stops = []; diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_multiple_series.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_multiple_series.dart index f52a9087..5f08f7fa 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_multiple_series.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_multiple_series.dart @@ -19,14 +19,26 @@ class BubbleMultiSeries extends SampleView { /// State class of the multiple bubble series chart class _BubbleMultiSeriesState extends SampleViewState { _BubbleMultiSeriesState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + textAlignment: ChartAlignment.center, + enable: true, + header: '', + canShowMarker: false, + format: + 'Literacy rate : point.x%\nGDP growth rate : point.y\nPopulation : point.sizeB'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getMultipleSeriesBubbleChart(); + return _buildMultipleSeriesBubbleChart(); } /// Returns the multiple bubble series chart - SfCartesianChart _getMultipleSeriesBubbleChart() { + SfCartesianChart _buildMultipleSeriesBubbleChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'World countries details'), @@ -43,13 +55,7 @@ class _BubbleMultiSeriesState extends SampleViewState { legend: Legend( isVisible: isCardView ? false : true, overflowMode: LegendItemOverflowMode.wrap), - tooltipBehavior: TooltipBehavior( - textAlignment: ChartAlignment.center, - enable: true, - header: '', - canShowMarker: false, - format: - 'Literacy rate : point.x%\nGDP growth rate : point.y\nPopulation : point.sizeB'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_various_colors.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_various_colors.dart index 100e2446..a79b0db2 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_various_colors.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/bubble_with_various_colors.dart @@ -20,14 +20,25 @@ class BubblePointColor extends SampleView { /// State class of the bubble chart with point color class _BubblePointColorState extends SampleViewState { _BubblePointColorState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + textAlignment: ChartAlignment.center, + enable: true, + canShowMarker: false, + header: '', + format: 'Country : point.x\nArea : point.y km²'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getPointColorBubbleChart(); + return _buildPointColorBubbleChart(); } /// Returns the bubble chart with point color - SfCartesianChart _getPointColorBubbleChart() { + SfCartesianChart _buildPointColorBubbleChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Countries by area'), plotAreaBorderWidth: 0, @@ -43,12 +54,7 @@ class _BubblePointColorState extends SampleViewState { rangePadding: ChartRangePadding.additional, majorTickLines: MajorTickLines(size: 0)), series: _getPointColorBubbleSeries(), - tooltipBehavior: TooltipBehavior( - textAlignment: ChartAlignment.center, - enable: true, - canShowMarker: false, - header: '', - format: 'Country : point.x\nArea : point.y km²'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/default_bubble_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/default_bubble_chart.dart index c4308d0b..8d0ba0da 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/default_bubble_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/default_bubble_chart.dart @@ -19,14 +19,26 @@ class BubbleDefault extends SampleView { /// State class of the default bubble chart class _BubbleDefaultState extends SampleViewState { _BubbleDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + textAlignment: ChartAlignment.center, + header: '', + canShowMarker: false, + format: + 'point.x\nLiteracy rate : point.x%\nGDP growth rate : point.y\nPopulation : point.sizeB'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultBubbleChart(); + return _buildDefaultBubbleChart(); } /// Rreturns the default bubble chart - SfCartesianChart _getDefaultBubbleChart() { + SfCartesianChart _buildDefaultBubbleChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'World countries details'), @@ -39,13 +51,7 @@ class _BubbleDefaultState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0), title: AxisTitle(text: isCardView ? '' : 'GDP growth rate')), - tooltipBehavior: TooltipBehavior( - enable: true, - textAlignment: ChartAlignment.center, - header: '', - canShowMarker: false, - format: - 'point.x\nLiteracy rate : point.x%\nGDP growth rate : point.y\nPopulation : point.sizeB'), + tooltipBehavior: _tooltipBehavior, series: _getDefaultBubbleSeries()); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart index 2ea47b77..55450795 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart @@ -23,8 +23,8 @@ class AnimationColumnDefault extends SampleView { class _AnimationColumnDefaultState extends SampleViewState { _AnimationColumnDefaultState(); - List<_ChartData> _chartData; - Timer _timer; + late List<_ChartData> _chartData; + Timer? _timer; @override Widget build(BuildContext context) { @@ -34,11 +34,11 @@ class _AnimationColumnDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationColumnChart(); + return _buildAnimationColumnChart(); } /// Get the cartesian chart - SfCartesianChart _getAnimationColumnChart() { + SfCartesianChart _buildAnimationColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), @@ -63,11 +63,11 @@ class _AnimationColumnDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer!.cancel(); } ///Generate random value - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/back_to_back_column.dart b/lib/samples/chart/cartesian_charts/chart_types/column/back_to_back_column.dart index 1c5c3540..dff2dcd4 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/back_to_back_column.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/back_to_back_column.dart @@ -22,10 +22,10 @@ class _ColumnBackState extends SampleViewState { @override Widget build(BuildContext context) { - return _getBackColumnChart(); + return _buildBackColumnChart(); } - SfCartesianChart _getBackColumnChart() { + SfCartesianChart _buildBackColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, enableSideBySideSeriesPlacement: false, diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart index b3dc937e..da165cb3 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart @@ -21,17 +21,19 @@ class _ColumnSpacingState extends SampleViewState { _ColumnSpacingState(); double _columnWidth = 0.8; double _columnSpacing = 0.2; + late TooltipBehavior _tooltipBehavior; @override void initState() { _columnWidth = 0.8; _columnSpacing = 0.2; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } @override Widget build(BuildContext context) { - return _getSpacingColumnChart(); + return _buildSpacingColumnChart(); } @override @@ -99,7 +101,7 @@ class _ColumnSpacingState extends SampleViewState { } ///Get the cartesian chart widget - SfCartesianChart _getSpacingColumnChart() { + SfCartesianChart _buildSpacingColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Winter olympic medals count'), @@ -114,7 +116,7 @@ class _ColumnSpacingState extends SampleViewState { majorTickLines: MajorTickLines(size: 0)), series: _getDefaultColumn(), legend: Legend(isVisible: !isCardView), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart index 3cb7209e..ab59eee5 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart @@ -22,20 +22,23 @@ class _AxisCrossingBaseValueState extends SampleViewState { final List _axis = ['-2 (modified)', '0 (default)'].toList(); //ignore: unused_field String _selectedAxisType = '-2 (modified)'; - String _selectedAxis; + late String _selectedAxis; double _crossAt = 0; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedAxisType = '-2 (modified)'; _selectedAxis = '-2 (modified)'; _crossAt = -2; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getAxisCrossingBaseValueSample(); + return _buildAxisCrossingBaseValueSample(); } @override @@ -70,7 +73,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { } /// Returns the spline chart with axis crossing at provided axis value. - SfCartesianChart _getAxisCrossingBaseValueSample() { + SfCartesianChart _buildAxisCrossingBaseValueSample() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -86,8 +89,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { maximum: 2, majorTickLines: MajorTickLines(size: 0)), series: _getSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } @@ -95,7 +97,7 @@ class _AxisCrossingBaseValueState extends SampleViewState { /// the bar or column chart with axis crossing. List> _getSeries() { - List> chart = null; + List> chart; final List chartData = [ ChartSampleData( x: 'Iceland', y: 1.13, pointColor: Color.fromRGBO(107, 189, 98, 1)), diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_rounded_corners.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_rounded_corners.dart index 0e0191a4..bd951d1f 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_rounded_corners.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_rounded_corners.dart @@ -18,14 +18,24 @@ class ColumnRounded extends SampleView { class _ColumnRoundedState extends SampleViewState { _ColumnRoundedState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + canShowMarker: false, + format: 'point.x : point.y sq.km', + header: ''); + super.initState(); + } @override Widget build(BuildContext context) { - return _getRoundedColumnChart(); + return _buildRoundedColumnChart(); } /// Get rounded corner column chart - SfCartesianChart _getRoundedColumnChart() { + SfCartesianChart _buildRoundedColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -39,11 +49,7 @@ class _ColumnRoundedState extends SampleViewState { ), primaryYAxis: NumericAxis(isVisible: false, minimum: 0, maximum: 9000), series: _getRoundedColumnSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - canShowMarker: false, - format: 'point.x : point.y sq.km', - header: ''), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_track.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_track.dart index 4a08c16b..dbaf0dd2 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_track.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_track.dart @@ -18,13 +18,24 @@ class ColumnTracker extends SampleView { class _ColumnTrackerState extends SampleViewState { _ColumnTrackerState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + canShowMarker: false, + header: '', + format: 'point.y marks in point.x'); + super.initState(); + } + @override Widget build(BuildContext context) { - return _getTrackerColumnChart(); + return _buildTrackerColumnChart(); } /// Get column series with track - SfCartesianChart _getTrackerColumnChart() { + SfCartesianChart _buildTrackerColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Marks of a student'), @@ -37,11 +48,7 @@ class _ColumnTrackerState extends SampleViewState { majorGridLines: MajorGridLines(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getTracker(), - tooltipBehavior: TooltipBehavior( - enable: true, - canShowMarker: false, - header: '', - format: 'point.y marks in point.x'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/customized_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/column/customized_column_chart.dart index 1eb2148d..ce8bd7fc 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/customized_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/customized_column_chart.dart @@ -18,14 +18,21 @@ class ColumnVertical extends SampleView { class _ColumnVerticalState extends SampleViewState { _ColumnVerticalState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); + super.initState(); + } @override Widget build(BuildContext context) { - return _getCustomizedColumnChart(); + return _buildCustomizedColumnChart(); } /// Get customized column chart - SfCartesianChart _getCustomizedColumnChart() { + SfCartesianChart _buildCustomizedColumnChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'PC vendor shipments - 2015 Q1'), @@ -73,8 +80,7 @@ class _ColumnVerticalState extends SampleViewState { pointColorMapper: (ChartSampleData sales, _) => sales.pointColor, ) ], - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, ); } } @@ -97,7 +103,7 @@ class _ColumnCustomPainter extends ColumnSegment { const Color.fromRGBO(116, 180, 155, 1) ]; @override - int get currentSegmentIndex => super.currentSegmentIndex; + int get currentSegmentIndex => super.currentSegmentIndex!; @override Paint getFillPaint() { diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/default_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/column/default_column_chart.dart index fb58ece2..be89d7cd 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/default_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/default_column_chart.dart @@ -18,14 +18,21 @@ class ColumnDefault extends SampleView { class _ColumnDefaultState extends SampleViewState { _ColumnDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultColumnChart(); + return _buildDefaultColumnChart(); } /// Get default column chart - SfCartesianChart _getDefaultColumnChart() { + SfCartesianChart _buildDefaultColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -38,8 +45,7 @@ class _ColumnDefaultState extends SampleViewState { labelFormat: '{value}%', majorTickLines: MajorTickLines(size: 0)), series: _getDefaultColumnSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart index 81a4a9fe..e043501f 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart @@ -19,8 +19,9 @@ class CandleChart extends SampleView { class _CandleChartState extends SampleViewState { _CandleChartState(); - bool _enableSolidCandle; - bool _toggleVisibility; + late bool _enableSolidCandle; + late bool _toggleVisibility; + late TrackballBehavior _trackballBehavior; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -41,9 +42,9 @@ class _CandleChartState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _enableSolidCandle, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _enableSolidCandle = value; + _enableSolidCandle = value!; stateSetter(() {}); }); })) @@ -63,9 +64,9 @@ class _CandleChartState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _toggleVisibility, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _toggleVisibility = value; + _toggleVisibility = value!; stateSetter(() {}); }); })) @@ -79,11 +80,11 @@ class _CandleChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getCandle(); + return _buildCandle(); } ///Get the cartesian chart with candle series - SfCartesianChart _getCandle() { + SfCartesianChart _buildCandle() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), @@ -101,8 +102,7 @@ class _CandleChartState extends SampleViewState { labelFormat: '\${value}', axisLine: AxisLine(width: 0)), series: _getCandleSeries(), - trackballBehavior: TrackballBehavior( - enable: true, activationMode: ActivationMode.singleTap), + trackballBehavior: _trackballBehavior, ); } @@ -358,6 +358,8 @@ class _CandleChartState extends SampleViewState { void initState() { _enableSolidCandle = false; _toggleVisibility = true; + _trackballBehavior = TrackballBehavior( + enable: true, activationMode: ActivationMode.singleTap); super.initState(); } } diff --git a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_chart.dart index a59db8d1..501e691b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_chart.dart @@ -19,7 +19,8 @@ class HiloChart extends SampleView { class _HiloChartState extends SampleViewState { _HiloChartState(); - bool _toggleVisibility; + late bool _toggleVisibility; + late TooltipBehavior _tooltipBehavior; @override Widget buildSettings(BuildContext context) { @@ -39,9 +40,9 @@ class _HiloChartState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _toggleVisibility, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _toggleVisibility = value; + _toggleVisibility = value!; stateSetter(() {}); }); })), @@ -53,11 +54,11 @@ class _HiloChartState extends SampleViewState { @override Widget build(BuildContext context) { - return getHilo(); + return _buildHilo(); } ///Get the cartesian chart with hilo series - SfCartesianChart getHilo() { + SfCartesianChart _buildHilo() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), @@ -74,7 +75,7 @@ class _HiloChartState extends SampleViewState { labelFormat: '\${value}', axisLine: AxisLine(width: 0)), series: _getHiloSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } @@ -249,6 +250,7 @@ class _HiloChartState extends SampleViewState { @override void initState() { _toggleVisibility = true; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } } diff --git a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_open_close_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_open_close_chart.dart index 24fb730c..1c15af44 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_open_close_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/hilo_open_close_chart.dart @@ -19,7 +19,8 @@ class HiloOpenCloseChart extends SampleView { class _HiloOpenCloseChartState extends SampleViewState { _HiloOpenCloseChartState(); - bool _toggleVisibility; + late bool _toggleVisibility; + late TrackballBehavior _trackballBehavior; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -38,9 +39,9 @@ class _HiloOpenCloseChartState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _toggleVisibility, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _toggleVisibility = value; + _toggleVisibility = value!; stateSetter(() {}); }); }), @@ -52,11 +53,11 @@ class _HiloOpenCloseChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getHiloOpenClose(); + return _buildHiloOpenClose(); } ///Get the cartesian chart with hilo open close series - SfCartesianChart _getHiloOpenClose() { + SfCartesianChart _buildHiloOpenClose() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), @@ -74,8 +75,7 @@ class _HiloOpenCloseChartState extends SampleViewState { labelFormat: '\${value}', axisLine: AxisLine(width: 0)), series: _getHiloOpenCloseSeries(), - trackballBehavior: TrackballBehavior( - enable: true, activationMode: ActivationMode.singleTap), + trackballBehavior: _trackballBehavior, ); } @@ -408,6 +408,8 @@ class _HiloOpenCloseChartState extends SampleViewState { @override void initState() { _toggleVisibility = true; + _trackballBehavior = TrackballBehavior( + enable: true, activationMode: ActivationMode.singleTap); super.initState(); } } diff --git a/lib/samples/chart/cartesian_charts/chart_types/histogram.dart b/lib/samples/chart/cartesian_charts/chart_types/histogram.dart index 20a3658b..28725fc4 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/histogram.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/histogram.dart @@ -18,7 +18,8 @@ class HistogramDefault extends SampleView { class _HistogramDefaultState extends SampleViewState { _HistogramDefaultState(); - bool _showDistributionCurve = true; + late bool _showDistributionCurve; + late TooltipBehavior _tooltipBehavior; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -37,9 +38,9 @@ class _HistogramDefaultState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _showDistributionCurve, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _showDistributionCurve = value; + _showDistributionCurve = value!; stateSetter(() {}); }); })), @@ -52,12 +53,13 @@ class _HistogramDefaultState extends SampleViewState { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 60), - child: _getDefaultHistogramChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 60), + child: _buildDefaultHistogramChart()); } /// Get the cartesian chart with histogram series - SfCartesianChart _getDefaultHistogramChart() { + SfCartesianChart _buildDefaultHistogramChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: 'Examination Result'), @@ -73,7 +75,7 @@ class _HistogramDefaultState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getHistogramSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } @@ -210,6 +212,7 @@ class _HistogramDefaultState extends SampleViewState { @override void initState() { _showDistributionCurve = true; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } } diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart index e5fdece2..11b35941 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart @@ -22,8 +22,8 @@ class AnimationLineDefault extends SampleView { class _AnimationLineDefaultState extends SampleViewState { _AnimationLineDefaultState(); - Timer _timer; - List<_ChartData> _chartData; + Timer? _timer; + late List<_ChartData> _chartData; @override Widget build(BuildContext context) { _getChartData(); @@ -33,11 +33,11 @@ class _AnimationLineDefaultState extends SampleViewState { }); }); - return _getAnimationLineChart(); + return _buildAnimationLineChart(); } ///Get the cartesian chart with line series - SfCartesianChart _getAnimationLineChart() { + SfCartesianChart _buildAnimationLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), @@ -63,10 +63,10 @@ class _AnimationLineDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer?.cancel(); } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart index 4ba3ef46..1f57a226 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart @@ -22,21 +22,28 @@ class CustomizedLine extends SampleView { _LineDefaultState createState() => _LineDefaultState(); } -List _xValues; -List _yValues; -List _xPointValues = []; -List _yPointValues = []; +late List _xValues; +late List _yValues; +List _xPointValues = []; +List _yPointValues = []; class _LineDefaultState extends SampleViewState { _LineDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getCustomizedLineChart(); + return _buildCustomizedLineChart(); } ///Get the cartesian chart - SfCartesianChart _getCustomizedLineChart() { + SfCartesianChart _buildCustomizedLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -71,7 +78,7 @@ class _LineDefaultState extends SampleViewState { ), LineSeries<_ChartData, DateTime>( onCreateRenderer: (ChartSeries series) { - return _CustomLineSeriesRenderer(series); + return _CustomLineSeriesRenderer(series as LineSeries); }, animationDuration: 2500, dataSource: <_ChartData>[ @@ -91,8 +98,7 @@ class _LineDefaultState extends SampleViewState { width: 2, markerSettings: MarkerSettings(isVisible: true)), ], - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } } @@ -110,7 +116,7 @@ class _CustomLineSeriesRenderer extends LineSeriesRenderer { static Random randomNumber = Random(); @override - ChartSegment createSegment() { + LineSegment createSegment() { return _LineCustomPainter(randomNumber.nextInt(4), series); } } @@ -124,8 +130,8 @@ class _LineCustomPainter extends LineSegment { } final LineSeries series; - double maximum, minimum; - int index; + late double maximum, minimum; + late int index; List colors = [ Colors.blue, Colors.yellow, @@ -190,14 +196,14 @@ class _LineCustomPainter extends LineSegment { _dashPath( bottomLinePath, dashArray: _CircularIntervalList([15, 3, 3, 3]), - ), + )!, bottomLinePaint); canvas.drawPath( _dashPath( topLinePath, dashArray: _CircularIntervalList([15, 3, 3, 3]), - ), + )!, topLinePaint); final TextSpan span = TextSpan( @@ -230,9 +236,9 @@ class _LineCustomPainter extends LineSegment { } } -Path _dashPath( +Path? _dashPath( Path source, { - @required _CircularIntervalList dashArray, + required _CircularIntervalList dashArray, }) { if (source == null) { return null; diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/default_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/line/default_line_chart.dart index 65d35c04..db8ea8e2 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/default_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/default_line_chart.dart @@ -21,11 +21,11 @@ class _LineDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultLineChart(); + return _buildDefaultLineChart(); } /// Get the cartesian chart with default line series - SfCartesianChart _getDefaultLineChart() { + SfCartesianChart _buildDefaultLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Inflation - Consumer price'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/line_with_dashes.dart b/lib/samples/chart/cartesian_charts/chart_types/line/line_with_dashes.dart index 81d0955f..45b05bb1 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/line_with_dashes.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/line_with_dashes.dart @@ -21,11 +21,11 @@ class _LineDashedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDashedLineChart(); + return _buildDashedLineChart(); } /// Get the cartesian chart with dashed line series - SfCartesianChart _getDashedLineChart() { + SfCartesianChart _buildDashedLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/multi_colored_line.dart b/lib/samples/chart/cartesian_charts/chart_types/line/multi_colored_line.dart index 5c1428c6..e10cc428 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/multi_colored_line.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/multi_colored_line.dart @@ -19,14 +19,24 @@ class LineMultiColor extends SampleView { class _LineMultiColorState extends SampleViewState { _LineMultiColorState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + _trackballBehavior = TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + lineType: TrackballLineType.vertical, + tooltipSettings: InteractiveTooltip(format: 'point.x : point.y')); + super.initState(); + } @override Widget build(BuildContext context) { - return _getMultiColorLineChart(); + return _buildMultiColorLineChart(); } ///Get the chart with multi colored line series - SfCartesianChart _getMultiColorLineChart() { + SfCartesianChart _buildMultiColorLineChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Annual rainfall of Paris'), plotAreaBorderWidth: 0, @@ -43,11 +53,7 @@ class _LineMultiColorState extends SampleViewState { labelFormat: '{value}mm', majorTickLines: MajorTickLines(size: 0)), series: _getMultiColoredLineSeries(), - trackballBehavior: TrackballBehavior( - enable: true, - activationMode: ActivationMode.singleTap, - lineType: TrackballLineType.vertical, - tooltipSettings: InteractiveTooltip(format: 'point.x : point.y')), + trackballBehavior: _trackballBehavior, ); } @@ -94,5 +100,5 @@ class _ChartData { _ChartData(this.x, this.y, [this.lineColor]); final DateTime x; final double y; - final Color lineColor; + final Color? lineColor; } diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_area.dart b/lib/samples/chart/cartesian_charts/chart_types/range_area.dart index b85b8c20..d71d0f31 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_area.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_area.dart @@ -23,14 +23,20 @@ class RangeArea extends SampleView { /// State class of the Range area chart. class _RangeAreaState extends SampleViewState { _RangeAreaState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior(enable: true, decimalPlaces: 1); + super.initState(); + } @override Widget build(BuildContext context) { - return _getRangeAreaChart(); + return _buildRangeAreaChart(); } /// Returns the Cartesian Range area chart. - SfCartesianChart _getRangeAreaChart() { + SfCartesianChart _buildRangeAreaChart() { return SfCartesianChart( title: ChartTitle(text: 'Average temperature variation'), plotAreaBorderWidth: 0, @@ -44,7 +50,7 @@ class _RangeAreaState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getRangeAreaSeries(), - tooltipBehavior: TooltipBehavior(enable: true, decimalPlaces: 1), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart index 2db7c553..079f8151 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart @@ -23,8 +23,8 @@ class AnimationRangeColumnDefault extends SampleView { class _AnimationRangeColumnDefaultState extends SampleViewState { _AnimationRangeColumnDefaultState(); - Timer _timer; - List<_ChartData> _chartData; + Timer? _timer; + late List<_ChartData> _chartData; @override Widget build(BuildContext context) { @@ -34,11 +34,11 @@ class _AnimationRangeColumnDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationRangeColumnChart(); + return _buildAnimationRangeColumnChart(); } /// Get range column chart animation. - SfCartesianChart _getAnimationRangeColumnChart() { + SfCartesianChart _buildAnimationRangeColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), @@ -64,10 +64,10 @@ class _AnimationRangeColumnDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer?.cancel(); } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_column/default_range_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/range_column/default_range_column_chart.dart index 9c535055..9aac3b0d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_column/default_range_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_column/default_range_column_chart.dart @@ -19,14 +19,21 @@ class RangeColumnDefault extends SampleView { /// State class of range column chart. class _RangeColumnDefaultState extends SampleViewState { _RangeColumnDefaultState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultRangeColumnChart(); + return _buildDefaultRangeColumnChart(); } /// Returns the default range column chart. - SfCartesianChart _getDefaultRangeColumnChart() { + SfCartesianChart _buildDefaultRangeColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -42,8 +49,7 @@ class _RangeColumnDefaultState extends SampleViewState { labelFormat: '{value}°C', majorTickLines: MajorTickLines(size: 0)), series: _getDefaultRangeColumnSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_column/range_column_with_track.dart b/lib/samples/chart/cartesian_charts/chart_types/range_column/range_column_with_track.dart index 5e7cfb7d..718e2fd8 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_column/range_column_with_track.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_column/range_column_with_track.dart @@ -19,14 +19,21 @@ class RangeColumnWithTrack extends SampleView { /// State class of range column chart with tracker. class _RangeColumnWithTrackState extends SampleViewState { _RangeColumnWithTrackState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, canShowMarker: false, header: ''); + super.initState(); + } @override Widget build(BuildContext context) { - return _getRangeColumnwithTrack(); + return _buildRangeColumnwithTrack(); } /// Returns the range column chart with tracker. - SfCartesianChart _getRangeColumnwithTrack() { + SfCartesianChart _buildRangeColumnwithTrack() { return SfCartesianChart( plotAreaBorderWidth: 0, title: @@ -41,8 +48,7 @@ class _RangeColumnWithTrackState extends SampleViewState { labelFormat: '{value} PM', majorTickLines: MajorTickLines(size: 0)), series: _getRangeColumnSerieswithTrack(), - tooltipBehavior: - TooltipBehavior(enable: true, canShowMarker: false, header: ''), + tooltipBehavior: _tooltipBehavior, ); } @@ -65,7 +71,7 @@ class _RangeColumnWithTrackState extends SampleViewState { isTrackVisible: true, trackColor: const Color.fromRGBO(198, 201, 207, 1), borderRadius: BorderRadius.circular(15), - trackBorderColor: Colors.grey[100], + trackBorderColor: Colors.grey[100]!, xValueMapper: (ChartSampleData sales, _) => sales.x, lowValueMapper: (ChartSampleData sales, _) => sales.y, highValueMapper: (ChartSampleData sales, _) => sales.yValue, diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_column/vertical_range_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/range_column/vertical_range_column_chart.dart index 5574e488..577fbc0b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_column/vertical_range_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_column/vertical_range_column_chart.dart @@ -22,11 +22,11 @@ class _RangeBarChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRangeBarChart(); + return _buildRangeBarChart(); } /// Returns the vertical range column chart. - SfCartesianChart _getRangeBarChart() { + SfCartesianChart _buildRangeBarChart() { return SfCartesianChart( plotAreaBorderWidth: 1, title: ChartTitle( diff --git a/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart index efb79f5e..a594b476 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart @@ -23,8 +23,8 @@ class AnimationScatterDefault extends SampleView { class _AnimationScatterDefaultState extends SampleViewState { _AnimationScatterDefaultState(); - Timer _timer; - List<_ChartData> _chartData; + Timer? _timer; + late List<_ChartData> _chartData; @override Widget build(BuildContext context) { @@ -34,11 +34,11 @@ class _AnimationScatterDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationScatterChart(); + return _buildAnimationScatterChart(); } /// Get the Scatter chart sample with dynamically updated data points. - SfCartesianChart _getAnimationScatterChart() { + SfCartesianChart _buildAnimationScatterChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), @@ -64,10 +64,10 @@ class _AnimationScatterDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer?.cancel(); } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/scatter/default_scatter_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/scatter/default_scatter_chart.dart index c05714ff..a2835c87 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/scatter/default_scatter_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/scatter/default_scatter_chart.dart @@ -22,11 +22,11 @@ class _ScatterDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultScatterChart(); + return _buildDefaultScatterChart(); } /// Returns the default scatter chart. - SfCartesianChart _getDefaultScatterChart() { + SfCartesianChart _buildDefaultScatterChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Export growth rate'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/scatter/scatter_with_various_shapes.dart b/lib/samples/chart/cartesian_charts/chart_types/scatter/scatter_with_various_shapes.dart index 2314eac0..c625143d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/scatter/scatter_with_various_shapes.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/scatter/scatter_with_various_shapes.dart @@ -19,14 +19,21 @@ class ScatterShapes extends SampleView { /// State class of scatter chart with various shapes. class _ScatterShapesState extends SampleViewState { _ScatterShapesState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getShapesScatterChart(); + return _buildShapesScatterChart(); } /// Returns the scatter chart with various shapes. - SfCartesianChart _getShapesScatterChart() { + SfCartesianChart _buildShapesScatterChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Inflation Analysis'), @@ -43,8 +50,7 @@ class _ScatterShapesState extends SampleViewState { labelFormat: '{value}%', axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, series: _getScatterShapesSeries(), ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart index 44c25d8e..38242b4c 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart @@ -22,9 +22,9 @@ class AnimationSplineDefault extends SampleView { class _AnimationSplineDefaultState extends SampleViewState { _AnimationSplineDefaultState(); - List<_ChartData> _chartData; + late List<_ChartData> _chartData; - Timer _timer; + Timer? _timer; @override Widget build(BuildContext context) { _getChartData(); @@ -33,11 +33,11 @@ class _AnimationSplineDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationSplineChart(); + return _buildAnimationSplineChart(); } /// get the spline chart sample with dynamically updated data points. - SfCartesianChart _getAnimationSplineChart() { + SfCartesianChart _buildAnimationSplineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), @@ -63,11 +63,11 @@ class _AnimationSplineDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - _timer.cancel(); + _timer?.cancel(); } /// get the random value - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart index 70facbd2..03a4f42c 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart @@ -26,11 +26,11 @@ class _SplineVerticalState extends SampleViewState { @override Widget build(BuildContext context) { - return _getCustomizedSplineChart(); + return _buildCustomizedSplineChart(); } /// Returns the customized spline chart. - SfCartesianChart _getCustomizedSplineChart() { + SfCartesianChart _buildCustomizedSplineChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Product sales prediction'), plotAreaBorderWidth: 0, @@ -45,7 +45,7 @@ class _SplineVerticalState extends SampleViewState { series: >[ SplineSeries( onCreateRenderer: (ChartSeries series) { - return _CustomSplineSeriesRenderer(series); + return _CustomSplineSeriesRenderer(series as SplineSeries); }, dataSource: [ ChartSampleData(x: 2016, y: 2), @@ -81,25 +81,25 @@ class _CustomSplineSeriesRenderer extends SplineSeriesRenderer { } } -List _yVal; -List _xVal; -double _textXOffset, _textYOffset; -double _text1XOffset, _text1YOffset; +late List _yVal; +late List _xVal; +double? _textXOffset, _textYOffset; +double? _text1XOffset, _text1YOffset; /// custom spline painter class for customized spline series. class _SplineCustomPainter extends SplineSegment { _SplineCustomPainter(int value, this.series) { //ignore: prefer_initializing_formals index = value; - _yVal = []; - _xVal = []; + _yVal = []; + _xVal = []; } final SplineSeries series; - double maximum, minimum; + late double maximum, minimum; - int index; + late int index; List colors = [ Colors.blue, @@ -110,7 +110,7 @@ class _SplineCustomPainter extends SplineSegment { ]; @override - int get currentSegmentIndex => super.currentSegmentIndex; + int get currentSegmentIndex => super.currentSegmentIndex!; @override Paint getStrokePaint() { @@ -144,10 +144,10 @@ class _SplineCustomPainter extends SplineSegment { final Path path = Path(); path.moveTo(x1, y1); path.cubicTo( - startControlX, startControlY, endControlX, endControlY, x2, y2); + startControlX!, startControlY!, endControlX!, endControlY!, x2, y2); currentSegmentIndex < 4 ? canvas.drawPath(path, getStrokePaint()) - : _drawDashedLine(canvas, series, strokePaint, path, true); + : _drawDashedLine(canvas, series, strokePaint!, path, true); if (currentSegmentIndex == 5) { _textXOffset = _xVal[0]; @@ -169,7 +169,7 @@ class _SplineCustomPainter extends SplineSegment { final TextPainter tp = TextPainter(text: span, textDirection: TextDirection.ltr); tp.layout(); - tp.paint(canvas, Offset(_text1XOffset, _text1YOffset + tp.size.height)); + tp.paint(canvas, Offset(_text1XOffset!, _text1YOffset! + tp.size.height)); const TextSpan span1 = TextSpan( style: TextStyle( color: Color.fromRGBO(246, 114, 128, 1), @@ -180,7 +180,7 @@ class _SplineCustomPainter extends SplineSegment { final TextPainter tp1 = TextPainter(text: span1, textDirection: TextDirection.ltr); tp1.layout(); - tp1.paint(canvas, Offset(_textXOffset, _textYOffset + tp.size.height)); + tp1.paint(canvas, Offset(_textXOffset!, _textYOffset! + tp.size.height)); } } } @@ -200,16 +200,16 @@ void _drawDashedLine(Canvas canvas, CartesianSeries series, path, dashArray: _CircularIntervalList( isSeries ? series.dashArray : [12, 3, 3, 3]), - ), + )!, paint); } else { canvas.drawPath(path, paint); } } -Path _dashPath( +Path? _dashPath( Path source, { - @required _CircularIntervalList dashArray, + required _CircularIntervalList dashArray, }) { if (source == null) { return null; diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/default_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/default_spline_chart.dart index 967b3ce1..64154fa9 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/default_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/default_spline_chart.dart @@ -22,11 +22,11 @@ class _SplineDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultSplineChart(); + return _buildDefaultSplineChart(); } /// Returns the defaul spline chart. - SfCartesianChart _getDefaultSplineChart() { + SfCartesianChart _buildDefaultSplineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart index 86f67424..c43c684e 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart @@ -22,19 +22,22 @@ class _SplineTypesState extends SampleViewState { final List _splineList = ['natural', 'monotonic', 'cardinal', 'clamped'].toList(); - String _selectedSplineType = 'natural'; - SplineType _spline = SplineType.natural; + late String _selectedSplineType; + late SplineType _spline; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedSplineType = 'natural'; _spline = SplineType.natural; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { - return _getTypesSplineChart(); + return _buildTypesSplineChart(); } @override @@ -72,7 +75,7 @@ class _SplineTypesState extends SampleViewState { } /// Returns the spline types chart. - SfCartesianChart _getTypesSplineChart() { + SfCartesianChart _buildTypesSplineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Export growth of Brazil'), @@ -87,8 +90,7 @@ class _SplineTypesState extends SampleViewState { interval: 0.1, majorTickLines: MajorTickLines(size: 0)), series: _getSplineTypesSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_with_dashes.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_with_dashes.dart index 64519197..31ed09ae 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_with_dashes.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_with_dashes.dart @@ -22,11 +22,11 @@ class _SplineDashedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDashedSplineChart(); + return _buildDashedSplineChart(); } /// Returns the dashed spline chart. - SfCartesianChart _getDashedSplineChart() { + SfCartesianChart _buildDashedSplineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Total investment (% of GDP)'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/vertical_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/vertical_spline_chart.dart index 958bc2f4..c492c048 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/vertical_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/vertical_spline_chart.dart @@ -22,11 +22,11 @@ class _SplineVerticalState extends SampleViewState { @override Widget build(BuildContext context) { - return _getVerticalSplineChart(); + return _buildVerticalSplineChart(); } /// Returns the vertical spline chart. - SfCartesianChart _getVerticalSplineChart() { + SfCartesianChart _buildVerticalSplineChart() { return SfCartesianChart( isTransposed: true, title: ChartTitle(text: isCardView ? '' : 'Climate graph - 2012'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline_area.dart b/lib/samples/chart/cartesian_charts/chart_types/spline_area.dart index 55b2cefd..e8e077bc 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline_area.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline_area.dart @@ -22,11 +22,11 @@ class _SplineAreaState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSplineAreaChart(); + return _buildSplineAreaChart(); } /// Returns the cartesian spline are chart. - SfCartesianChart _getSplineAreaChart() { + SfCartesianChart _buildSplineAreaChart() { return SfCartesianChart( legend: Legend(isVisible: true, opacity: 0.7), title: ChartTitle(text: 'Inflation rate'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline_range_area.dart b/lib/samples/chart/cartesian_charts/chart_types/spline_range_area.dart index 4a74ee72..af2097b7 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline_range_area.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline_range_area.dart @@ -21,11 +21,11 @@ class _SplineRangeAreaState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSplineRangeAreaChart(); + return _buildSplineRangeAreaChart(); } ///Get chart with spline range area chart - SfCartesianChart _getSplineRangeAreaChart() { + SfCartesianChart _buildSplineRangeAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: 'Product price comparison'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart index a2f9096c..4932154b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_area_100_chart.dart @@ -20,14 +20,21 @@ class StackedArea100Chart extends SampleView { /// State class of the stacked area 1oo chart. class _StackedAreaChartState extends SampleViewState { _StackedAreaChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedArea100Chart(); + return _buildStackedArea100Chart(); } /// Returns the stacked area 100 chart. - SfCartesianChart _getStackedArea100Chart() { + SfCartesianChart _buildStackedArea100Chart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -43,8 +50,7 @@ class _StackedAreaChartState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getStackedAreaSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart index aa3468ce..00cb0afb 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_bar_100_chart.dart @@ -19,14 +19,21 @@ class StackedBar100Chart extends SampleView { /// State class of the stacked bar 100 chart. class _StackedBar100ChartState extends SampleViewState { _StackedBar100ChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedBar100Chart(); + return _buildStackedBar100Chart(); } /// Returns the cartesian stacked bar 100 chart. - SfCartesianChart _getStackedBar100Chart() { + SfCartesianChart _buildStackedBar100Chart() { return SfCartesianChart( plotAreaBorderWidth: 1, title: ChartTitle(text: isCardView ? '' : 'Sales comparison of fruits'), @@ -39,8 +46,7 @@ class _StackedBar100ChartState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getStackedBarSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart index 929bcb0d..796604a8 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_column_100_chart.dart @@ -19,14 +19,21 @@ class StackedColumn100Chart extends SampleView { /// State class of the stacked column 100 chart. class _StackedColumn100ChartState extends SampleViewState { _StackedColumn100ChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedColumn100Chart(); + return _buildStackedColumn100Chart(); } /// Returns the cartesian stacked column 100 chart. - SfCartesianChart _getStackedColumn100Chart() { + SfCartesianChart _buildStackedColumn100Chart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -41,8 +48,7 @@ class _StackedColumn100ChartState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getStackedColumnSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart index a6b7d134..3846acb5 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_100_charts/stacked_line_100_chart.dart @@ -22,11 +22,11 @@ class _StackedLineChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getStackedLine100Chart(); + return _buildStackedLine100Chart(); } /// Returns the cartesian stacked line 100 chart. - SfCartesianChart _getStackedLine100Chart() { + SfCartesianChart _buildStackedLine100Chart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Monthly expense of a family'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_area_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_area_chart.dart index f57b409a..cfb8983e 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_area_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_area_chart.dart @@ -20,14 +20,21 @@ class StackedAreaChart extends SampleView { /// State class of the stacked area chart. class _StackedAreaChartState extends SampleViewState { _StackedAreaChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedAreaChart(); + return _buildStackedAreaChart(); } /// Returns the cartesian stacked area chart. - SfCartesianChart _getStackedAreaChart() { + SfCartesianChart _buildStackedAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -43,8 +50,7 @@ class _StackedAreaChartState extends SampleViewState { labelFormat: '{value}B', majorTickLines: MajorTickLines(size: 0)), series: _getStackedAreaSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_bar_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_bar_chart.dart index 3b7b5ca2..2e7b05b5 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_bar_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_bar_chart.dart @@ -19,14 +19,21 @@ class StackedBarChart extends SampleView { /// State class of the stacked bar chart. class _StackedBarChartState extends SampleViewState { _StackedBarChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedBarChart(); + return _buildStackedBarChart(); } /// Reutrns the cartesian stacked bar chart. - SfCartesianChart _getStackedBarChart() { + SfCartesianChart _buildStackedBarChart() { return SfCartesianChart( plotAreaBorderWidth: 1, title: ChartTitle(text: isCardView ? '' : 'Sales comparison of fruits'), @@ -39,8 +46,7 @@ class _StackedBarChartState extends SampleViewState { labelFormat: '{value}%', majorTickLines: MajorTickLines(size: 0)), series: _getStackedBarSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_column_chart.dart index f81140bd..c3d8690d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_column_chart.dart @@ -19,14 +19,21 @@ class StackedColumnChart extends SampleView { /// State class of the stacked column chart. class _StackedColumnChartState extends SampleViewState { _StackedColumnChartState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedColumnChart(); + return _buildStackedColumnChart(); } /// Returns the cartesian Stacked column chart. - SfCartesianChart _getStackedColumnChart() { + SfCartesianChart _buildStackedColumnChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -42,8 +49,7 @@ class _StackedColumnChartState extends SampleViewState { maximum: 300, majorTickLines: MajorTickLines(size: 0)), series: _getStackedColumnSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_line_chart.dart index 5d00481c..aeefde81 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/stacked_charts/stacked_line_chart.dart @@ -19,14 +19,21 @@ class StackedLineChart extends SampleView { /// State class of the stacked line chart. class _StackedLineChartState extends SampleViewState { _StackedLineChartState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + _trackballBehavior = TrackballBehavior( + enable: true, activationMode: ActivationMode.singleTap); + super.initState(); + } @override Widget build(BuildContext context) { - return _getStackedLineChart(); + return _buildStackedLineChart(); } /// Returns the cartesian stacked line chart. - SfCartesianChart _getStackedLineChart() { + SfCartesianChart _buildStackedLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Monthly expense of a family'), @@ -41,8 +48,7 @@ class _StackedLineChartState extends SampleViewState { labelFormat: '\${value}', majorTickLines: MajorTickLines(size: 0)), series: _getStackedLineSeries(), - trackballBehavior: TrackballBehavior( - enable: true, activationMode: ActivationMode.singleTap), + trackballBehavior: _trackballBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_area.dart b/lib/samples/chart/cartesian_charts/chart_types/step_area.dart index 6792a3eb..7d7b9a26 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_area.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_area.dart @@ -23,12 +23,13 @@ class _StepAreaState extends SampleViewState { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 60), - child: _getStepAreaChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 60), + child: _buildStepAreaChart()); } /// Returns the cartesian step area chart. - SfCartesianChart _getStepAreaChart() { + SfCartesianChart _buildStepAreaChart() { return SfCartesianChart( legend: Legend(isVisible: true), title: ChartTitle(text: 'Temperature variation of Paris'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart index fd669017..80b03d50 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart @@ -23,7 +23,7 @@ class AnimationStepLineDefault extends SampleView { class _AnimationStepLineDefaultState extends SampleViewState { _AnimationStepLineDefaultState(); - Timer timer; + Timer? timer; @override Widget build(BuildContext context) { @@ -33,11 +33,11 @@ class _AnimationStepLineDefaultState extends SampleViewState { _getChartData(); }); }); - return _getAnimationStepLineChart(); + return _buildAnimationStepLineChart(); } /// get the stepline chart sample with dynamically updated data points. - SfCartesianChart _getAnimationStepLineChart() { + SfCartesianChart _buildAnimationStepLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), @@ -62,10 +62,10 @@ class _AnimationStepLineDefaultState extends SampleViewState { @override void dispose() { super.dispose(); - timer.cancel(); + timer?.cancel(); } - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } @@ -80,7 +80,7 @@ class _AnimationStepLineDefaultState extends SampleViewState { } } -List<_ChartData> _chartData; +late List<_ChartData> _chartData; class _ChartData { _ChartData(this.x, this.y); diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_line/default_step_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/step_line/default_step_line_chart.dart index 87807bd1..82c31150 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_line/default_step_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_line/default_step_line_chart.dart @@ -22,11 +22,11 @@ class _StepLineDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultStepLineChart(); + return _buildDefaultStepLineChart(); } /// Returns the default cartesian stepline chart. - SfCartesianChart _getDefaultStepLineChart() { + SfCartesianChart _buildDefaultStepLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Electricity-Production'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_line/step_line_with_dashes.dart b/lib/samples/chart/cartesian_charts/chart_types/step_line/step_line_with_dashes.dart index 388616fc..bcd6c4cf 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_line/step_line_with_dashes.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_line/step_line_with_dashes.dart @@ -22,11 +22,11 @@ class _StepLineDashedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDashedStepLineChart(); + return _buildDashedStepLineChart(); } /// Returns the dashed cartesian stepline chart. - SfCartesianChart _getDashedStepLineChart() { + SfCartesianChart _buildDashedStepLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'CO2 - Intensity analysis'), diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_line/vertical_step_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/step_line/vertical_step_line_chart.dart index 72fa50ec..a452cdd9 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_line/vertical_step_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_line/vertical_step_line_chart.dart @@ -23,11 +23,11 @@ class _StepLineVerticalState extends SampleViewState { @override Widget build(BuildContext context) { - return _getVerticalStepLineChart(); + return _buildVerticalStepLineChart(); } /// Returns the vertical stepline chart. - SfCartesianChart _getVerticalStepLineChart() { + SfCartesianChart _buildVerticalStepLineChart() { return SfCartesianChart( legend: Legend(isVisible: !isCardView), title: diff --git a/lib/samples/chart/cartesian_charts/chart_types/waterfall/vertical_waterfall.dart b/lib/samples/chart/cartesian_charts/chart_types/waterfall/vertical_waterfall.dart index eab12e85..3a8bddd2 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/waterfall/vertical_waterfall.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/waterfall/vertical_waterfall.dart @@ -7,8 +7,9 @@ import 'package:syncfusion_flutter_charts/charts.dart'; /// Local imports import '../../../../../model/sample_view.dart'; -///Renders histogram chart sample +///Renders vertical water fall chart sample class VerticalWaterFall extends SampleView { + /// Creates the vertical water fall chart const VerticalWaterFall(Key key) : super(key: key); @override @@ -18,9 +19,9 @@ class VerticalWaterFall extends SampleView { class _VerticalWaterFallState extends SampleViewState { _VerticalWaterFallState(); - TooltipBehavior tooltipBehavior1 = TooltipBehavior(enable: true); - TooltipBehavior tooltipBehavior2 = TooltipBehavior(enable: true); - TooltipBehavior tooltipBehavior3 = TooltipBehavior(enable: true); + late TooltipBehavior tooltipBehavior1; + late TooltipBehavior tooltipBehavior2; + late TooltipBehavior tooltipBehavior3; @override Widget build(BuildContext context) { @@ -87,10 +88,9 @@ class _VerticalWaterFallState extends SampleViewState { }, plotAreaBorderWidth: 0, isTransposed: true, - onAxisLabelRender: (AxisLabelRenderArgs args) { - if (args.axisName == 'XAxis') { - args.text = ''; - } + axisLabelFormatter: (AxisLabelRenderDetails details) { + return ChartAxisLabel( + details.axisName == 'XAxis' ? '' : details.text, null); }, margin: EdgeInsets.fromLTRB(0, 10, 10, 10), title: ChartTitle( @@ -139,10 +139,9 @@ class _VerticalWaterFallState extends SampleViewState { fontStyle: FontStyle.normal, fontWeight: FontWeight.normal, fontFamily: 'Normal')), - onAxisLabelRender: (AxisLabelRenderArgs args) { - if (args.axisName == 'XAxis') { - args.text = ''; - } + axisLabelFormatter: (AxisLabelRenderDetails details) { + return ChartAxisLabel( + details.axisName == 'XAxis' ? '' : details.text, null); }, margin: EdgeInsets.fromLTRB(0, 10, 10, 10), primaryXAxis: CategoryAxis( @@ -356,6 +355,9 @@ class _VerticalWaterFallState extends SampleViewState { @override void initState() { + tooltipBehavior1 = TooltipBehavior(enable: true); + tooltipBehavior2 = TooltipBehavior(enable: true); + tooltipBehavior3 = TooltipBehavior(enable: true); super.initState(); } } @@ -364,8 +366,8 @@ class _ChartSampleData { _ChartSampleData( {this.x, this.y, this.intermediateSumPredicate, this.totalSumPredicate}); - final String x; - final num y; - final bool intermediateSumPredicate; - final bool totalSumPredicate; + final String? x; + final num? y; + final bool? intermediateSumPredicate; + final bool? totalSumPredicate; } diff --git a/lib/samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart b/lib/samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart index cbd19a0e..c788eed4 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/waterfall/waterfall.dart @@ -9,6 +9,7 @@ import '../../../../../model/sample_view.dart'; ///Renders histogram chart sample class WaterFall extends SampleView { + /// Creates waterfall chart const WaterFall(Key key) : super(key: key); @override @@ -17,18 +18,22 @@ class WaterFall extends SampleView { class _WaterFallState extends SampleViewState { _WaterFallState(); + late TooltipBehavior _tooltipBehavior; @override Widget build(BuildContext context) { - return _getDefaultWaterfallChart(); + return _buildDefaultWaterfallChart(); } /// Get the cartesian chart with histogram series - SfCartesianChart _getDefaultWaterfallChart() { + SfCartesianChart _buildDefaultWaterfallChart() { return SfCartesianChart( - onAxisLabelRender: (AxisLabelRenderArgs args) { - if (args.axis.name == 'Expenditure') - args.text = (args.value ~/ 1000).toString() + 'B'; + axisLabelFormatter: (AxisLabelRenderDetails details) { + return ChartAxisLabel( + details.axisName == 'Expenditure' + ? (details.value ~/ 1000).toString() + 'B' + : details.text, + null); }, plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Company revenue and profit'), @@ -45,18 +50,14 @@ class _WaterFallState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getWaterFallSeries(), - tooltipBehavior: TooltipBehavior(enable: true, header: ''), + tooltipBehavior: _tooltipBehavior, onTooltipRender: (TooltipArgs args) { - args.text = args.dataPoints[args.pointIndex].x.toString() + + args.text = args.dataPoints![args.pointIndex!.toInt()].x.toString() + ' : ' + - (args.dataPoints[args.pointIndex].y / 1000).toString() + + (args.dataPoints![args.pointIndex!.toInt()].y / 1000).toString() + 'B'; }, onDataLabelRender: (dataLabelArgs) { - // double value = double.parse(dataLabelArgs.text)/1000; - // value = (value * 100).roundToDouble()/100; - // dataLabelArgs.text = value.toString(); - // print(dataLabelArgs.text); if (dataLabelArgs.pointIndex == 0) { dataLabelArgs.text = '4.7B'; } else if (dataLabelArgs.pointIndex == 1) { @@ -140,6 +141,7 @@ class _WaterFallState extends SampleViewState { @override void initState() { + _tooltipBehavior = TooltipBehavior(enable: true, header: ''); super.initState(); } } @@ -148,8 +150,8 @@ class _ChartSampleData { _ChartSampleData( {this.x, this.y, this.intermediateSumPredicate, this.totalSumPredicate}); - final String x; - final num y; - final bool intermediateSumPredicate; - final bool totalSumPredicate; + final String? x; + final num? y; + final bool? intermediateSumPredicate; + final bool? totalSumPredicate; } diff --git a/lib/samples/chart/cartesian_charts/data_source/json.dart b/lib/samples/chart/cartesian_charts/data_source/json.dart index 57146c12..c71d332a 100644 --- a/lib/samples/chart/cartesian_charts/data_source/json.dart +++ b/lib/samples/chart/cartesian_charts/data_source/json.dart @@ -23,8 +23,9 @@ class JsonData extends SampleView { class _JsonDataState extends SampleViewState { _JsonDataState(); + late TrackballBehavior _trackballBehavior; - List chartData = []; + List<_SampleData> chartData = []; // Method to load Json file from assets. Future _loadSalesDataAsset() async { @@ -33,28 +34,41 @@ class _JsonDataState extends SampleViewState { // Method to hanlde deserialization steps. Future loadSalesData() async { - String jsonString = await _loadSalesDataAsset(); // Deserialization step 1 + final String jsonString = + await _loadSalesDataAsset(); // Deserialization step 1 final jsonResponse = json.decode(jsonString); // Deserialization step 2 setState(() { - for (Map i in jsonResponse) { - chartData.add(SampleData.fromJson(i)); // Deserialization step 3 + for (final Map i in jsonResponse) { + chartData.add(_SampleData.fromJson(i)); // Deserialization step 3 } }); } @override void initState() { - loadSalesData(); super.initState(); + loadSalesData(); + _trackballBehavior = TrackballBehavior( + enable: true, + lineColor: model.themeData.brightness == Brightness.dark + ? const Color.fromRGBO(255, 255, 255, 0.03) + : const Color.fromRGBO(0, 0, 0, 0.03), + lineWidth: 15, + activationMode: ActivationMode.singleTap, + markerSettings: TrackballMarkerSettings( + borderWidth: 4, + height: 10, + width: 10, + markerVisibility: TrackballVisibilityMode.visible)); } @override Widget build(BuildContext context) { - return _getDefaultLineChart(); + return _buildDefaultLineChart(); } /// Get the cartesian chart with default line series - SfCartesianChart _getDefaultLineChart() { + SfCartesianChart _buildDefaultLineChart() { return SfCartesianChart( key: GlobalKey(), plotAreaBorderWidth: 0, @@ -77,50 +91,39 @@ class _JsonDataState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(color: Colors.transparent)), series: _getDefaultLineSeries(), - trackballBehavior: TrackballBehavior( - enable: true, - lineColor: model.themeData.brightness == Brightness.dark - ? const Color.fromRGBO(255, 255, 255, 0.03) - : const Color.fromRGBO(0, 0, 0, 0.03), - lineWidth: 15, - activationMode: ActivationMode.singleTap, - markerSettings: TrackballMarkerSettings( - borderWidth: 4, - height: 10, - width: 10, - markerVisibility: TrackballVisibilityMode.visible)), + trackballBehavior: _trackballBehavior, ); } /// The method returns line series to chart. - List> _getDefaultLineSeries() { - return >[ - LineSeries( + List> _getDefaultLineSeries() { + return >[ + LineSeries<_SampleData, DateTime>( dataSource: chartData, - xValueMapper: (SampleData sales, _) => sales.x, - yValueMapper: (SampleData sales, _) => sales.y1, + xValueMapper: (_SampleData sales, _) => sales.x, + yValueMapper: (_SampleData sales, _) => sales.y1, name: 'Product A', ), - LineSeries( + LineSeries<_SampleData, DateTime>( dataSource: chartData, name: 'Product B', - xValueMapper: (SampleData sales, _) => sales.x, - yValueMapper: (SampleData sales, _) => sales.y2, + xValueMapper: (_SampleData sales, _) => sales.x, + yValueMapper: (_SampleData sales, _) => sales.y2, ) ]; } } -class SampleData { - SampleData(this.x, this.y1, this.y2); - DateTime x; - num y1; - num y2; - factory SampleData.fromJson(Map parsedJson) { - return SampleData( +class _SampleData { + factory _SampleData.fromJson(Map parsedJson) { + return _SampleData( DateTime.parse(parsedJson['x']), parsedJson['y1'], parsedJson['y2'], ); } + _SampleData(this.x, this.y1, this.y2); + DateTime x; + num y1; + num y2; } diff --git a/lib/samples/chart/cartesian_charts/data_source/list.dart b/lib/samples/chart/cartesian_charts/data_source/list.dart index 46a41a85..e8b3ab2f 100644 --- a/lib/samples/chart/cartesian_charts/data_source/list.dart +++ b/lib/samples/chart/cartesian_charts/data_source/list.dart @@ -19,14 +19,31 @@ class LocalData extends SampleView { class _LocalDataState extends SampleViewState { _LocalDataState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + super.initState(); + _trackballBehavior = TrackballBehavior( + enable: true, + lineColor: model.themeData.brightness == Brightness.dark + ? const Color.fromRGBO(255, 255, 255, 0.03) + : const Color.fromRGBO(0, 0, 0, 0.03), + lineWidth: 15, + activationMode: ActivationMode.singleTap, + markerSettings: TrackballMarkerSettings( + borderWidth: 4, + height: 10, + width: 10, + markerVisibility: TrackballVisibilityMode.visible)); + } @override Widget build(BuildContext context) { - return _getDefaultLineChart(); + return _buildDefaultLineChart(); } /// Get the cartesian chart with default line series - SfCartesianChart _getDefaultLineChart() { + SfCartesianChart _buildDefaultLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Sales comparison'), @@ -48,311 +65,300 @@ class _LocalDataState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(color: Colors.transparent)), series: _getDefaultLineSeries(), - trackballBehavior: TrackballBehavior( - enable: true, - lineColor: model.themeData.brightness == Brightness.dark - ? const Color.fromRGBO(255, 255, 255, 0.03) - : const Color.fromRGBO(0, 0, 0, 0.03), - lineWidth: 15, - activationMode: ActivationMode.singleTap, - markerSettings: TrackballMarkerSettings( - borderWidth: 4, - height: 10, - width: 10, - markerVisibility: TrackballVisibilityMode.visible)), + trackballBehavior: _trackballBehavior, ); } /// The method returns line series to chart. - List> _getDefaultLineSeries() { - List chartData = [ - ChartData(x: DateTime(1980, 1, 23), y1: 83, y2: 94), - ChartData(x: DateTime(1980, 2, 24), y1: 83, y2: 93), - ChartData(x: DateTime(1980, 3, 25), y1: 82, y2: 93), - ChartData(x: DateTime(1980, 4, 26), y1: 83, y2: 93), - ChartData(x: DateTime(1980, 5, 27), y1: 83, y2: 93), - ChartData(x: DateTime(1980, 6, 28), y1: 84, y2: 94), - ChartData(x: DateTime(1980, 7, 29), y1: 84, y2: 94), - ChartData(x: DateTime(1980, 9, 30), y1: 85, y2: 95), - ChartData(x: DateTime(1980, 10, 1), y1: 84, y2: 94), - ChartData(x: DateTime(1980, 11, 2), y1: 83, y2: 93), - ChartData(x: DateTime(1980, 12, 3), y1: 83, y2: 94), - ChartData(x: DateTime(1981, 1, 4), y1: 83, y2: 94), - ChartData(x: DateTime(1981, 2, 5), y1: 82, y2: 93), - ChartData(x: DateTime(1981, 3, 6), y1: 82, y2: 93), - ChartData(x: DateTime(1981, 4, 7), y1: 82, y2: 94), - ChartData(x: DateTime(1981, 5, 8), y1: 83, y2: 94), - ChartData(x: DateTime(1981, 6, 9), y1: 83, y2: 94), - ChartData(x: DateTime(1981, 7, 10), y1: 83, y2: 94), - ChartData(x: DateTime(1981, 8, 11), y1: 83, y2: 95), - ChartData(x: DateTime(1981, 9, 12), y1: 84, y2: 95), - ChartData(x: DateTime(1981, 10, 13), y1: 83, y2: 95), - ChartData(x: DateTime(1981, 11, 14), y1: 84, y2: 96), - ChartData(x: DateTime(1981, 12, 15), y1: 83, y2: 96), - ChartData(x: DateTime(1982, 1, 16), y1: 84, y2: 97), - ChartData(x: DateTime(1982, 2, 17), y1: 84, y2: 96), - ChartData(x: DateTime(1982, 3, 18), y1: 84, y2: 96), - ChartData(x: DateTime(1982, 4, 19), y1: 84, y2: 96), - ChartData(x: DateTime(1982, 5, 20), y1: 84, y2: 96), - ChartData(x: DateTime(1982, 6, 21), y1: 83, y2: 95), - ChartData(x: DateTime(1982, 7, 22), y1: 84, y2: 96), - ChartData(x: DateTime(1982, 8, 23), y1: 83, y2: 95), - ChartData(x: DateTime(1982, 9, 24), y1: 83, y2: 94), - ChartData(x: DateTime(1982, 10, 25), y1: 83, y2: 95), - ChartData(x: DateTime(1982, 11, 26), y1: 83, y2: 94), - ChartData(x: DateTime(1982, 12, 27), y1: 84, y2: 94), - ChartData(x: DateTime(1983, 1, 28), y1: 85, y2: 95), - ChartData(x: DateTime(1983, 2, 29), y1: 84, y2: 95), - ChartData(x: DateTime(1983, 4, 30), y1: 84, y2: 95), - ChartData(x: DateTime(1983, 5, 1), y1: 83, y2: 95), - ChartData(x: DateTime(1983, 6, 2), y1: 84, y2: 95), - ChartData(x: DateTime(1983, 7, 3), y1: 85, y2: 95), - ChartData(x: DateTime(1983, 8, 4), y1: 86, y2: 95), - ChartData(x: DateTime(1983, 9, 5), y1: 86, y2: 96), - ChartData(x: DateTime(1983, 10, 6), y1: 87, y2: 97), - ChartData(x: DateTime(1983, 11, 7), y1: 87, y2: 98), - ChartData(x: DateTime(1983, 12, 8), y1: 87, y2: 99), - ChartData(x: DateTime(1984, 1, 9), y1: 86, y2: 98), - ChartData(x: DateTime(1984, 2, 10), y1: 86, y2: 98), - ChartData(x: DateTime(1984, 3, 11), y1: 86, y2: 97), - ChartData(x: DateTime(1984, 4, 12), y1: 86, y2: 96), - ChartData(x: DateTime(1984, 5, 13), y1: 86, y2: 97), - ChartData(x: DateTime(1984, 6, 14), y1: 85, y2: 97), - ChartData(x: DateTime(1984, 7, 15), y1: 85, y2: 96), - ChartData(x: DateTime(1984, 8, 16), y1: 84, y2: 96), - ChartData(x: DateTime(1984, 9, 17), y1: 84, y2: 96), - ChartData(x: DateTime(1984, 10, 18), y1: 84, y2: 97), - ChartData(x: DateTime(1984, 11, 19), y1: 85, y2: 98), - ChartData(x: DateTime(1984, 12, 20), y1: 85, y2: 98), - ChartData(x: DateTime(1985, 1, 21), y1: 85, y2: 97), - ChartData(x: DateTime(1985, 2, 22), y1: 85, y2: 98), - ChartData(x: DateTime(1985, 3, 23), y1: 86, y2: 99), - ChartData(x: DateTime(1985, 4, 24), y1: 85, y2: 98), - ChartData(x: DateTime(1985, 5, 25), y1: 85, y2: 97), - ChartData(x: DateTime(1985, 6, 26), y1: 86, y2: 97), - ChartData(x: DateTime(1985, 7, 27), y1: 86, y2: 98), - ChartData(x: DateTime(1985, 8, 28), y1: 86, y2: 97), - ChartData(x: DateTime(1985, 9, 29), y1: 86, y2: 96), - ChartData(x: DateTime(1985, 11, 30), y1: 86, y2: 97), - ChartData(x: DateTime(1985, 12, 1), y1: 86, y2: 98), - ChartData(x: DateTime(1986, 1, 2), y1: 87, y2: 98), - ChartData(x: DateTime(1986, 2, 3), y1: 87, y2: 98), - ChartData(x: DateTime(1986, 3, 4), y1: 87, y2: 98), - ChartData(x: DateTime(1986, 4, 5), y1: 88, y2: 99), - ChartData(x: DateTime(1986, 5, 6), y1: 88, y2: 98), - ChartData(x: DateTime(1986, 6, 7), y1: 87, y2: 97), - ChartData(x: DateTime(1986, 7, 8), y1: 88, y2: 98), - ChartData(x: DateTime(1986, 8, 9), y1: 88, y2: 98), - ChartData(x: DateTime(1986, 9, 10), y1: 88, y2: 98), - ChartData(x: DateTime(1986, 10, 11), y1: 88, y2: 97), - ChartData(x: DateTime(1986, 11, 12), y1: 88, y2: 98), - ChartData(x: DateTime(1986, 12, 13), y1: 89, y2: 99), - ChartData(x: DateTime(1987, 1, 14), y1: 88, y2: 98), - ChartData(x: DateTime(1987, 2, 15), y1: 89, y2: 98), - ChartData(x: DateTime(1987, 3, 16), y1: 88, y2: 98), - ChartData(x: DateTime(1987, 4, 17), y1: 87, y2: 97), - ChartData(x: DateTime(1987, 5, 18), y1: 87, y2: 98), - ChartData(x: DateTime(1987, 6, 19), y1: 87, y2: 97), - ChartData(x: DateTime(1987, 7, 20), y1: 87, y2: 96), - ChartData(x: DateTime(1987, 8, 21), y1: 87, y2: 95), - ChartData(x: DateTime(1987, 9, 22), y1: 87, y2: 95), - ChartData(x: DateTime(1987, 10, 23), y1: 86, y2: 94), - ChartData(x: DateTime(1987, 11, 24), y1: 85, y2: 94), - ChartData(x: DateTime(1987, 12, 25), y1: 86, y2: 95), - ChartData(x: DateTime(1988, 1, 26), y1: 85, y2: 94), - ChartData(x: DateTime(1988, 2, 27), y1: 86, y2: 95), - ChartData(x: DateTime(1988, 3, 28), y1: 85, y2: 95), - ChartData(x: DateTime(1988, 4, 29), y1: 85, y2: 95), - ChartData(x: DateTime(1988, 6, 30), y1: 85, y2: 95), - ChartData(x: DateTime(1988, 7, 1), y1: 86, y2: 96), - ChartData(x: DateTime(1988, 8, 2), y1: 85, y2: 96), - ChartData(x: DateTime(1988, 9, 3), y1: 84, y2: 95), - ChartData(x: DateTime(1988, 10, 4), y1: 85, y2: 96), - ChartData(x: DateTime(1988, 11, 5), y1: 85, y2: 96), - ChartData(x: DateTime(1988, 12, 6), y1: 85, y2: 96), - ChartData(x: DateTime(1989, 1, 7), y1: 86, y2: 97), - ChartData(x: DateTime(1989, 2, 8), y1: 86, y2: 97), - ChartData(x: DateTime(1989, 3, 9), y1: 85, y2: 96), - ChartData(x: DateTime(1989, 4, 10), y1: 84, y2: 95), - ChartData(x: DateTime(1989, 5, 11), y1: 85, y2: 96), - ChartData(x: DateTime(1989, 6, 12), y1: 84, y2: 95), - ChartData(x: DateTime(1989, 7, 13), y1: 84, y2: 94), - ChartData(x: DateTime(1989, 8, 14), y1: 85, y2: 95), - ChartData(x: DateTime(1989, 9, 15), y1: 84, y2: 94), - ChartData(x: DateTime(1989, 10, 16), y1: 84, y2: 95), - ChartData(x: DateTime(1989, 11, 17), y1: 84, y2: 95), - ChartData(x: DateTime(1989, 12, 18), y1: 84, y2: 95), - ChartData(x: DateTime(1990, 1, 19), y1: 83, y2: 95), - ChartData(x: DateTime(1990, 2, 20), y1: 84, y2: 95), - ChartData(x: DateTime(1990, 3, 21), y1: 85, y2: 96), - ChartData(x: DateTime(1990, 4, 22), y1: 84, y2: 95), - ChartData(x: DateTime(1990, 5, 23), y1: 83, y2: 94), - ChartData(x: DateTime(1990, 6, 24), y1: 84, y2: 95), - ChartData(x: DateTime(1990, 7, 25), y1: 84, y2: 96), - ChartData(x: DateTime(1990, 8, 26), y1: 84, y2: 96), - ChartData(x: DateTime(1990, 9, 27), y1: 84, y2: 95), - ChartData(x: DateTime(1990, 10, 28), y1: 83, y2: 94), - ChartData(x: DateTime(1990, 11, 29), y1: 84, y2: 94), - ChartData(x: DateTime(1991, 1, 30), y1: 84, y2: 95), - ChartData(x: DateTime(1991, 2, 1), y1: 84, y2: 95), - ChartData(x: DateTime(1991, 3, 2), y1: 83, y2: 94), - ChartData(x: DateTime(1991, 4, 3), y1: 84, y2: 95), - ChartData(x: DateTime(1991, 5, 4), y1: 85, y2: 96), - ChartData(x: DateTime(1991, 6, 5), y1: 84, y2: 96), - ChartData(x: DateTime(1991, 7, 6), y1: 84, y2: 95), - ChartData(x: DateTime(1991, 8, 7), y1: 84, y2: 96), - ChartData(x: DateTime(1991, 9, 8), y1: 84, y2: 96), - ChartData(x: DateTime(1991, 10, 9), y1: 84, y2: 96), - ChartData(x: DateTime(1991, 11, 10), y1: 84, y2: 96), - ChartData(x: DateTime(1991, 12, 11), y1: 84, y2: 97), - ChartData(x: DateTime(1992, 1, 12), y1: 85, y2: 97), - ChartData(x: DateTime(1992, 2, 13), y1: 86, y2: 98), - ChartData(x: DateTime(1992, 3, 14), y1: 86, y2: 99), - ChartData(x: DateTime(1992, 4, 15), y1: 86, y2: 98), - ChartData(x: DateTime(1992, 5, 16), y1: 86, y2: 98), - ChartData(x: DateTime(1992, 6, 17), y1: 85, y2: 98), - ChartData(x: DateTime(1992, 7, 18), y1: 85, y2: 98), - ChartData(x: DateTime(1992, 8, 19), y1: 86, y2: 98), - ChartData(x: DateTime(1992, 9, 20), y1: 87, y2: 98), - ChartData(x: DateTime(1992, 10, 21), y1: 88, y2: 99), - ChartData(x: DateTime(1992, 11, 22), y1: 87, y2: 98), - ChartData(x: DateTime(1992, 12, 23), y1: 87, y2: 98), - ChartData(x: DateTime(1993, 1, 24), y1: 87, y2: 99), - ChartData(x: DateTime(1993, 2, 25), y1: 88, y2: 100), - ChartData(x: DateTime(1993, 3, 26), y1: 87, y2: 99), - ChartData(x: DateTime(1993, 4, 27), y1: 86, y2: 99), - ChartData(x: DateTime(1993, 5, 28), y1: 86, y2: 99), - ChartData(x: DateTime(1993, 6, 29), y1: 85, y2: 98), - ChartData(x: DateTime(1993, 8, 30), y1: 85, y2: 98), - ChartData(x: DateTime(1993, 9, 1), y1: 85, y2: 98), - ChartData(x: DateTime(1993, 10, 2), y1: 85, y2: 98), - ChartData(x: DateTime(1993, 11, 3), y1: 84, y2: 97), - ChartData(x: DateTime(1993, 12, 4), y1: 85, y2: 97), - ChartData(x: DateTime(1994, 1, 5), y1: 84, y2: 97), - ChartData(x: DateTime(1994, 2, 6), y1: 84, y2: 96), - ChartData(x: DateTime(1994, 3, 7), y1: 83, y2: 96), - ChartData(x: DateTime(1994, 4, 8), y1: 83, y2: 95), - ChartData(x: DateTime(1994, 5, 9), y1: 84, y2: 96), - ChartData(x: DateTime(1994, 6, 10), y1: 83, y2: 95), - ChartData(x: DateTime(1994, 7, 11), y1: 83, y2: 95), - ChartData(x: DateTime(1994, 8, 12), y1: 84, y2: 95), - ChartData(x: DateTime(1994, 9, 13), y1: 83, y2: 95), - ChartData(x: DateTime(1994, 10, 14), y1: 82, y2: 94), - ChartData(x: DateTime(1994, 11, 15), y1: 83, y2: 94), - ChartData(x: DateTime(1994, 12, 16), y1: 83, y2: 95), - ChartData(x: DateTime(1995, 1, 17), y1: 83, y2: 96), - ChartData(x: DateTime(1995, 2, 18), y1: 83, y2: 95), - ChartData(x: DateTime(1995, 3, 19), y1: 84, y2: 96), - ChartData(x: DateTime(1995, 4, 20), y1: 84, y2: 96), - ChartData(x: DateTime(1995, 5, 21), y1: 84, y2: 97), - ChartData(x: DateTime(1995, 6, 22), y1: 84, y2: 97), - ChartData(x: DateTime(1995, 7, 23), y1: 83, y2: 96), - ChartData(x: DateTime(1995, 8, 24), y1: 84, y2: 97), - ChartData(x: DateTime(1995, 9, 25), y1: 84, y2: 96), - ChartData(x: DateTime(1995, 10, 26), y1: 84, y2: 97), - ChartData(x: DateTime(1995, 11, 27), y1: 84, y2: 96), - ChartData(x: DateTime(1995, 12, 28), y1: 85, y2: 96), - ChartData(x: DateTime(1996, 1, 29), y1: 85, y2: 97), - ChartData(x: DateTime(1996, 3, 30), y1: 84, y2: 96), - ChartData(x: DateTime(1996, 4, 1), y1: 84, y2: 96), - ChartData(x: DateTime(1996, 5, 2), y1: 84, y2: 97), - ChartData(x: DateTime(1996, 6, 3), y1: 85, y2: 97), - ChartData(x: DateTime(1996, 7, 4), y1: 86, y2: 97), - ChartData(x: DateTime(1996, 8, 5), y1: 87, y2: 98), - ChartData(x: DateTime(1996, 9, 6), y1: 86, y2: 97), - ChartData(x: DateTime(1996, 10, 7), y1: 85, y2: 97), - ChartData(x: DateTime(1996, 11, 8), y1: 85, y2: 96), - ChartData(x: DateTime(1996, 12, 9), y1: 84, y2: 96), - ChartData(x: DateTime(1997, 1, 10), y1: 84, y2: 96), - ChartData(x: DateTime(1997, 2, 11), y1: 85, y2: 96), - ChartData(x: DateTime(1997, 3, 12), y1: 85, y2: 96), - ChartData(x: DateTime(1997, 4, 13), y1: 86, y2: 96), - ChartData(x: DateTime(1997, 5, 14), y1: 85, y2: 95), - ChartData(x: DateTime(1997, 6, 15), y1: 86, y2: 96), - ChartData(x: DateTime(1997, 7, 16), y1: 85, y2: 96), - ChartData(x: DateTime(1997, 8, 17), y1: 85, y2: 95), - ChartData(x: DateTime(1997, 9, 18), y1: 85, y2: 96), - ChartData(x: DateTime(1997, 10, 19), y1: 86, y2: 96), - ChartData(x: DateTime(1997, 11, 20), y1: 85, y2: 95), - ChartData(x: DateTime(1997, 12, 21), y1: 86, y2: 95), - ChartData(x: DateTime(1998, 1, 22), y1: 86, y2: 96), - ChartData(x: DateTime(1998, 2, 23), y1: 86, y2: 97), - ChartData(x: DateTime(1998, 3, 24), y1: 87, y2: 97), - ChartData(x: DateTime(1998, 4, 25), y1: 87, y2: 98), - ChartData(x: DateTime(1998, 5, 26), y1: 87, y2: 99), - ChartData(x: DateTime(1998, 6, 27), y1: 88, y2: 99), - ChartData(x: DateTime(1998, 7, 28), y1: 88, y2: 98), - ChartData(x: DateTime(1998, 8, 29), y1: 87, y2: 97), - ChartData(x: DateTime(1998, 10, 30), y1: 87, y2: 97), - ChartData(x: DateTime(1998, 11, 1), y1: 87, y2: 98), - ChartData(x: DateTime(1998, 12, 2), y1: 86, y2: 98), - ChartData(x: DateTime(1999, 1, 3), y1: 86, y2: 97), - ChartData(x: DateTime(1999, 2, 4), y1: 86, y2: 96), - ChartData(x: DateTime(1999, 3, 5), y1: 86, y2: 97), - ChartData(x: DateTime(1999, 4, 6), y1: 85, y2: 97), - ChartData(x: DateTime(1999, 5, 7), y1: 85, y2: 96), - ChartData(x: DateTime(1999, 6, 8), y1: 84, y2: 95), - ChartData(x: DateTime(1999, 7, 9), y1: 85, y2: 96), - ChartData(x: DateTime(1999, 8, 10), y1: 84, y2: 96), - ChartData(x: DateTime(1999, 9, 11), y1: 84, y2: 96), - ChartData(x: DateTime(1999, 10, 12), y1: 83, y2: 95), - ChartData(x: DateTime(1999, 11, 13), y1: 84, y2: 96), - ChartData(x: DateTime(1999, 12, 14), y1: 84, y2: 96), - ChartData(x: DateTime(2000, 1, 15), y1: 84, y2: 95), - ChartData(x: DateTime(2000, 2, 16), y1: 84, y2: 96), - ChartData(x: DateTime(2000, 3, 17), y1: 85, y2: 96), - ChartData(x: DateTime(2000, 4, 18), y1: 84, y2: 95), - ChartData(x: DateTime(2000, 5, 19), y1: 85, y2: 96), - ChartData(x: DateTime(2000, 6, 20), y1: 85, y2: 96), - ChartData(x: DateTime(2000, 7, 21), y1: 85, y2: 96), - ChartData(x: DateTime(2000, 8, 22), y1: 84, y2: 96), - ChartData(x: DateTime(2000, 9, 23), y1: 84, y2: 96), - ChartData(x: DateTime(2000, 10, 24), y1: 84, y2: 96), - ChartData(x: DateTime(2000, 11, 25), y1: 84, y2: 95), - ChartData(x: DateTime(2000, 12, 26), y1: 84, y2: 94), - ChartData(x: DateTime(2001, 1, 27), y1: 85, y2: 95), - ChartData(x: DateTime(2001, 2, 28), y1: 85, y2: 94), - ChartData(x: DateTime(2001, 3, 29), y1: 85, y2: 95), - ChartData(x: DateTime(2001, 5, 30), y1: 84, y2: 94), - ChartData(x: DateTime(2001, 6, 1), y1: 84, y2: 94), - ChartData(x: DateTime(2001, 7, 2), y1: 85, y2: 94), - ChartData(x: DateTime(2001, 8, 3), y1: 85, y2: 95), - ChartData(x: DateTime(2001, 9, 4), y1: 84, y2: 95), - ChartData(x: DateTime(2001, 10, 5), y1: 84, y2: 94), - ChartData(x: DateTime(2001, 11, 6), y1: 85, y2: 95), - ChartData(x: DateTime(2001, 12, 7), y1: 85, y2: 95), - ChartData(x: DateTime(2002, 1, 8), y1: 84, y2: 95), - ChartData(x: DateTime(2002, 2, 9), y1: 84, y2: 94), - ChartData(x: DateTime(2002, 3, 10), y1: 84, y2: 93), - ChartData(x: DateTime(2002, 4, 11), y1: 84, y2: 93), - ChartData(x: DateTime(2002, 5, 12), y1: 84, y2: 92), - ChartData(x: DateTime(2002, 6, 13), y1: 84, y2: 92), - ChartData(x: DateTime(2002, 7, 14), y1: 84, y2: 92), - ChartData(x: DateTime(2002, 8, 15), y1: 83, y2: 91), - ChartData(x: DateTime(2002, 9, 16), y1: 83, y2: 92), - ChartData(x: DateTime(2002, 10, 17), y1: 84, y2: 93), - ChartData(x: DateTime(2002, 11, 18), y1: 84, y2: 93), - ChartData(x: DateTime(2002, 12, 19), y1: 83, y2: 92), + List> _getDefaultLineSeries() { + final List<_ChartData> chartData = <_ChartData>[ + _ChartData(x: DateTime(1980, 1, 23), y1: 83, y2: 94), + _ChartData(x: DateTime(1980, 2, 24), y1: 83, y2: 93), + _ChartData(x: DateTime(1980, 3, 25), y1: 82, y2: 93), + _ChartData(x: DateTime(1980, 4, 26), y1: 83, y2: 93), + _ChartData(x: DateTime(1980, 5, 27), y1: 83, y2: 93), + _ChartData(x: DateTime(1980, 6, 28), y1: 84, y2: 94), + _ChartData(x: DateTime(1980, 7, 29), y1: 84, y2: 94), + _ChartData(x: DateTime(1980, 9, 30), y1: 85, y2: 95), + _ChartData(x: DateTime(1980, 10, 1), y1: 84, y2: 94), + _ChartData(x: DateTime(1980, 11, 2), y1: 83, y2: 93), + _ChartData(x: DateTime(1980, 12, 3), y1: 83, y2: 94), + _ChartData(x: DateTime(1981, 1, 4), y1: 83, y2: 94), + _ChartData(x: DateTime(1981, 2, 5), y1: 82, y2: 93), + _ChartData(x: DateTime(1981, 3, 6), y1: 82, y2: 93), + _ChartData(x: DateTime(1981, 4, 7), y1: 82, y2: 94), + _ChartData(x: DateTime(1981, 5, 8), y1: 83, y2: 94), + _ChartData(x: DateTime(1981, 6, 9), y1: 83, y2: 94), + _ChartData(x: DateTime(1981, 7, 10), y1: 83, y2: 94), + _ChartData(x: DateTime(1981, 8, 11), y1: 83, y2: 95), + _ChartData(x: DateTime(1981, 9, 12), y1: 84, y2: 95), + _ChartData(x: DateTime(1981, 10, 13), y1: 83, y2: 95), + _ChartData(x: DateTime(1981, 11, 14), y1: 84, y2: 96), + _ChartData(x: DateTime(1981, 12, 15), y1: 83, y2: 96), + _ChartData(x: DateTime(1982, 1, 16), y1: 84, y2: 97), + _ChartData(x: DateTime(1982, 2, 17), y1: 84, y2: 96), + _ChartData(x: DateTime(1982, 3, 18), y1: 84, y2: 96), + _ChartData(x: DateTime(1982, 4, 19), y1: 84, y2: 96), + _ChartData(x: DateTime(1982, 5, 20), y1: 84, y2: 96), + _ChartData(x: DateTime(1982, 6, 21), y1: 83, y2: 95), + _ChartData(x: DateTime(1982, 7, 22), y1: 84, y2: 96), + _ChartData(x: DateTime(1982, 8, 23), y1: 83, y2: 95), + _ChartData(x: DateTime(1982, 9, 24), y1: 83, y2: 94), + _ChartData(x: DateTime(1982, 10, 25), y1: 83, y2: 95), + _ChartData(x: DateTime(1982, 11, 26), y1: 83, y2: 94), + _ChartData(x: DateTime(1982, 12, 27), y1: 84, y2: 94), + _ChartData(x: DateTime(1983, 1, 28), y1: 85, y2: 95), + _ChartData(x: DateTime(1983, 2, 29), y1: 84, y2: 95), + _ChartData(x: DateTime(1983, 4, 30), y1: 84, y2: 95), + _ChartData(x: DateTime(1983, 5, 1), y1: 83, y2: 95), + _ChartData(x: DateTime(1983, 6, 2), y1: 84, y2: 95), + _ChartData(x: DateTime(1983, 7, 3), y1: 85, y2: 95), + _ChartData(x: DateTime(1983, 8, 4), y1: 86, y2: 95), + _ChartData(x: DateTime(1983, 9, 5), y1: 86, y2: 96), + _ChartData(x: DateTime(1983, 10, 6), y1: 87, y2: 97), + _ChartData(x: DateTime(1983, 11, 7), y1: 87, y2: 98), + _ChartData(x: DateTime(1983, 12, 8), y1: 87, y2: 99), + _ChartData(x: DateTime(1984, 1, 9), y1: 86, y2: 98), + _ChartData(x: DateTime(1984, 2, 10), y1: 86, y2: 98), + _ChartData(x: DateTime(1984, 3, 11), y1: 86, y2: 97), + _ChartData(x: DateTime(1984, 4, 12), y1: 86, y2: 96), + _ChartData(x: DateTime(1984, 5, 13), y1: 86, y2: 97), + _ChartData(x: DateTime(1984, 6, 14), y1: 85, y2: 97), + _ChartData(x: DateTime(1984, 7, 15), y1: 85, y2: 96), + _ChartData(x: DateTime(1984, 8, 16), y1: 84, y2: 96), + _ChartData(x: DateTime(1984, 9, 17), y1: 84, y2: 96), + _ChartData(x: DateTime(1984, 10, 18), y1: 84, y2: 97), + _ChartData(x: DateTime(1984, 11, 19), y1: 85, y2: 98), + _ChartData(x: DateTime(1984, 12, 20), y1: 85, y2: 98), + _ChartData(x: DateTime(1985, 1, 21), y1: 85, y2: 97), + _ChartData(x: DateTime(1985, 2, 22), y1: 85, y2: 98), + _ChartData(x: DateTime(1985, 3, 23), y1: 86, y2: 99), + _ChartData(x: DateTime(1985, 4, 24), y1: 85, y2: 98), + _ChartData(x: DateTime(1985, 5, 25), y1: 85, y2: 97), + _ChartData(x: DateTime(1985, 6, 26), y1: 86, y2: 97), + _ChartData(x: DateTime(1985, 7, 27), y1: 86, y2: 98), + _ChartData(x: DateTime(1985, 8, 28), y1: 86, y2: 97), + _ChartData(x: DateTime(1985, 9, 29), y1: 86, y2: 96), + _ChartData(x: DateTime(1985, 11, 30), y1: 86, y2: 97), + _ChartData(x: DateTime(1985, 12, 1), y1: 86, y2: 98), + _ChartData(x: DateTime(1986, 1, 2), y1: 87, y2: 98), + _ChartData(x: DateTime(1986, 2, 3), y1: 87, y2: 98), + _ChartData(x: DateTime(1986, 3, 4), y1: 87, y2: 98), + _ChartData(x: DateTime(1986, 4, 5), y1: 88, y2: 99), + _ChartData(x: DateTime(1986, 5, 6), y1: 88, y2: 98), + _ChartData(x: DateTime(1986, 6, 7), y1: 87, y2: 97), + _ChartData(x: DateTime(1986, 7, 8), y1: 88, y2: 98), + _ChartData(x: DateTime(1986, 8, 9), y1: 88, y2: 98), + _ChartData(x: DateTime(1986, 9, 10), y1: 88, y2: 98), + _ChartData(x: DateTime(1986, 10, 11), y1: 88, y2: 97), + _ChartData(x: DateTime(1986, 11, 12), y1: 88, y2: 98), + _ChartData(x: DateTime(1986, 12, 13), y1: 89, y2: 99), + _ChartData(x: DateTime(1987, 1, 14), y1: 88, y2: 98), + _ChartData(x: DateTime(1987, 2, 15), y1: 89, y2: 98), + _ChartData(x: DateTime(1987, 3, 16), y1: 88, y2: 98), + _ChartData(x: DateTime(1987, 4, 17), y1: 87, y2: 97), + _ChartData(x: DateTime(1987, 5, 18), y1: 87, y2: 98), + _ChartData(x: DateTime(1987, 6, 19), y1: 87, y2: 97), + _ChartData(x: DateTime(1987, 7, 20), y1: 87, y2: 96), + _ChartData(x: DateTime(1987, 8, 21), y1: 87, y2: 95), + _ChartData(x: DateTime(1987, 9, 22), y1: 87, y2: 95), + _ChartData(x: DateTime(1987, 10, 23), y1: 86, y2: 94), + _ChartData(x: DateTime(1987, 11, 24), y1: 85, y2: 94), + _ChartData(x: DateTime(1987, 12, 25), y1: 86, y2: 95), + _ChartData(x: DateTime(1988, 1, 26), y1: 85, y2: 94), + _ChartData(x: DateTime(1988, 2, 27), y1: 86, y2: 95), + _ChartData(x: DateTime(1988, 3, 28), y1: 85, y2: 95), + _ChartData(x: DateTime(1988, 4, 29), y1: 85, y2: 95), + _ChartData(x: DateTime(1988, 6, 30), y1: 85, y2: 95), + _ChartData(x: DateTime(1988, 7, 1), y1: 86, y2: 96), + _ChartData(x: DateTime(1988, 8, 2), y1: 85, y2: 96), + _ChartData(x: DateTime(1988, 9, 3), y1: 84, y2: 95), + _ChartData(x: DateTime(1988, 10, 4), y1: 85, y2: 96), + _ChartData(x: DateTime(1988, 11, 5), y1: 85, y2: 96), + _ChartData(x: DateTime(1988, 12, 6), y1: 85, y2: 96), + _ChartData(x: DateTime(1989, 1, 7), y1: 86, y2: 97), + _ChartData(x: DateTime(1989, 2, 8), y1: 86, y2: 97), + _ChartData(x: DateTime(1989, 3, 9), y1: 85, y2: 96), + _ChartData(x: DateTime(1989, 4, 10), y1: 84, y2: 95), + _ChartData(x: DateTime(1989, 5, 11), y1: 85, y2: 96), + _ChartData(x: DateTime(1989, 6, 12), y1: 84, y2: 95), + _ChartData(x: DateTime(1989, 7, 13), y1: 84, y2: 94), + _ChartData(x: DateTime(1989, 8, 14), y1: 85, y2: 95), + _ChartData(x: DateTime(1989, 9, 15), y1: 84, y2: 94), + _ChartData(x: DateTime(1989, 10, 16), y1: 84, y2: 95), + _ChartData(x: DateTime(1989, 11, 17), y1: 84, y2: 95), + _ChartData(x: DateTime(1989, 12, 18), y1: 84, y2: 95), + _ChartData(x: DateTime(1990, 1, 19), y1: 83, y2: 95), + _ChartData(x: DateTime(1990, 2, 20), y1: 84, y2: 95), + _ChartData(x: DateTime(1990, 3, 21), y1: 85, y2: 96), + _ChartData(x: DateTime(1990, 4, 22), y1: 84, y2: 95), + _ChartData(x: DateTime(1990, 5, 23), y1: 83, y2: 94), + _ChartData(x: DateTime(1990, 6, 24), y1: 84, y2: 95), + _ChartData(x: DateTime(1990, 7, 25), y1: 84, y2: 96), + _ChartData(x: DateTime(1990, 8, 26), y1: 84, y2: 96), + _ChartData(x: DateTime(1990, 9, 27), y1: 84, y2: 95), + _ChartData(x: DateTime(1990, 10, 28), y1: 83, y2: 94), + _ChartData(x: DateTime(1990, 11, 29), y1: 84, y2: 94), + _ChartData(x: DateTime(1991, 1, 30), y1: 84, y2: 95), + _ChartData(x: DateTime(1991, 2, 1), y1: 84, y2: 95), + _ChartData(x: DateTime(1991, 3, 2), y1: 83, y2: 94), + _ChartData(x: DateTime(1991, 4, 3), y1: 84, y2: 95), + _ChartData(x: DateTime(1991, 5, 4), y1: 85, y2: 96), + _ChartData(x: DateTime(1991, 6, 5), y1: 84, y2: 96), + _ChartData(x: DateTime(1991, 7, 6), y1: 84, y2: 95), + _ChartData(x: DateTime(1991, 8, 7), y1: 84, y2: 96), + _ChartData(x: DateTime(1991, 9, 8), y1: 84, y2: 96), + _ChartData(x: DateTime(1991, 10, 9), y1: 84, y2: 96), + _ChartData(x: DateTime(1991, 11, 10), y1: 84, y2: 96), + _ChartData(x: DateTime(1991, 12, 11), y1: 84, y2: 97), + _ChartData(x: DateTime(1992, 1, 12), y1: 85, y2: 97), + _ChartData(x: DateTime(1992, 2, 13), y1: 86, y2: 98), + _ChartData(x: DateTime(1992, 3, 14), y1: 86, y2: 99), + _ChartData(x: DateTime(1992, 4, 15), y1: 86, y2: 98), + _ChartData(x: DateTime(1992, 5, 16), y1: 86, y2: 98), + _ChartData(x: DateTime(1992, 6, 17), y1: 85, y2: 98), + _ChartData(x: DateTime(1992, 7, 18), y1: 85, y2: 98), + _ChartData(x: DateTime(1992, 8, 19), y1: 86, y2: 98), + _ChartData(x: DateTime(1992, 9, 20), y1: 87, y2: 98), + _ChartData(x: DateTime(1992, 10, 21), y1: 88, y2: 99), + _ChartData(x: DateTime(1992, 11, 22), y1: 87, y2: 98), + _ChartData(x: DateTime(1992, 12, 23), y1: 87, y2: 98), + _ChartData(x: DateTime(1993, 1, 24), y1: 87, y2: 99), + _ChartData(x: DateTime(1993, 2, 25), y1: 88, y2: 100), + _ChartData(x: DateTime(1993, 3, 26), y1: 87, y2: 99), + _ChartData(x: DateTime(1993, 4, 27), y1: 86, y2: 99), + _ChartData(x: DateTime(1993, 5, 28), y1: 86, y2: 99), + _ChartData(x: DateTime(1993, 6, 29), y1: 85, y2: 98), + _ChartData(x: DateTime(1993, 8, 30), y1: 85, y2: 98), + _ChartData(x: DateTime(1993, 9, 1), y1: 85, y2: 98), + _ChartData(x: DateTime(1993, 10, 2), y1: 85, y2: 98), + _ChartData(x: DateTime(1993, 11, 3), y1: 84, y2: 97), + _ChartData(x: DateTime(1993, 12, 4), y1: 85, y2: 97), + _ChartData(x: DateTime(1994, 1, 5), y1: 84, y2: 97), + _ChartData(x: DateTime(1994, 2, 6), y1: 84, y2: 96), + _ChartData(x: DateTime(1994, 3, 7), y1: 83, y2: 96), + _ChartData(x: DateTime(1994, 4, 8), y1: 83, y2: 95), + _ChartData(x: DateTime(1994, 5, 9), y1: 84, y2: 96), + _ChartData(x: DateTime(1994, 6, 10), y1: 83, y2: 95), + _ChartData(x: DateTime(1994, 7, 11), y1: 83, y2: 95), + _ChartData(x: DateTime(1994, 8, 12), y1: 84, y2: 95), + _ChartData(x: DateTime(1994, 9, 13), y1: 83, y2: 95), + _ChartData(x: DateTime(1994, 10, 14), y1: 82, y2: 94), + _ChartData(x: DateTime(1994, 11, 15), y1: 83, y2: 94), + _ChartData(x: DateTime(1994, 12, 16), y1: 83, y2: 95), + _ChartData(x: DateTime(1995, 1, 17), y1: 83, y2: 96), + _ChartData(x: DateTime(1995, 2, 18), y1: 83, y2: 95), + _ChartData(x: DateTime(1995, 3, 19), y1: 84, y2: 96), + _ChartData(x: DateTime(1995, 4, 20), y1: 84, y2: 96), + _ChartData(x: DateTime(1995, 5, 21), y1: 84, y2: 97), + _ChartData(x: DateTime(1995, 6, 22), y1: 84, y2: 97), + _ChartData(x: DateTime(1995, 7, 23), y1: 83, y2: 96), + _ChartData(x: DateTime(1995, 8, 24), y1: 84, y2: 97), + _ChartData(x: DateTime(1995, 9, 25), y1: 84, y2: 96), + _ChartData(x: DateTime(1995, 10, 26), y1: 84, y2: 97), + _ChartData(x: DateTime(1995, 11, 27), y1: 84, y2: 96), + _ChartData(x: DateTime(1995, 12, 28), y1: 85, y2: 96), + _ChartData(x: DateTime(1996, 1, 29), y1: 85, y2: 97), + _ChartData(x: DateTime(1996, 3, 30), y1: 84, y2: 96), + _ChartData(x: DateTime(1996, 4, 1), y1: 84, y2: 96), + _ChartData(x: DateTime(1996, 5, 2), y1: 84, y2: 97), + _ChartData(x: DateTime(1996, 6, 3), y1: 85, y2: 97), + _ChartData(x: DateTime(1996, 7, 4), y1: 86, y2: 97), + _ChartData(x: DateTime(1996, 8, 5), y1: 87, y2: 98), + _ChartData(x: DateTime(1996, 9, 6), y1: 86, y2: 97), + _ChartData(x: DateTime(1996, 10, 7), y1: 85, y2: 97), + _ChartData(x: DateTime(1996, 11, 8), y1: 85, y2: 96), + _ChartData(x: DateTime(1996, 12, 9), y1: 84, y2: 96), + _ChartData(x: DateTime(1997, 1, 10), y1: 84, y2: 96), + _ChartData(x: DateTime(1997, 2, 11), y1: 85, y2: 96), + _ChartData(x: DateTime(1997, 3, 12), y1: 85, y2: 96), + _ChartData(x: DateTime(1997, 4, 13), y1: 86, y2: 96), + _ChartData(x: DateTime(1997, 5, 14), y1: 85, y2: 95), + _ChartData(x: DateTime(1997, 6, 15), y1: 86, y2: 96), + _ChartData(x: DateTime(1997, 7, 16), y1: 85, y2: 96), + _ChartData(x: DateTime(1997, 8, 17), y1: 85, y2: 95), + _ChartData(x: DateTime(1997, 9, 18), y1: 85, y2: 96), + _ChartData(x: DateTime(1997, 10, 19), y1: 86, y2: 96), + _ChartData(x: DateTime(1997, 11, 20), y1: 85, y2: 95), + _ChartData(x: DateTime(1997, 12, 21), y1: 86, y2: 95), + _ChartData(x: DateTime(1998, 1, 22), y1: 86, y2: 96), + _ChartData(x: DateTime(1998, 2, 23), y1: 86, y2: 97), + _ChartData(x: DateTime(1998, 3, 24), y1: 87, y2: 97), + _ChartData(x: DateTime(1998, 4, 25), y1: 87, y2: 98), + _ChartData(x: DateTime(1998, 5, 26), y1: 87, y2: 99), + _ChartData(x: DateTime(1998, 6, 27), y1: 88, y2: 99), + _ChartData(x: DateTime(1998, 7, 28), y1: 88, y2: 98), + _ChartData(x: DateTime(1998, 8, 29), y1: 87, y2: 97), + _ChartData(x: DateTime(1998, 10, 30), y1: 87, y2: 97), + _ChartData(x: DateTime(1998, 11, 1), y1: 87, y2: 98), + _ChartData(x: DateTime(1998, 12, 2), y1: 86, y2: 98), + _ChartData(x: DateTime(1999, 1, 3), y1: 86, y2: 97), + _ChartData(x: DateTime(1999, 2, 4), y1: 86, y2: 96), + _ChartData(x: DateTime(1999, 3, 5), y1: 86, y2: 97), + _ChartData(x: DateTime(1999, 4, 6), y1: 85, y2: 97), + _ChartData(x: DateTime(1999, 5, 7), y1: 85, y2: 96), + _ChartData(x: DateTime(1999, 6, 8), y1: 84, y2: 95), + _ChartData(x: DateTime(1999, 7, 9), y1: 85, y2: 96), + _ChartData(x: DateTime(1999, 8, 10), y1: 84, y2: 96), + _ChartData(x: DateTime(1999, 9, 11), y1: 84, y2: 96), + _ChartData(x: DateTime(1999, 10, 12), y1: 83, y2: 95), + _ChartData(x: DateTime(1999, 11, 13), y1: 84, y2: 96), + _ChartData(x: DateTime(1999, 12, 14), y1: 84, y2: 96), + _ChartData(x: DateTime(2000, 1, 15), y1: 84, y2: 95), + _ChartData(x: DateTime(2000, 2, 16), y1: 84, y2: 96), + _ChartData(x: DateTime(2000, 3, 17), y1: 85, y2: 96), + _ChartData(x: DateTime(2000, 4, 18), y1: 84, y2: 95), + _ChartData(x: DateTime(2000, 5, 19), y1: 85, y2: 96), + _ChartData(x: DateTime(2000, 6, 20), y1: 85, y2: 96), + _ChartData(x: DateTime(2000, 7, 21), y1: 85, y2: 96), + _ChartData(x: DateTime(2000, 8, 22), y1: 84, y2: 96), + _ChartData(x: DateTime(2000, 9, 23), y1: 84, y2: 96), + _ChartData(x: DateTime(2000, 10, 24), y1: 84, y2: 96), + _ChartData(x: DateTime(2000, 11, 25), y1: 84, y2: 95), + _ChartData(x: DateTime(2000, 12, 26), y1: 84, y2: 94), + _ChartData(x: DateTime(2001, 1, 27), y1: 85, y2: 95), + _ChartData(x: DateTime(2001, 2, 28), y1: 85, y2: 94), + _ChartData(x: DateTime(2001, 3, 29), y1: 85, y2: 95), + _ChartData(x: DateTime(2001, 5, 30), y1: 84, y2: 94), + _ChartData(x: DateTime(2001, 6, 1), y1: 84, y2: 94), + _ChartData(x: DateTime(2001, 7, 2), y1: 85, y2: 94), + _ChartData(x: DateTime(2001, 8, 3), y1: 85, y2: 95), + _ChartData(x: DateTime(2001, 9, 4), y1: 84, y2: 95), + _ChartData(x: DateTime(2001, 10, 5), y1: 84, y2: 94), + _ChartData(x: DateTime(2001, 11, 6), y1: 85, y2: 95), + _ChartData(x: DateTime(2001, 12, 7), y1: 85, y2: 95), + _ChartData(x: DateTime(2002, 1, 8), y1: 84, y2: 95), + _ChartData(x: DateTime(2002, 2, 9), y1: 84, y2: 94), + _ChartData(x: DateTime(2002, 3, 10), y1: 84, y2: 93), + _ChartData(x: DateTime(2002, 4, 11), y1: 84, y2: 93), + _ChartData(x: DateTime(2002, 5, 12), y1: 84, y2: 92), + _ChartData(x: DateTime(2002, 6, 13), y1: 84, y2: 92), + _ChartData(x: DateTime(2002, 7, 14), y1: 84, y2: 92), + _ChartData(x: DateTime(2002, 8, 15), y1: 83, y2: 91), + _ChartData(x: DateTime(2002, 9, 16), y1: 83, y2: 92), + _ChartData(x: DateTime(2002, 10, 17), y1: 84, y2: 93), + _ChartData(x: DateTime(2002, 11, 18), y1: 84, y2: 93), + _ChartData(x: DateTime(2002, 12, 19), y1: 83, y2: 92), ]; - return >[ - LineSeries( + return >[ + LineSeries<_ChartData, DateTime>( dataSource: chartData, - xValueMapper: (ChartData sales, _) => sales.x, - yValueMapper: (ChartData sales, _) => sales.y1, + xValueMapper: (_ChartData sales, _) => sales.x, + yValueMapper: (_ChartData sales, _) => sales.y1, name: 'Product A'), - LineSeries( + LineSeries<_ChartData, DateTime>( dataSource: chartData, name: 'Product B', - xValueMapper: (ChartData sales, _) => sales.x, - yValueMapper: (ChartData sales, _) => sales.y2) + xValueMapper: (_ChartData sales, _) => sales.x, + yValueMapper: (_ChartData sales, _) => sales.y2) ]; } } -class ChartData { - ChartData({this.x, this.y1, this.y2}); - DateTime x; - num y1; - num y2; +class _ChartData { + _ChartData({this.x, this.y1, this.y2}); + DateTime? x; + num? y1; + num? y2; } diff --git a/lib/samples/chart/cartesian_charts/export.dart b/lib/samples/chart/cartesian_charts/export.dart index ba156ee6..fea09886 100644 --- a/lib/samples/chart/cartesian_charts/export.dart +++ b/lib/samples/chart/cartesian_charts/export.dart @@ -38,7 +38,7 @@ class _ExportState extends SampleViewState { return Scaffold( key: scaffoldKey, body: Column(children: [ - Expanded(child: _getDefaultColumnChart()), + Expanded(child: _buildDefaultColumnChart()), Container( padding: EdgeInsets.only(bottom: 10), child: Row( @@ -55,14 +55,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 100), content: - Text("Chart has been exported as PNG image"), + Text('Chart has been exported as PNG image'), )); _renderImage(); }, @@ -80,14 +80,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, duration: Duration(milliseconds: 2000), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), content: - Text("Chart is being exported as PDF document"), + Text('Chart is being exported as PDF document'), )); _renderPdf(); }, @@ -99,7 +99,7 @@ class _ExportState extends SampleViewState { } /// Get default column chart - SfCartesianChart _getDefaultColumnChart() { + SfCartesianChart _buildDefaultColumnChart() { return SfCartesianChart( legend: Legend(isVisible: true), key: _chartKey, @@ -116,12 +116,10 @@ class _ExportState extends SampleViewState { minimum: 0, maximum: 250, interval: 50, - // title: AxisTitle(text: 'Average rainfall in mm') ), axes: [ NumericAxis( name: 'YAxis', - // title: AxisTitle(text: 'Rainy days'), opposedPosition: true, majorGridLines: MajorGridLines(width: 0), minimum: 0, @@ -166,8 +164,8 @@ class _ExportState extends SampleViewState { await getApplicationDocumentsDirectory(); final String path = documentDirectory.path; final String imageName = 'cartesianchart.png'; - imageCache.clear(); - File file = new File('$path/$imageName'); + imageCache!.clear(); + final File file = File('$path/$imageName'); file.writeAsBytesSync(bytes); await Navigator.of(context).push( @@ -203,13 +201,13 @@ class _ExportState extends SampleViewState { page.graphics.drawImage( bitmap, Rect.fromLTWH(0, 0, pageSize.width, pageSize.height)); - scaffoldKey.currentState.hideCurrentSnackBar(); - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 200), - content: Text("Chart has been exported as PDF document."), + content: Text('Chart has been exported as PDF document.'), )); final List bytes = document.save(); document.dispose(); @@ -217,8 +215,9 @@ class _ExportState extends SampleViewState { } Future> _readImageData() async { - dart_ui.Image data = await _chartKey.currentState.toImage(pixelRatio: 3.0); + final dart_ui.Image data = + await _chartKey.currentState!.toImage(pixelRatio: 3.0); final bytes = await data.toByteData(format: dart_ui.ImageByteFormat.png); - return bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); + return bytes!.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); } } diff --git a/lib/samples/chart/cartesian_charts/legend/chart_with_customized_legend.dart b/lib/samples/chart/cartesian_charts/legend/chart_with_customized_legend.dart index 9be61b60..1ed0eb54 100644 --- a/lib/samples/chart/cartesian_charts/legend/chart_with_customized_legend.dart +++ b/lib/samples/chart/cartesian_charts/legend/chart_with_customized_legend.dart @@ -22,11 +22,11 @@ class _LegendCustomizedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLegendCustomizedChart(); + return _buildLegendCustomizedChart(); } /// Returns the line chart with customized legends. - SfCartesianChart _getLegendCustomizedChart() { + SfCartesianChart _buildLegendCustomizedChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( diff --git a/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart b/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart index 50640166..18c484b4 100644 --- a/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart +++ b/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart @@ -20,14 +20,14 @@ class CartesianLegendOptions extends SampleView { class _CartesianLegendOptionsState extends SampleViewState { _CartesianLegendOptionsState(); - bool toggleVisibility; + late bool toggleVisibility; final List _positionList = ['auto', 'bottom', 'left', 'right', 'top'].toList(); - String _selectedPosition; - LegendPosition _position; + late String _selectedPosition; + late LegendPosition _position; final List _modeList = ['wrap', 'scroll', 'none'].toList(); - String _selectedMode; - LegendItemOverflowMode _overflowMode; + late String _selectedMode; + late LegendItemOverflowMode _overflowMode; @override void initState() { @@ -41,94 +41,85 @@ class _CartesianLegendOptionsState extends SampleViewState { @override Widget build(BuildContext context) { - return _getCartesianLegendOptionsChart(); + return _buildCartesianLegendOptionsChart(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - children: [ - Text('Position ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(75, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: - Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _positionList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'auto', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onPositionTypeChange(value.toString()); - stateSetter(() {}); - })), - ], - ), + ListTile( + title: Text('Position ', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _positionList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'auto', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onPositionTypeChange(value.toString()); + stateSetter(() {}); + })), ), - Container( - child: Row( - children: [ - Text('Overflow mode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(30, 0, 0, 0), - height: 50, - child: DropdownButton( - underline: - Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'wrap', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onModeTypeChange(value); - stateSetter(() {}); - })), - ], - ), + ListTile( + title: Text('Overflow mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'wrap', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onModeTypeChange(value); + stateSetter(() {}); + })), ), - Container( - child: Row( - children: [ - Text('Toggle visibility', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - width: 75, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: toggleVisibility, - onChanged: (bool value) { - setState(() { - toggleVisibility = value; - stateSetter(() {}); - }); - })), - ], - ), + ListTile( + title: Text('Toggle visibility', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.4 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: toggleVisibility, + onChanged: (bool? value) { + setState(() { + toggleVisibility = value!; + stateSetter(() {}); + }); + })), ), ], ); @@ -136,7 +127,7 @@ class _CartesianLegendOptionsState extends SampleViewState { } /// Returns the stacked line chart with various legedn modification options. - SfCartesianChart _getCartesianLegendOptionsChart() { + SfCartesianChart _buildCartesianLegendOptionsChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Monthly expense of a family'), diff --git a/lib/samples/chart/cartesian_charts/on_demand_loading/infinite_scrolling.dart b/lib/samples/chart/cartesian_charts/on_demand_loading/infinite_scrolling.dart new file mode 100644 index 00000000..1efd1228 --- /dev/null +++ b/lib/samples/chart/cartesian_charts/on_demand_loading/infinite_scrolling.dart @@ -0,0 +1,214 @@ +/// dart import +import 'dart:math'; + +/// Package import +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../model/sample_view.dart'; + +/// Renders the chart with default trackball sample. +class InfiniteScrolling extends SampleView { + /// Creates the chart with default trackball sample. + const InfiniteScrolling(Key key) : super(key: key); + + @override + _InfiniteScrollingState createState() => _InfiniteScrollingState(); +} + +/// State class the chart with default trackball. +class _InfiniteScrollingState extends SampleViewState { + _InfiniteScrollingState(); + + ChartSeriesController? seriesController; + late List chartData; + + late bool isLoadMoreView, isNeedToUpdateView, isDataUpdated; + + double? oldAxisVisibleMin, oldAxisVisibleMax; + + late ZoomPanBehavior _zoomPanBehavior; + + late GlobalKey globalKey; + @override + void initState() { + _initializeVariables(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return _buildInfiniteScrollingChart(); + } + + void _initializeVariables() { + chartData = [ + ChartSampleData(xValue: 0, y: 326), + ChartSampleData(xValue: 1, y: 416), + ChartSampleData(xValue: 2, y: 290), + ChartSampleData(xValue: 3, y: 70), + ChartSampleData(xValue: 4, y: 500), + ChartSampleData(xValue: 5, y: 416), + ChartSampleData(xValue: 6, y: 290), + ChartSampleData(xValue: 7, y: 120), + ChartSampleData(xValue: 8, y: 500), + ]; + isLoadMoreView = false; + isNeedToUpdateView = false; + isDataUpdated = true; + globalKey = GlobalKey(); + _zoomPanBehavior = ZoomPanBehavior( + enablePanning: true, + ); + } + + /// Returns the cartesian chart with default trackball. + SfCartesianChart _buildInfiniteScrollingChart() { + return SfCartesianChart( + key: GlobalKey(), + onActualRangeChanged: (ActualRangeChangedArgs args) { + if (args.orientation == AxisOrientation.horizontal) { + if (isLoadMoreView) { + args.visibleMin = oldAxisVisibleMin; + args.visibleMax = oldAxisVisibleMax; + } + oldAxisVisibleMin = args.visibleMin; + oldAxisVisibleMax = args.visibleMax; + } + isLoadMoreView = false; + }, + zoomPanBehavior: _zoomPanBehavior, + plotAreaBorderWidth: 0, + primaryXAxis: NumericAxis( + name: 'XAxis', + interval: 2, + enableAutoIntervalOnZooming: false, + edgeLabelPlacement: EdgeLabelPlacement.shift, + majorGridLines: MajorGridLines(width: 0)), + primaryYAxis: NumericAxis( + axisLine: AxisLine(width: 0), + majorTickLines: MajorTickLines(color: Colors.transparent)), + series: getSeries(), + axisLabelFormatter: (AxisLabelRenderDetails details) { + return ChartAxisLabel( + details.axisName == 'XAxis' + ? details.text.split('.')[0] + : details.text, + null); + }, + loadMoreIndicatorBuilder: + (BuildContext context, ChartSwipeDirection direction) => + getloadMoreIndicatorBuilder(context, direction), + ); + } + + List> getSeries() { + return >[ + SplineAreaSeries( + dataSource: chartData, + color: const Color.fromRGBO(75, 135, 185, 0.6), + borderColor: const Color.fromRGBO(75, 135, 185, 1), + borderWidth: 2, + xValueMapper: (ChartSampleData sales, _) => sales.xValue, + yValueMapper: (ChartSampleData sales, _) => sales.y, + onRendererCreated: (ChartSeriesController controller) { + seriesController = controller; + }, + ), + ]; + } + + Widget getloadMoreIndicatorBuilder( + BuildContext context, ChartSwipeDirection direction) { + if (direction == ChartSwipeDirection.end) { + isNeedToUpdateView = true; + globalKey = GlobalKey(); + return StatefulBuilder( + key: globalKey, + builder: (BuildContext context, StateSetter stateSetter) { + Widget widget; + if (isNeedToUpdateView) { + widget = getProgressIndicator(); + _updateView(); + isDataUpdated = true; + } else { + widget = Container(); + } + return widget; + }); + } else { + return SizedBox.fromSize(size: Size.zero); + } + } + + Widget getProgressIndicator() { + return Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.only(bottom: 22), + child: Container( + width: 50, + alignment: Alignment.centerRight, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: model.themeData.brightness == Brightness.light + ? [ + Colors.white.withOpacity(0.0), + Colors.white.withOpacity(0.74) + ] + : [ + Color.fromRGBO(33, 33, 33, 0.0), + Color.fromRGBO(33, 33, 33, 0.74) + ], + stops: [0.0, 1]), + ), + child: SizedBox( + height: 35, + width: 35, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(model.backgroundColor), + backgroundColor: Colors.transparent, + strokeWidth: 3, + ))))); + } + + void _updateData() { + for (int i = 0; i < 4; i++) { + chartData.add(ChartSampleData( + xValue: chartData[chartData.length - 1].xValue + 1, + y: getRandomInt(0, 600))); + } + isLoadMoreView = true; + seriesController?.updateDataSource(addedDataIndexes: getIndexes(4)); + } + + Future _updateView() async { + await Future.delayed(const Duration(seconds: 1), () { + isNeedToUpdateView = false; + if (isDataUpdated) { + _updateData(); + isDataUpdated = false; + } + if (globalKey.currentState != null) { + (globalKey.currentState as dynamic).setState(() {}); + } + }); + } + + List getIndexes(int length) { + final List indexes = []; + for (int i = length - 1; i >= 0; i--) { + indexes.add(chartData.length - 1 - i); + } + return indexes; + } + + int getRandomInt(int min, int max) { + final Random random = Random(); + final int result = min + random.nextInt(max - min); + return result < 50 ? 95 : result; + } +} diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart index ccccde63..5dc596e5 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart @@ -26,7 +26,7 @@ class _LiveVerticalState extends SampleViewState { chartData.removeRange(10, chartData.length - 1); } } - ChartSeriesController _chartSeriesController; + ChartSeriesController? _chartSeriesController; /// List for storing the chart series data points. List chartData = [ @@ -45,7 +45,7 @@ class _LiveVerticalState extends SampleViewState { int count = 11; /// Get the random value - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random random = Random(); return min + random.nextInt(max - min); } @@ -73,7 +73,7 @@ class _LiveVerticalState extends SampleViewState { backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, 0, 5, bottomPadding), - child: Container(child: _getAddRemovePointsChart()), + child: Container(child: _buildAddRemovePointsChart()), ), floatingActionButton: Stack( children: [ @@ -83,8 +83,8 @@ class _LiveVerticalState extends SampleViewState { padding: const EdgeInsets.fromLTRB(30, 50, 0, 0), child: Container( height: isCardView ? 40 : 45, - width: model.isWeb - ? 135 + width: model.isWebFullView + ? 140 : isCardView ? 100 : 110, @@ -92,12 +92,12 @@ class _LiveVerticalState extends SampleViewState { splashColor: Colors.transparent, child: Row(children: [ SizedBox( - width: model.isWeb ? 65 : 45, + width: model.isWebFullView ? 65 : 45, height: 50, child: IconButton( onPressed: () { chartData = _addDataPoint(); - _chartSeriesController.updateDataSource( + _chartSeriesController?.updateDataSource( addedDataIndexes: [ chartData.length - 1 ], @@ -112,14 +112,14 @@ class _LiveVerticalState extends SampleViewState { padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), child: SizedBox( - width: model.isWeb ? 65 : 45, + width: model.isWebFullView ? 65 : 45, height: 50, child: IconButton( onPressed: () { if (chartData.length > 1) { chartData = _removeDataPoint(); _chartSeriesController - .updateDataSource( + ?.updateDataSource( updatedDataIndexes: [ chartData.length - 1 ], @@ -136,41 +136,11 @@ class _LiveVerticalState extends SampleViewState { )))) ]))))) ], - ) - - // Row(children: [ - // Spacer(), - // IconButton( - // onPressed: () { - // chartData = _addDataPoint(); - // _chartSeriesController.updateDataSource( - // addedDataIndexes: [chartData.length - 1], - // ); - // }, - // icon: Icon(Icons.add_circle, - // size: isCardView ? 40 : 50, color: model.backgroundColor), - // ), - // IconButton( - // onPressed: () { - // if (chartData.length > 1) { - // chartData = _removeDataPoint(); - // _chartSeriesController.updateDataSource( - // updatedDataIndexes: [chartData.length - 1], - // removedDataIndexes: [chartData.length - 1], - // ); - // } - // }, - // icon: Icon( - // Icons.remove_circle, - // size: isCardView ? 40 : 50, - // color: model.backgroundColor, - // )) - // ]) - ); + )); } /// Returns the chart with add and remove points options. - SfCartesianChart _getAddRemovePointsChart() { + SfCartesianChart _buildAddRemovePointsChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis( diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart index 1f5bbd41..b7537182 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart @@ -73,13 +73,13 @@ class _LiveVerticalState extends SampleViewState { padding: const EdgeInsets.fromLTRB(30, 50, 0, 0), child: Container( height: 45, - width: model.isWeb ? 135 : 110, + width: model.isWebFullView ? 140 : 110, child: InkWell( splashColor: Colors.transparent, child: Row( children: [ SizedBox( - width: model.isWeb ? 65 : 45, + width: model.isWebFullView ? 65 : 45, height: 50, child: IconButton( splashColor: Colors.transparent, @@ -93,7 +93,7 @@ class _LiveVerticalState extends SampleViewState { Padding( padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), child: SizedBox( - width: model.isWeb ? 65 : 45, + width: model.isWebFullView ? 65 : 45, height: 50, child: IconButton( splashColor: Colors.transparent, @@ -158,7 +158,7 @@ class _LiveVerticalState extends SampleViewState { } ///Get the random data point - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random _random = Random(); return min + _random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart index 40632667..e5dc0e7c 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart @@ -27,7 +27,7 @@ class _LiveLineChartState extends SampleViewState { Timer.periodic(const Duration(milliseconds: 100), _updateDataSource); } - Timer timer; + Timer? timer; List<_ChartData> chartData = <_ChartData>[ _ChartData(0, 42), _ChartData(1, 47), @@ -50,7 +50,7 @@ class _LiveLineChartState extends SampleViewState { _ChartData(18, 94), ]; int count = 19; - ChartSeriesController _chartSeriesController; + ChartSeriesController? _chartSeriesController; @override void dispose() { @@ -60,11 +60,11 @@ class _LiveLineChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLiveLineChart(); + return _buildLiveLineChart(); } /// Returns the realtime Cartesian line chart. - SfCartesianChart _getLiveLineChart() { + SfCartesianChart _buildLiveLineChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), @@ -91,12 +91,12 @@ class _LiveLineChartState extends SampleViewState { chartData.add(_ChartData(count, _getRandomInt(10, 100))); if (chartData.length == 20) { chartData.removeAt(0); - _chartSeriesController.updateDataSource( + _chartSeriesController?.updateDataSource( addedDataIndexes: [chartData.length - 1], removedDataIndexes: [0], ); } else { - _chartSeriesController.updateDataSource( + _chartSeriesController?.updateDataSource( addedDataIndexes: [chartData.length - 1], ); } @@ -105,7 +105,7 @@ class _LiveLineChartState extends SampleViewState { } ///Get the random data - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final math.Random _random = math.Random(); return min + _random.nextInt(max - min); } @@ -114,6 +114,6 @@ class _LiveLineChartState extends SampleViewState { /// Private calss for storing the chart series data points. class _ChartData { _ChartData(this.country, this.sales); - final num country; + final int country; final num sales; } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_spline_chart.dart b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_spline_chart.dart index 4dacfd54..c7d992d2 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_spline_chart.dart @@ -24,7 +24,7 @@ class _LiveUpdateState extends SampleViewState { _LiveUpdateState() { timer = Timer.periodic(const Duration(milliseconds: 5), _updateData); } - Timer timer; + Timer? timer; List chartData1 = [ ChartSampleData(x: 0, y: 0), ChartSampleData(x: 1, y: -2), @@ -38,8 +38,8 @@ class _LiveUpdateState extends SampleViewState { ChartSampleData(x: 3, y: 0) ]; bool canStopTimer = false; - int wave1; - int wave2, count = 1; + late int wave1, wave2; + int count = 1; @override void initState() { @@ -67,11 +67,11 @@ class _LiveUpdateState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLiveUpdateChart(); + return _buildLiveUpdateChart(); } ///Get the cartesian chart widget - SfCartesianChart _getLiveUpdateChart() { + SfCartesianChart _buildLiveUpdateChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart index eedc2da7..4cf4cd83 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart @@ -23,9 +23,9 @@ class VerticalLineLiveUpdate extends SampleView { /// State class of the vertical live update chart. class _LiveUpdateState extends SampleViewState { _LiveUpdateState(); - Timer timer; + Timer? timer; int count = 0; - ChartSeriesController _chartSeriesController; + ChartSeriesController? _chartSeriesController; List chartData = [ ChartSampleData(x: 0, y: -4), ChartSampleData(x: 1, y: 3), @@ -52,17 +52,17 @@ class _LiveUpdateState extends SampleViewState { void dispose() { count = 0; chartData = []; - timer.cancel(); + timer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { - return _getVerticalLineUpdateChart(); + return _buildVerticalLineUpdateChart(); } /// Returns the vertical live update cartesian chart. - SfCartesianChart _getVerticalLineUpdateChart() { + SfCartesianChart _buildVerticalLineUpdateChart() { return SfCartesianChart( isTransposed: true, plotAreaBorderWidth: 0, @@ -99,14 +99,14 @@ class _LiveUpdateState extends SampleViewState { void _updateData(Timer timer) { if (isCardView != null) { chartData = _getChartData(); - _chartSeriesController.updateDataSource( + _chartSeriesController?.updateDataSource( addedDataIndexes: [chartData.length - 1], ); } } ///Get random value - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { final Random _random = Random(); return min + _random.nextInt(max - min); } @@ -115,7 +115,7 @@ class _LiveUpdateState extends SampleViewState { List _getChartData() { count = count + 1; if (count > 350 || chartData.length > 350) { - timer.cancel(); + timer?.cancel(); } else if (count > 300) { chartData .add(ChartSampleData(x: chartData.length, y: _getRandomInt(0, 1))); diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart b/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart index 2d067e8f..7f6f7659 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart @@ -40,20 +40,20 @@ class _LiveVerticalState extends SampleViewState { backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, 15, 5, bottomPadding), - child: Container(child: _getUpdateDataSourceChart()), + child: Container(child: _buildUpdateDataSourceChart()), ), floatingActionButton: FloatingActionButton( onPressed: () => setState(() { chartData = []; chartData = _getChartData(); }), - child: const Icon(Icons.refresh, color: Colors.white), backgroundColor: model.backgroundColor, + child: const Icon(Icons.refresh, color: Colors.white), )); } /// Returns the update data source cartesian chart. - SfCartesianChart _getUpdateDataSourceChart() { + SfCartesianChart _buildUpdateDataSourceChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis( @@ -80,7 +80,7 @@ class _LiveVerticalState extends SampleViewState { } ///Get the random value - num _getRandomInt(num min, num max) { + int _getRandomInt(int min, int max) { return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/series_features/animation/series_animation.dart b/lib/samples/chart/cartesian_charts/series_features/animation/series_animation.dart index ab7f5c73..84f3b908 100644 --- a/lib/samples/chart/cartesian_charts/series_features/animation/series_animation.dart +++ b/lib/samples/chart/cartesian_charts/series_features/animation/series_animation.dart @@ -24,60 +24,16 @@ class _AnimationDefaultState extends SampleViewState { @override Widget build(BuildContext context) { padding = MediaQuery.of(context).orientation == Orientation.landscape || - model.isWeb + model.isWebFullView ? (MediaQuery.of(context).size.width / 100 * 14) : (MediaQuery.of(context).size.width / 100) * 5; - return _getDefaultAnimationChart(); + return _buildDefaultAnimationChart(); } - ChartSeriesController _chartSeriesController1, _chartSeriesController2; - // @override - // Widget buildSettings(BuildContext context) { - // return ListView( - // children: [ - // Padding( - // padding: EdgeInsets.only(right: model.isWeb ? 0 : 15), - // child: Column( - // children: [ - // Container( - // width: 180, - // child: RaisedButton( - // color: model.backgroundColor, - // onPressed: () { - // _chartSeriesController2?.animate(); - // }, - // child: Text('Animate line series', - // style: TextStyle(color: Colors.white)), - // )), - // Container( - // width: 180, - // child: RaisedButton( - // color: model.backgroundColor, - // onPressed: () { - // _chartSeriesController1?.animate(); - // }, - // child: Text('Animate column series', - // style: TextStyle(color: Colors.white)), - // )), - // Container( - // width: 180, - // child: RaisedButton( - // color: model.backgroundColor, - // onPressed: () { - // _chartSeriesController1?.animate(); - // _chartSeriesController2?.animate(); - // }, - // child: Text('Animate both', - // style: TextStyle(color: Colors.white)), - // )), - // ], - // )) - // ], - // ); - // } + ChartSeriesController? _chartSeriesController1, _chartSeriesController2; /// Returns the cartesian chart with default serie animation. - Column _getDefaultAnimationChart() { + Column _buildDefaultAnimationChart() { return Column(children: [ Expanded( child: SfCartesianChart( @@ -111,20 +67,20 @@ class _AnimationDefaultState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - child: model.isWeb + child: model.isWebFullView ? ButtonTheme( minWidth: 40.0, height: 30.0, - child: _getColumnButton()) - : _getColumnButton()), + child: _buildColumnButton()) + : _buildColumnButton()), Padding(padding: EdgeInsets.fromLTRB(5, 0, 0, 0)), Container( - child: model.isWeb + child: model.isWebFullView ? ButtonTheme( minWidth: 40.0, height: 30.0, - child: _getLineButton()) - : _getLineButton()), + child: _buildLineButton()) + : _buildLineButton()), ], ) ]); @@ -165,9 +121,12 @@ class _AnimationDefaultState extends SampleViewState { ]; } - RaisedButton _getColumnButton() { - return RaisedButton( - color: model.backgroundColor, + ElevatedButton _buildColumnButton() { + return ElevatedButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + ), onPressed: () { _chartSeriesController2?.animate(); }, @@ -176,9 +135,12 @@ class _AnimationDefaultState extends SampleViewState { ); } - RaisedButton _getLineButton() { - return RaisedButton( - color: model.backgroundColor, + ElevatedButton _buildLineButton() { + return ElevatedButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + ), onPressed: () { _chartSeriesController1?.animate(); }, diff --git a/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_annotation.dart b/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_annotation.dart index 1f2edb86..4c138002 100644 --- a/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_annotation.dart +++ b/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_annotation.dart @@ -22,11 +22,13 @@ class _AnnotationWatermarkState extends SampleViewState { @override Widget build(BuildContext context) { - return _getWatermarkAnnotationChart(); + return _buildWatermarkAnnotationChart(); } /// Returns the Cartesian chart with annotation. - SfCartesianChart _getWatermarkAnnotationChart() { + SfCartesianChart _buildWatermarkAnnotationChart() { + final bool needSmallAnnotation = + (model.isWebFullView && MediaQuery.of(context).size.height < 530); return SfCartesianChart( title: ChartTitle( text: isCardView ? '' : 'UK social media reach, by platform'), @@ -47,8 +49,16 @@ class _AnnotationWatermarkState extends SampleViewState { annotations: [ CartesianChartAnnotation( widget: Container( - height: isCardView ? 100 : 150, - width: isCardView ? 100 : 150, + height: isCardView + ? 100 + : needSmallAnnotation + ? 80 + : 150, + width: isCardView + ? 100 + : needSmallAnnotation + ? 80 + : 150, child: SfCircularChart( series: >[ PieSeries( @@ -86,11 +96,13 @@ class _AnnotationWatermarkState extends SampleViewState { dataLabelSettings: DataLabelSettings( isVisible: true, labelIntersectAction: LabelIntersectAction.none, - textStyle: isCardView - ? const TextStyle( - color: Colors.white, fontSize: 10) - : const TextStyle( - color: Colors.white, fontSize: 12)), + textStyle: TextStyle( + color: Colors.white, + fontSize: isCardView + ? 10 + : needSmallAnnotation + ? 7 + : 12)), pointColorMapper: (ChartSampleData data, _) => data.pointColor) ], diff --git a/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_watermark.dart b/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_watermark.dart index 2ff044b5..998ef4e6 100644 --- a/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_watermark.dart +++ b/lib/samples/chart/cartesian_charts/series_features/annotation/chart_with_watermark.dart @@ -19,14 +19,23 @@ class AnnotationDefault extends SampleView { /// State class of the chart with watermark. class _AnnotationDefaultState extends SampleViewState { _AnnotationDefaultState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + _trackballBehavior = TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + tooltipSettings: InteractiveTooltip(format: 'point.x : point.y')); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultAnnotationChart(); + return _buildDefaultAnnotationChart(); } /// Returns the cartesian chart with watermark. - SfCartesianChart _getDefaultAnnotationChart() { + SfCartesianChart _buildDefaultAnnotationChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -42,10 +51,7 @@ class _AnnotationDefaultState extends SampleViewState { majorTickLines: MajorTickLines(size: 0), ), series: _getAnnotationLineSeries(), - trackballBehavior: TrackballBehavior( - enable: true, - activationMode: ActivationMode.singleTap, - tooltipSettings: InteractiveTooltip(format: 'point.x : point.y')), + trackballBehavior: _trackballBehavior, /// Using various styles in annotation we can achieve /// the water marker on chart. diff --git a/lib/samples/chart/cartesian_charts/series_features/data_label/data_label_template.dart b/lib/samples/chart/cartesian_charts/series_features/data_label/data_label_template.dart index 8e6cd575..9cdd9aa1 100644 --- a/lib/samples/chart/cartesian_charts/series_features/data_label/data_label_template.dart +++ b/lib/samples/chart/cartesian_charts/series_features/data_label/data_label_template.dart @@ -21,11 +21,11 @@ class _DataLabelTemplateState extends SampleViewState { _DataLabelTemplateState(); @override Widget build(BuildContext context) { - return _getDataLabelTemplateChart(); + return _buildDataLabelTemplateChart(); } /// Returns the chart with various marker shapes. - SfCartesianChart _getDataLabelTemplateChart() { + SfCartesianChart _buildDataLabelTemplateChart() { return SfCartesianChart( title: ChartTitle( text: isCardView @@ -78,7 +78,6 @@ class _DataLabelTemplateState extends SampleViewState { ChartSampleData( x: 'Instagram', y: 63, - // pointColor: gradientColors, ), ChartSampleData( x: 'Snapchat', @@ -135,7 +134,7 @@ class _DataLabelTemplateState extends SampleViewState { } String _getImageTemplate(int pointIndex) { - String path = (pointIndex == 0 + final String path = (pointIndex == 0 ? 'images/youtube.png' : (pointIndex == 1 ? 'images/maps_twitter.png' @@ -159,23 +158,24 @@ class _CustomColumnSeriesRenderer extends ColumnSeriesRenderer { class _ColumnCustomPainter extends ColumnSegment { @override - int get currentSegmentIndex => super.currentSegmentIndex; + int get currentSegmentIndex => super.currentSegmentIndex!; @override void onPaint(Canvas canvas) { - Paint myPaint = fillPaint; - if (currentSegmentIndex == 0) + Paint? myPaint = fillPaint; + if (currentSegmentIndex == 0) { myPaint = Paint()..color = Color.fromRGBO(192, 33, 39, 1); - else if (currentSegmentIndex == 1) + } else if (currentSegmentIndex == 1) { myPaint = Paint()..color = const Color.fromRGBO(26, 157, 235, 1); - else if (currentSegmentIndex == 2) + } else if (currentSegmentIndex == 2) { myPaint = fillPaint; - else if (currentSegmentIndex == 3) + } else if (currentSegmentIndex == 3) { myPaint = Paint()..color = const Color.fromRGBO(254, 250, 55, 1); - else if (currentSegmentIndex == 4) + } else if (currentSegmentIndex == 4) { myPaint = Paint()..color = const Color.fromRGBO(60, 92, 156, 1); + } final Rect rect = Rect.fromLTRB(segmentRect.left, segmentRect.top, segmentRect.right * animationFactor, segmentRect.bottom); - canvas.drawRect(rect, myPaint); + canvas.drawRect(rect, myPaint!); } } diff --git a/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart b/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart index 2e97f999..1942a9bc 100644 --- a/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart +++ b/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart @@ -20,13 +20,14 @@ class DataLabelDefault extends SampleView { /// State class of the chart with default data labels. class _DataLabelDefaultState extends SampleViewState { _DataLabelDefaultState(); - bool _seriescolor; + late bool _seriescolor; String _labelPos = 'top'; String _labelAln = 'center'; - ChartDataLabelAlignment _labelPosition; - ChartAlignment _chartAlignment; - double _horizontalPaddding = 0; - double _verticalPaddding = 0; + late ChartDataLabelAlignment _labelPosition; + late ChartAlignment _chartAlignment; + late double _horizontalPaddding; + late double _verticalPaddding; + late TooltipBehavior _tooltipBehavior; final List _positionType = ['outer', 'top', 'bottom', 'middle'].toList(); @@ -55,9 +56,9 @@ class _DataLabelDefaultState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _seriescolor, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _seriescolor = value; + _seriescolor = value!; stateSetter(() {}); }); })), @@ -178,11 +179,11 @@ class _DataLabelDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDataLabelDefaultChart(); + return _buildDataLabelDefaultChart(); } /// Returns the chart with default data labels. - SfCartesianChart _getDataLabelDefaultChart() { + SfCartesianChart _buildDataLabelDefaultChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : 'Gross investments'), plotAreaBorderWidth: 0, @@ -201,7 +202,7 @@ class _DataLabelDefaultState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getDataLabelDefaultSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } @@ -261,6 +262,7 @@ class _DataLabelDefaultState extends SampleViewState { _seriescolor = true; _horizontalPaddding = 0; _verticalPaddding = 0; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } diff --git a/lib/samples/chart/cartesian_charts/series_features/empty_points.dart b/lib/samples/chart/cartesian_charts/series_features/empty_points.dart index d7631a28..e023371e 100644 --- a/lib/samples/chart/cartesian_charts/series_features/empty_points.dart +++ b/lib/samples/chart/cartesian_charts/series_features/empty_points.dart @@ -21,21 +21,25 @@ class _EmptyPointsState extends SampleViewState { _EmptyPointsState(); final List _emptyPointMode = ['gap', 'zero', 'average', 'drop'].toList(); - EmptyPointMode _selectedEmptyPointMode = EmptyPointMode.gap; - String _selectedMode; + late EmptyPointMode _selectedEmptyPointMode = EmptyPointMode.gap; + late String _selectedMode; + late TooltipBehavior _tooltipBehavior; @override void initState() { _selectedMode = 'zero'; _selectedEmptyPointMode = EmptyPointMode.gap; + _tooltipBehavior = + TooltipBehavior(enable: true, header: '', canShowMarker: false); super.initState(); } @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 60), - child: _getEmptyPointChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 60), + child: _buildEmptyPointChart()); } @override @@ -72,7 +76,7 @@ class _EmptyPointsState extends SampleViewState { } /// Returns the cartesian chart with empty points. - SfCartesianChart _getEmptyPointChart() { + SfCartesianChart _buildEmptyPointChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: 'Population growth of various countries'), @@ -84,8 +88,7 @@ class _EmptyPointsState extends SampleViewState { labelFormat: '{value}%', majorTickLines: MajorTickLines(size: 0)), series: _getEmptyPointSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, header: '', canShowMarker: false), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/series_features/gradients/horizantal_gradient.dart b/lib/samples/chart/cartesian_charts/series_features/gradients/horizantal_gradient.dart index c9874ca9..8067e0b3 100644 --- a/lib/samples/chart/cartesian_charts/series_features/gradients/horizantal_gradient.dart +++ b/lib/samples/chart/cartesian_charts/series_features/gradients/horizantal_gradient.dart @@ -19,23 +19,29 @@ class HorizantalGradient extends SampleView { /// State class of horizontal gradient. class _HorizantalGradientState extends SampleViewState { _HorizantalGradientState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior(enable: true, canShowMarker: false); + super.initState(); + } @override Widget build(BuildContext context) { - return _getHorizantalGradientAreaChart(); + return _buildHorizantalGradientAreaChart(); } /// Return the circular chart with horizontal gradient. - SfCartesianChart _getHorizantalGradientAreaChart() { + SfCartesianChart _buildHorizantalGradientAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Total investment (% of GDP)'), primaryXAxis: CategoryAxis( labelPlacement: LabelPlacement.onTicks, - interval: model.isWeb ? 1 : null, + interval: model.isWebFullView ? 1 : null, labelRotation: -45, majorGridLines: MajorGridLines(width: 0)), - tooltipBehavior: TooltipBehavior(enable: true, canShowMarker: false), + tooltipBehavior: _tooltipBehavior, primaryYAxis: NumericAxis( interval: 2, minimum: 14, @@ -79,8 +85,8 @@ class _HorizantalGradientState extends SampleViewState { _ChartData(x: '2004', y: 17.90) ]; final List color = []; - color.add(Colors.blue[200]); - color.add(Colors.orange[200]); + color.add(Colors.blue[200]!); + color.add(Colors.orange[200]!); final List stops = []; stops.add(0.2); @@ -124,6 +130,6 @@ class _HorizantalGradientState extends SampleViewState { class _ChartData { _ChartData({this.x, this.y}); - final String x; - final double y; + final String? x; + final double? y; } diff --git a/lib/samples/chart/cartesian_charts/series_features/gradients/vertical_gradient.dart b/lib/samples/chart/cartesian_charts/series_features/gradients/vertical_gradient.dart index 3e96fc79..e832251d 100644 --- a/lib/samples/chart/cartesian_charts/series_features/gradients/vertical_gradient.dart +++ b/lib/samples/chart/cartesian_charts/series_features/gradients/vertical_gradient.dart @@ -18,17 +18,24 @@ class VerticalGradient extends SampleView { class _ChartData { _ChartData({this.x, this.y}); - final String x; - final double y; + final String? x; + final double? y; } /// State class of vertical gradient. class _VerticalGradientState extends SampleViewState { _VerticalGradientState(); + late TrackballBehavior _trackballBehavior; + @override + void initState() { + _trackballBehavior = TrackballBehavior( + enable: true, activationMode: ActivationMode.singleTap); + super.initState(); + } @override Widget build(BuildContext context) { - return _getVerticalGradientAreaChart(); + return _buildVerticalGradientAreaChart(); } /// Returns the list of spline area series with vertical gradient. @@ -97,12 +104,12 @@ class _VerticalGradientState extends SampleViewState { } /// Return the circular chart with vertical gradient. - SfCartesianChart _getVerticalGradientAreaChart() { + SfCartesianChart _buildVerticalGradientAreaChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: CategoryAxis( labelPlacement: LabelPlacement.onTicks, - interval: model.isWeb ? 1 : null, + interval: model.isWebFullView ? 1 : null, labelRotation: -45, majorGridLines: MajorGridLines(width: 0)), primaryYAxis: NumericAxis( @@ -112,7 +119,7 @@ class _VerticalGradientState extends SampleViewState { labelFormat: '{value}%', axisLine: AxisLine(width: 0), ), - trackballBehavior: TrackballBehavior(enable: true), + trackballBehavior: _trackballBehavior, series: _getGradientAreaSeries(), ); } diff --git a/lib/samples/chart/cartesian_charts/series_features/marker.dart b/lib/samples/chart/cartesian_charts/series_features/marker.dart index 32ab72c5..5d29a4a6 100644 --- a/lib/samples/chart/cartesian_charts/series_features/marker.dart +++ b/lib/samples/chart/cartesian_charts/series_features/marker.dart @@ -23,11 +23,11 @@ class _MarkerDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getMarkerDefaultChart(); + return _buildMarkerDefaultChart(); } /// Returns the chart with various marker shapes. - SfCartesianChart _getMarkerDefaultChart() { + SfCartesianChart _buildMarkerDefaultChart() { return SfCartesianChart( title: ChartTitle(text: 'Vehicles crossed tollgate'), legend: Legend(isVisible: true), diff --git a/lib/samples/chart/cartesian_charts/series_features/sorting.dart b/lib/samples/chart/cartesian_charts/series_features/sorting.dart index a585918a..37bc4157 100644 --- a/lib/samples/chart/cartesian_charts/series_features/sorting.dart +++ b/lib/samples/chart/cartesian_charts/series_features/sorting.dart @@ -23,17 +23,23 @@ class _SortingDefaultState extends SampleViewState { final List _labelList = ['y', 'x'].toList(); final List _sortList = ['none', 'descending', 'ascending'].toList(); - String _selectedType = 'y'; - String _selectedSortType = 'none'; - SortingOrder _sortingOrder = SortingOrder.none; + late String _selectedType; + late String _selectedSortType; + late SortingOrder _sortingOrder; + late TooltipBehavior _tooltipBehavior; - String _sortby = 'y'; + late String _sortby; @override void initState() { _selectedType = 'y'; _selectedSortType = 'none'; _sortingOrder = SortingOrder.none; + _tooltipBehavior = TooltipBehavior( + enable: true, + canShowMarker: false, + header: '', + format: 'point.x : point.y m'); _sortby = 'y'; super.initState(); } @@ -41,8 +47,9 @@ class _SortingDefaultState extends SampleViewState { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 60), - child: _getDefaultSortingChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 60), + child: _buildDefaultSortingChart()); } @override @@ -114,7 +121,7 @@ class _SortingDefaultState extends SampleViewState { } /// Returns the Cartesian chart with sorting options. - SfCartesianChart _getDefaultSortingChart() { + SfCartesianChart _buildDefaultSortingChart() { return SfCartesianChart( title: ChartTitle(text: "World's tallest buildings"), plotAreaBorderWidth: 0, @@ -129,11 +136,7 @@ class _SortingDefaultState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getDefaultSortingSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - canShowMarker: false, - header: '', - format: 'point.x : point.y m'), + tooltipBehavior: _tooltipBehavior, ); } @@ -152,7 +155,7 @@ class _SortingDefaultState extends SampleViewState { dataSource: chartData, xValueMapper: (ChartSampleData sales, _) => sales.x, yValueMapper: (ChartSampleData sales, _) => sales.y, - sortingOrder: _sortingOrder ?? SortingOrder.none, + sortingOrder: _sortingOrder, dataLabelSettings: DataLabelSettings( isVisible: true, labelAlignment: ChartDataLabelAlignment.auto), sortFieldValueMapper: (ChartSampleData sales, _) => diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/accumulation_distribution.dart b/lib/samples/chart/cartesian_charts/technical_indicators/accumulation_distribution.dart index b207b996..2082d8aa 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/accumulation_distribution.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/accumulation_distribution.dart @@ -21,14 +21,26 @@ class AdIndicator extends SampleView { /// State class of the OHLC chart with Accumulation distribution indicator. class _AdIndicatorState extends SampleViewState { _AdIndicatorState(); + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + super.initState(); + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); + } @override Widget build(BuildContext context) { - return _getDefaultAdIndicator(); + return _buildDefaultAdIndicator(); } /// Returns the OHLC chart with Accumulation distribution indicator. - SfCartesianChart _getDefaultAdIndicator() { + SfCartesianChart _buildDefaultAdIndicator() { final List chartData = getChartData(); return SfCartesianChart( legend: Legend(isVisible: !isCardView), @@ -58,12 +70,8 @@ class _AdIndicatorState extends SampleViewState { numberFormat: NumberFormat.compact(), ) ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// AD indicator mentioned here. AccumulationDistributionIndicator( diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/atr_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/atr_indicator.dart index b28504c0..081eb59a 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/atr_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/atr_indicator.dart @@ -22,17 +22,25 @@ class ATRIndicator extends SampleView { /// State class of the OHLC Ohart with Average true range indicator. class _ATRIndicatorState extends SampleViewState { _ATRIndicatorState(); - double _period = 14.0; + late double _period; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { - _period = 14; super.initState(); + _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaultATRIndicator(); + return _buildDefaultATRIndicator(); } @override @@ -63,7 +71,7 @@ class _ATRIndicatorState extends SampleViewState { } /// Returns the OHLC Ohart with Average true range indicator. - SfCartesianChart _getDefaultATRIndicator() { + SfCartesianChart _buildDefaultATRIndicator() { final List chartData = getChartData(); return SfCartesianChart( legend: Legend(isVisible: !isCardView), @@ -91,18 +99,12 @@ class _ATRIndicatorState extends SampleViewState { maximum: 10, interval: 2) ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// ATR indicator mentioned here. AtrIndicator( - seriesName: 'AAPL', - yAxisName: 'yaxes', - period: _period.toInt() ?? 14), + seriesName: 'AAPL', yAxisName: 'yaxes', period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/bollinger_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/bollinger_indicator.dart index 90ebada1..c50056db 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/bollinger_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/bollinger_indicator.dart @@ -22,74 +22,79 @@ class BollingerIndicator extends SampleView { /// State class of the OHLC chart with Bollinger band indicator. class _BollingerIndicatorState extends SampleViewState { _BollingerIndicatorState(); - double _period = 14.0; - double _standardDeviation = 1.0; + late double _period; + late double _standardDeviation; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { + super.initState(); _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + tooltipSettings: InteractiveTooltip( + color: model.themeData.brightness == Brightness.light + ? Color.fromRGBO(79, 79, 79, 1) + : Color.fromRGBO(255, 255, 255, 1), + ), + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); _standardDeviation = 1; - super.initState(); } @override Widget build(BuildContext context) { - return _getDefaulBollingerIndicator(); + return _buildDefaulBollingerIndicator(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Period', - style: TextStyle(color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(125, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _period, - onChanged: (double val) => setState(() { - _period = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _period, + onChanged: (double val) => setState(() { + _period = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Standard deviation', - style: TextStyle(color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(50, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 5, - initialValue: _standardDeviation, - onChanged: (double val) => setState(() { - _standardDeviation = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - ), - ], + ListTile( + title: Text( + 'Standard deviation', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 5, + initialValue: _standardDeviation, + onChanged: (double val) => setState(() { + _standardDeviation = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), ], @@ -97,7 +102,7 @@ class _BollingerIndicatorState extends SampleViewState { } // Returns the OHLC chart with Bollinger band indicator - SfCartesianChart _getDefaulBollingerIndicator() { + SfCartesianChart _buildDefaulBollingerIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -117,24 +122,15 @@ class _BollingerIndicatorState extends SampleViewState { interval: 20, labelFormat: '\${value}', axisLine: AxisLine(width: 0)), - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - tooltipSettings: InteractiveTooltip( - color: model.themeData.brightness == Brightness.light - ? Color.fromRGBO(79, 79, 79, 1) - : Color.fromRGBO(255, 255, 255, 1), - ), - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// Bollinger band indicator mentioned here. BollingerBandIndicator( seriesName: 'AAPL', animationDuration: 0, - period: _period.toInt() ?? 14, - standardDeviation: _standardDeviation.toInt() ?? 1, + period: _period.toInt(), + standardDeviation: _standardDeviation.toInt(), ), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/ema_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/ema_indicator.dart index 17a47494..d2702b66 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/ema_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/ema_indicator.dart @@ -22,17 +22,25 @@ class EMAIndicator extends SampleView { /// State class of the OHLC chart with Exponential moving average indicator. class _EMAIndicatorState extends SampleViewState { _EMAIndicatorState(); - double _period = 14.0; + late double _period; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { - _period = 14; super.initState(); + _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaulEMAIndicator(); + return _buildDefaulEMAIndicator(); } @override @@ -63,7 +71,7 @@ class _EMAIndicatorState extends SampleViewState { } /// Returns the the OHLC chart with Exponential moving average indicator. - SfCartesianChart _getDefaulEMAIndicator() { + SfCartesianChart _buildDefaulEMAIndicator() { final List chartData = getChartData(); return SfCartesianChart( legend: Legend(isVisible: !isCardView), @@ -81,16 +89,12 @@ class _EMAIndicatorState extends SampleViewState { interval: 20, labelFormat: '\${value}', axisLine: AxisLine(width: 0)), - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// EMA indicator mentioned here. EmaIndicator( - seriesName: 'AAPL', period: _period.toInt() ?? 14), + seriesName: 'AAPL', period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/macd_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/macd_indicator.dart index c9dcc581..5eff5da2 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/macd_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/macd_indicator.dart @@ -24,138 +24,129 @@ class MACDIndicator extends SampleView { /// Moving average convergence divergence indicator. class _MACDIndicatorState extends SampleViewState { _MACDIndicatorState(); - double _period = 14.0; - double _longPeriod = 5.0; - double _shortPeriod = 2.0; + late double _period; + late double _longPeriod; + late double _shortPeriod; final List _macdIndicatorTypeList = ['Both', 'Line', 'Histogram'].toList(); - String _selectedMacdIndicatorType = 'Both'; - MacdType _macdType = MacdType.both; + late String _selectedMacdIndicatorType = 'Both'; + late MacdType _macdType = MacdType.both; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { + super.initState(); _period = 14; _longPeriod = 5.0; _shortPeriod = 2.0; _selectedMacdIndicatorType = 'Both'; _macdType = MacdType.both; - super.initState(); + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaultMACDIndicator(); + return _buildDefaultMACDIndicator(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(80, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _period, - onChanged: (double val) => setState(() { - _period = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _period, + onChanged: (double val) => setState(() { + _period = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Long Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _longPeriod, - onChanged: (double val) => setState(() { - _longPeriod = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Long Period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _longPeriod, + onChanged: (double val) => setState(() { + _longPeriod = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Short period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(36, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _shortPeriod, - onChanged: (double val) => setState(() { - _shortPeriod = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Short period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _shortPeriod, + onChanged: (double val) => setState(() { + _shortPeriod = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - children: [ - Text('MACD type ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(34, 0, 0, 0), - height: 50, - alignment: Alignment.bottomCenter, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedMacdIndicatorType, - items: _macdIndicatorTypeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'Both', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (String value) { - _onMacdIndicatorTypeChanged(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('MACD type ', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMacdIndicatorType, + items: _macdIndicatorTypeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Both', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (String? value) { + _onMacdIndicatorTypeChanged(value.toString()); + stateSetter(() {}); + }), ), ), ], @@ -165,7 +156,7 @@ class _MACDIndicatorState extends SampleViewState { /// Returns the OHLC chart with /// Moving average convergence divergence indicator. - SfCartesianChart _getDefaultMACDIndicator() { + SfCartesianChart _buildDefaultMACDIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -193,20 +184,16 @@ class _MACDIndicatorState extends SampleViewState { indicators: >[ /// MACD indicator mentioned here. MacdIndicator( - period: _period.toInt() ?? 14, - longPeriod: _longPeriod.toInt() ?? 5, - shortPeriod: _shortPeriod.toInt() ?? 2, + period: _period.toInt(), + longPeriod: _longPeriod.toInt(), + shortPeriod: _shortPeriod.toInt(), signalLineWidth: 2, macdType: _macdType, seriesName: 'AAPL', yAxisName: 'agybrd'), ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ HiloOpenCloseSeries( diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/momentum_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/momentum_indicator.dart index e12dee9c..afb7a3e7 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/momentum_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/momentum_indicator.dart @@ -22,17 +22,24 @@ class MomentummIndicator extends SampleView { /// State class of the OHLC chart with Momentum indicator. class _MomentummIndicatorState extends SampleViewState { _MomentummIndicatorState(); - double _period = 14.0; + late double _period; + late TooltipBehavior _tooltipBehavior; + late TrackballBehavior _trackballBehavior; @override void initState() { - _period = 14; super.initState(); + _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaulMomentumIndicator(); + return _buildDefaulMomentumIndicator(); } @override @@ -63,7 +70,7 @@ class _MomentummIndicatorState extends SampleViewState { } /// Returns the OHLC chart with Momentum indicator. - SfCartesianChart _getDefaulMomentumIndicator() { + SfCartesianChart _buildDefaulMomentumIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -91,18 +98,12 @@ class _MomentummIndicatorState extends SampleViewState { interval: 20, axisLine: AxisLine(width: 0)) ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// Momentum indicator mentioned here. MomentumIndicator( - seriesName: 'AAPL', - yAxisName: 'yaxes', - period: _period.toInt() ?? 14), + seriesName: 'AAPL', yAxisName: 'yaxes', period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/rsi_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/rsi_indicator.dart index a58673e4..06a6bc5a 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/rsi_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/rsi_indicator.dart @@ -22,138 +22,128 @@ class RSIIndicator extends SampleView { /// State class of the the OHLC chart with Relative strength index indicator. class _RSIIndicatorState extends SampleViewState { _RSIIndicatorState(); - double _period = 14.0; - double _overBought = 80.0; - double _overSold = 20.0; - bool _showZones = true; + late double _period; + late double _overBought; + late double _overSold; + late bool _showZones; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { + super.initState(); _period = 14.0; _overBought = 80.0; _overSold = 20.0; _showZones = true; - super.initState(); + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaultRSIIndicator(); + return _buildDefaultRSIIndicator(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(88, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _period, - onChanged: (double val) => setState(() { - _period = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Period', + style: TextStyle(color: model.textColor), ), - ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Overbought', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(49, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 100, - initialValue: _overBought, - onChanged: (double val) => setState(() { - _overBought = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _period, + onChanged: (double val) => setState(() { + _period = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Oversold', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(68, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _overSold, - onChanged: (double val) => setState(() { - _overSold = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Over bought', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 100, + initialValue: _overBought, + onChanged: (double val) => setState(() { + _overBought = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - children: [ - Text('Show zones', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Padding( - padding: const EdgeInsets.fromLTRB(17, 0, 0, 0), - child: Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _showZones, - onChanged: (bool value) { - setState(() { - _showZones = value; - stateSetter(() {}); - }); - }))), - ], + ListTile( + title: Text( + 'Over Sold', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _overSold, + onChanged: (double val) => setState(() { + _overSold = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), + ListTile( + title: Text('Show zones', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.5 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: _showZones, + onChanged: (bool? value) { + setState(() { + _showZones = value!; + stateSetter(() {}); + }); + }))), ], ); }); } /// Returns the OHLC chart with Relative strength index indicator. - SfCartesianChart _getDefaultRSIIndicator() { + SfCartesianChart _buildDefaultRSIIndicator() { return SfCartesianChart( plotAreaBorderWidth: 0, legend: Legend(isVisible: !isCardView), @@ -180,21 +170,17 @@ class _RSIIndicatorState extends SampleViewState { interval: 20, axisLine: AxisLine(width: 0)) ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// RSI indicator mentioned here. RsiIndicator( seriesName: 'AAPL', yAxisName: 'yaxes', - overbought: _overBought ?? 80, - oversold: _overSold ?? 20, - showZones: _showZones ?? true, - period: _period.toInt() ?? 14), + overbought: _overBought, + oversold: _overSold, + showZones: _showZones, + period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: _getDataLabelHilotSeries()); diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/sma_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/sma_indicator.dart index 452bfcce..aed7a841 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/sma_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/sma_indicator.dart @@ -22,17 +22,25 @@ class SMAIndicator extends SampleView { /// State class of the OHLC chart with Simple moving average indicator. class _SMAIndicatorState extends SampleViewState { _SMAIndicatorState(); - double _period = 14.0; + late double _period; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { - _period = 14; super.initState(); + _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaulSMAIndicator(); + return _buildDefaulSMAIndicator(); } @override @@ -63,7 +71,7 @@ class _SMAIndicatorState extends SampleViewState { } /// Returns the OHLC chart with Simple moving average indicator. - SfCartesianChart _getDefaulSMAIndicator() { + SfCartesianChart _buildDefaulSMAIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -81,16 +89,12 @@ class _SMAIndicatorState extends SampleViewState { interval: 20, labelFormat: '\${value}', axisLine: AxisLine(width: 0)), - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// SMA indicator mentioned here. SmaIndicator( - seriesName: 'AAPL', period: _period.toInt() ?? 14), + seriesName: 'AAPL', period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/stochastic_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/stochastic_indicator.dart index 6290dbd8..27db65ae 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/stochastic_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/stochastic_indicator.dart @@ -22,192 +22,172 @@ class StochasticcIndicator extends SampleView { /// State class of the OHLC chart with Stochastic indicator. class _StochasticcIndicatorState extends SampleViewState { _StochasticcIndicatorState(); - double _period = 14.0; - double _kPeriod = 3.0; - double _dPeriod = 5.0; - double _overBought = 80.0; - double _overSold = 20.0; - bool _showZones = true; + late double _period; + late double _kPeriod; + late double _dPeriod; + late double _overBought; + late double _overSold; + late bool _showZones; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { + super.initState(); _period = 14.0; _overBought = 80.0; _overSold = 20.0; _kPeriod = 3.0; _dPeriod = 5.0; _showZones = true; - super.initState(); + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaultStochasticIndicator(); + return _buildDefaultStochasticIndicator(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(82, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _period, - onChanged: (double val) => setState(() { - _period = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Period', + style: TextStyle(color: model.textColor), ), - ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'K Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(68, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 100, - initialValue: _kPeriod, - onChanged: (double val) => setState(() { - _kPeriod = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _period, + onChanged: (double val) => setState(() { + _period = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'D Period', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(68, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _dPeriod, - onChanged: (double val) => setState(() { - _dPeriod = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'K Period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 100, + initialValue: _kPeriod, + onChanged: (double val) => setState(() { + _kPeriod = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Overbought', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(46, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 100, - initialValue: _overBought, - onChanged: (double val) => setState(() { - _overBought = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], + ListTile( + title: Text( + 'D Period', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _dPeriod, + onChanged: (double val) => setState(() { + _dPeriod = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Oversold', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(65, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _overSold, - onChanged: (double val) => setState(() { - _overSold = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ) - ], + ListTile( + title: Text( + 'Overbought', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 100, + initialValue: _overBought, + onChanged: (double val) => setState(() { + _overBought = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - children: [ - Text('Show zones', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Padding( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - child: Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _showZones, - onChanged: (bool value) { - setState(() { - _showZones = value; - stateSetter(() {}); - }); - }))), - ], + ListTile( + title: Text( + 'Oversold', + style: TextStyle(color: model.textColor), + ), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: _overSold, + onChanged: (double val) => setState(() { + _overSold = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), + ListTile( + title: Text('Show zones', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.5 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: _showZones, + onChanged: (bool? value) { + setState(() { + _showZones = value!; + stateSetter(() {}); + }); + }))), ], ); }); } /// Returns the OHLC chart with Stochastic indicator. - SfCartesianChart _getDefaultStochasticIndicator() { + SfCartesianChart _buildDefaultStochasticIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -235,23 +215,19 @@ class _StochasticcIndicatorState extends SampleViewState { interval: 20, axisLine: AxisLine(width: 0)) ], - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// Stochastic indicator mentioned here. StochasticIndicator( seriesName: 'AAPL', yAxisName: 'yaxes', - overbought: _overBought ?? 80, - oversold: _overSold ?? 20, - showZones: _showZones ?? true, - period: _period.toInt() ?? 14, - kPeriod: _kPeriod.toInt() ?? 3, - dPeriod: _dPeriod.toInt() ?? 5, + overbought: _overBought, + oversold: _overSold, + showZones: _showZones, + period: _period.toInt(), + kPeriod: _kPeriod.toInt(), + dPeriod: _dPeriod.toInt(), ), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), diff --git a/lib/samples/chart/cartesian_charts/technical_indicators/tma_indicator.dart b/lib/samples/chart/cartesian_charts/technical_indicators/tma_indicator.dart index aea5e42d..d2da1ce7 100644 --- a/lib/samples/chart/cartesian_charts/technical_indicators/tma_indicator.dart +++ b/lib/samples/chart/cartesian_charts/technical_indicators/tma_indicator.dart @@ -22,17 +22,24 @@ class TMAIndicator extends SampleView { /// State class of the OHLC chart with Triangular moving average indicator. class _TMAIndicatorState extends SampleViewState { _TMAIndicatorState(); - double _period = 14.0; - + late double _period; + late TrackballBehavior _trackballBehavior; + late TooltipBehavior _tooltipBehavior; @override void initState() { - _period = 14; super.initState(); + _period = 14; + _trackballBehavior = TrackballBehavior( + enable: !isCardView, + activationMode: ActivationMode.singleTap, + tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, + ); + _tooltipBehavior = TooltipBehavior(enable: isCardView ? true : false); } @override Widget build(BuildContext context) { - return _getDefaulTMAIndicator(); + return _buildDefaulTMAIndicator(); } @override @@ -63,7 +70,7 @@ class _TMAIndicatorState extends SampleViewState { } /// Returns the OHLC chart with Triangular moving average indicator. - SfCartesianChart _getDefaulTMAIndicator() { + SfCartesianChart _buildDefaulTMAIndicator() { final List chartData = getChartData(); return SfCartesianChart( plotAreaBorderWidth: 0, @@ -81,16 +88,12 @@ class _TMAIndicatorState extends SampleViewState { interval: 20, labelFormat: '\${value}', axisLine: AxisLine(width: 0)), - trackballBehavior: TrackballBehavior( - enable: !isCardView, - activationMode: ActivationMode.singleTap, - tooltipDisplayMode: TrackballDisplayMode.groupAllPoints, - ), - tooltipBehavior: TooltipBehavior(enable: isCardView ? true : false), + trackballBehavior: _trackballBehavior, + tooltipBehavior: _tooltipBehavior, indicators: >[ /// TMA indicator mentioned here. TmaIndicator( - seriesName: 'AAPL', period: _period.toInt() ?? 14), + seriesName: 'AAPL', period: _period.toInt()), ], title: ChartTitle(text: isCardView ? '' : 'AAPL - 2016'), series: >[ diff --git a/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart b/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart index a4e400d7..be52cbba 100644 --- a/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart +++ b/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart @@ -31,10 +31,11 @@ class _TrendLineDefaultState extends SampleViewState { 'Polynomial', 'MovingAverage' ].toList(); - String _selectedTrendLineType = 'Linear'; - TrendlineType _type = TrendlineType.linear; - int _polynomialOrder = 2; - int _period = 2; + late String _selectedTrendLineType; + late TrendlineType _type; + late int _polynomialOrder; + late int _period; + late TooltipBehavior _tooltipBehavior; @override void initState() { @@ -42,114 +43,98 @@ class _TrendLineDefaultState extends SampleViewState { _type = TrendlineType.linear; _polynomialOrder = 2; _period = 2; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } @override Widget build(BuildContext context) { - return _getTrendLineDefaultChart(); + return _buildTrendLineDefaultChart(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - children: [ - Text( - 'Trendline type', - style: TextStyle( - color: model.textColor, - fontSize: 16.0, - ), - ), - Container( - padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedTrendLineType, - items: _trendlineTypeList.map((String value) { - return DropdownMenuItem( - value: value ?? 'Linear', - child: Text('$value', - style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onTrendLineTypeChanged(value.toString()); - stateSetter(() {}); - }, - ), - ) - ], + ListTile( + title: Text('Trendline type', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.6 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedTrendLineType, + items: _trendlineTypeList.map((String value) { + return DropdownMenuItem( + value: value, + child: Text('$value', + style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onTrendLineTypeChanged(value.toString()); + stateSetter(() {}); + }, + ), ), ), Visibility( visible: _selectedTrendLineType != 'Polynomial' ? false : true, maintainState: true, - child: Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Polynomial Order', - style: TextStyle( - color: _selectedTrendLineType != 'Polynomial' - ? const Color.fromRGBO(0, 0, 0, 0.3) - : model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(37, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: 2, - maxValue: 6, - initialValue: _polynomialOrder.toDouble(), - onChanged: (double val) => setState(() { - _polynomialOrder = val.floor(); - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - ) - ], + child: ListTile( + title: Text('Polynomial Order', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + width: 0.6 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + minValue: 2, + maxValue: 6, + initialValue: _polynomialOrder.toDouble(), + onChanged: (double val) => setState(() { + _polynomialOrder = val.floor(); + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), ), ), ), Visibility( visible: _selectedTrendLineType != 'MovingAverage' ? false : true, maintainState: true, - child: Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Period', - style: TextStyle(color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(103, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: 2, - maxValue: periodMaxValue.toDouble(), - initialValue: _period.toDouble(), - onChanged: (double val) => setState(() { - _period = val.floor(); - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - ) - ], + child: ListTile( + title: Text('Period', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + width: 0.6 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + minValue: 2, + maxValue: periodMaxValue.toDouble(), + initialValue: _period.toDouble(), + onChanged: (double val) => setState(() { + _period = val.floor(); + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), ), ), ) @@ -159,7 +144,7 @@ class _TrendLineDefaultState extends SampleViewState { } /// Returns the column chart with defaul trendline types. - SfCartesianChart _getTrendLineDefaultChart() { + SfCartesianChart _buildTrendLineDefaultChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle( @@ -177,7 +162,7 @@ class _TrendLineDefaultState extends SampleViewState { labelFormat: '{value}', ), series: _getTrendLineDefaultSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart b/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart index ce330eb7..2d9fedb6 100644 --- a/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart +++ b/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart @@ -20,19 +20,21 @@ class TrendLineForecast extends SampleView { /// State class of the spline cahrt with trende forcasting. class _TrendLineForecastState extends SampleViewState { _TrendLineForecastState(); - double _backwardForecastValue = 0.0; - double _forwardForecastValue = 0.0; + late double _backwardForecastValue; + late double _forwardForecastValue; + late TooltipBehavior _tooltipBehavior; @override void initState() { _backwardForecastValue = 0.0; _forwardForecastValue = 0.0; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } @override Widget build(BuildContext context) { - return _getTrendLineForecastChart(); + return _buildTrendLineForecastChart(); } @override @@ -95,7 +97,7 @@ class _TrendLineForecastState extends SampleViewState { } /// Returns the spline chart with trendline forcating. - SfCartesianChart _getTrendLineForecastChart() { + SfCartesianChart _buildTrendLineForecastChart() { int j = 0; final List trendLineData = []; final List yValue = [ @@ -134,7 +136,7 @@ class _TrendLineForecastState extends SampleViewState { ? '' : 'Euro to USD yearly exchange rate - 1999 to 2019'), legend: Legend(isVisible: !isCardView), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0), interval: 2), primaryYAxis: NumericAxis( diff --git a/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart b/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart index 062b7c2f..ca4599e2 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/add_point_on_click.dart @@ -28,8 +28,8 @@ class _InteractiveChartState extends SampleViewState { ]; List scatterData = []; bool isLineExist = false; - ChartSeriesController seriesController; - List> chartSeries; + ChartSeriesController? seriesController; + // List> chartSeries; bool isSorting = false; bool isDataAdded = false; bool isScatterData = false; @@ -43,17 +43,17 @@ class _InteractiveChartState extends SampleViewState { @override Widget build(BuildContext context) { - final double bottomPadding = !model.isWeb ? 40 : 60; + final double bottomPadding = !model.isWebFullView ? 40 : 60; return Scaffold( backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, isCardView ? 0 : 15, 5, bottomPadding), child: Container( - child: _getInteractiveChart(), + child: _buildInteractiveChart(), )), floatingActionButton: SizedBox( - height: model.isWeb ? 45 : 40, + height: model.isWebFullView ? 45 : 40, width: 45, child: FloatingActionButton( onPressed: isResetVisible @@ -68,15 +68,15 @@ class _InteractiveChartState extends SampleViewState { isResetVisible = false; }) : null, - child: const Icon(Icons.refresh, color: Colors.white), backgroundColor: isResetVisible ? model.backgroundColor : Colors.grey[600], + child: const Icon(Icons.refresh, color: Colors.white), ), )); } /// Returns the cartesian chart with default tootlip. - SfCartesianChart _getInteractiveChart() { + SfCartesianChart _buildInteractiveChart() { return SfCartesianChart( margin: EdgeInsets.fromLTRB(10, 15, 10, 10), plotAreaBorderWidth: 0, @@ -106,7 +106,7 @@ class _InteractiveChartState extends SampleViewState { isResetVisible = true; final Offset value = Offset(args.position.dx, args.position.dy); CartesianChartPoint chartpoint; - chartpoint = seriesController.pixelToPoint(value); + chartpoint = seriesController!.pixelToPoint(value); chartData.add(ChartSampleData(x: chartpoint.x, y: chartpoint.y)); setState(() {}); }); diff --git a/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart b/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart new file mode 100644 index 00000000..9736b711 --- /dev/null +++ b/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart @@ -0,0 +1,156 @@ +/// Dart imports +import 'dart:async'; +import 'dart:math' as math; +import 'package:intl/intl.dart'; + +/// Package imports +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../model/sample_view.dart'; + +/// Renders the auto scrolling chart +class AutoScrollingChart extends SampleView { + /// Creates the auto scrolling chart + const AutoScrollingChart(Key key) : super(key: key); + + @override + _AutoScrollingChartState createState() => _AutoScrollingChartState(); +} + +class _AutoScrollingChartState extends SampleViewState { + _AutoScrollingChartState(); + + Timer? timer; + late List palette; + late List<_ChartData> chartData, chartDataTemp; + ChartSeriesController? _chartSeriesController; + + late bool isPointerMoved; + @override + void initState() { + _initializeVariables(); + super.initState(); + } + + @override + void dispose() { + timer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return _buildLiveLineChart(); + } + + void _initializeVariables() { + palette = const [ + Color.fromRGBO(75, 135, 185, 1), + Color.fromRGBO(192, 108, 132, 1), + Color.fromRGBO(246, 114, 128, 1), + Color.fromRGBO(248, 177, 149, 1), + Color.fromRGBO(116, 180, 155, 1), + Color.fromRGBO(0, 168, 181, 1), + Color.fromRGBO(73, 76, 162, 1), + Color.fromRGBO(255, 205, 96, 1), + Color.fromRGBO(255, 240, 219, 1), + Color.fromRGBO(238, 238, 238, 1) + ]; + isPointerMoved = false; + chartData = <_ChartData>[ + _ChartData(DateTime(2020, 01, 1, 00, 00, 00), 42, palette[0]), + _ChartData(DateTime(2020, 01, 1, 00, 00, 01), 47, palette[1]), + ]; + chartDataTemp = <_ChartData>[]; + timer = Timer.periodic(const Duration(milliseconds: 1000), (Timer timer) { + if (!isPointerMoved) { + if (chartDataTemp.isNotEmpty) { + chartData.addAll(chartDataTemp); + chartDataTemp.clear(); + } + setState(() { + chartData = _updateDataSource(); + }); + } else { + chartDataTemp = _updateTempDataSource(); + } + }); + } + + SfCartesianChart _buildLiveLineChart() { + return SfCartesianChart( + zoomPanBehavior: ZoomPanBehavior(enablePanning: true), + onChartTouchInteractionMove: (ChartTouchInteractionArgs args) { + isPointerMoved = true; + }, + onChartTouchInteractionUp: (ChartTouchInteractionArgs args) { + isPointerMoved = false; + }, + plotAreaBorderWidth: 0, + primaryXAxis: DateTimeAxis( + majorGridLines: MajorGridLines(width: 0), + dateFormat: DateFormat.Hms(), + intervalType: DateTimeIntervalType.seconds, + autoScrollingDelta: 10, + autoScrollingDeltaType: DateTimeIntervalType.seconds, + ), + primaryYAxis: NumericAxis( + axisLine: AxisLine(width: 0), + majorTickLines: MajorTickLines(size: 0)), + series: >[ + ColumnSeries<_ChartData, DateTime>( + onRendererCreated: (ChartSeriesController controller) { + _chartSeriesController = controller; + }, + dataSource: chartData, + color: const Color.fromRGBO(192, 108, 132, 1), + xValueMapper: (_ChartData data, _) => data.x, + yValueMapper: (_ChartData data, _) => data.y, + pointColorMapper: (_ChartData data, _) => data.color, + animationDuration: 0, + ) + ]); + } + + List<_ChartData> _updateDataSource() { + chartData.add(_ChartData( + chartData[chartData.length - 1].x.add(Duration(seconds: 1)), + _getRandomInt(30, 60), + palette[chartData.length % 10])); + _chartSeriesController?.updateDataSource( + addedDataIndexes: [chartData.length - 1], + ); + return chartData; + } + + List<_ChartData> _updateTempDataSource() { + chartDataTemp.add(_ChartData( + chartDataTemp.isEmpty + ? chartData[chartData.length - 1].x.add(Duration(seconds: 1)) + : chartDataTemp[chartDataTemp.length - 1] + .x + .add(Duration(seconds: 1)), + _getRandomInt(30, 60), + palette[(chartDataTemp.isEmpty + ? chartData.length + : chartData.length + chartDataTemp.length) % + 10])); + return chartDataTemp; + } + + int _getRandomInt(int min, int max) { + final math.Random _random = math.Random(); + return min + _random.nextInt(max - min); + } +} + +class _ChartData { + _ChartData(this.x, this.y, this.color); + final DateTime x; + final num y; + final Color color; +} diff --git a/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart b/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart index bbe27efc..5009aab0 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart @@ -24,12 +24,12 @@ class DefaultCrossHair extends SampleView { /// State class of the chart with crosshair. class _DefaultCrossHairState extends SampleViewState { _DefaultCrossHairState(); - bool alwaysShow = false; - double duration = 2; + late bool alwaysShow; + late double duration; final List _lineTypeList = ['both', 'vertical', 'horizontal'].toList(); - String _selectedLineType = 'both'; - CrosshairLineType _lineType = CrosshairLineType.both; + late String _selectedLineType; + late CrosshairLineType _lineType; List randomData = getDatatTimeData(); @override @@ -44,89 +44,76 @@ class _DefaultCrossHairState extends SampleViewState { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: model.isWeb || !isCardView ? 0 : 60), - child: getDefaultCrossHairChart()); + padding: EdgeInsets.only( + bottom: model.isWebFullView || !isCardView ? 0 : 60), + child: _buildDefaultCrossHairChart()); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - children: [ - Text('Line type ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(36, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: - Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedLineType, - items: _lineTypeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'both', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - onLineTypeChange(value); - stateSetter(() {}); - })), - ], - ), + ListTile( + title: Text('Line type', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedLineType, + items: _lineTypeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'both', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + onLineTypeChange(value); + stateSetter(() {}); + })), ), - Container( - child: Row( - children: [ - Text('Show always ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: alwaysShow, - onChanged: (bool value) { - setState(() { - alwaysShow = value; - stateSetter(() {}); - }); - })) - ], - ), - ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Hide delay ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(46, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 10, - initialValue: duration, - onChanged: (double val) => setState(() { - duration = val; - }), - step: 2, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], + ListTile( + title: Text('Show always', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.5 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: alwaysShow, + onChanged: (bool? value) { + setState(() { + alwaysShow = value!; + stateSetter(() {}); + }); + }))), + ListTile( + title: + Text('Hide delay ', style: TextStyle(color: model.textColor)), + trailing: Container( + width: 0.5 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 10, + initialValue: duration, + onChanged: (double val) => setState(() { + duration = val; + }), + step: 2, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), ], @@ -135,8 +122,8 @@ class _DefaultCrossHairState extends SampleViewState { } /// Returns the cartesian chart with crosshair. - SfCartesianChart getDefaultCrossHairChart() { - _lineType = _lineType ?? CrosshairLineType.both; + SfCartesianChart _buildDefaultCrossHairChart() { + _lineType = _lineType; return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: DateTimeAxis( @@ -152,10 +139,10 @@ class _DefaultCrossHairState extends SampleViewState { /// To enable the cross hair for cartesian chart. crosshairBehavior: CrosshairBehavior( enable: true, - hideDelay: (duration ?? 2.0) * 1000, + hideDelay: (duration) * 1000, lineWidth: 1, activationMode: ActivationMode.singleTap, - shouldAlwaysShow: alwaysShow ?? true, + shouldAlwaysShow: alwaysShow, lineType: _lineType), primaryYAxis: NumericAxis( axisLine: AxisLine(width: 0), diff --git a/lib/samples/chart/cartesian_charts/user_interactions/events/events.dart b/lib/samples/chart/cartesian_charts/user_interactions/events/events.dart index b47adcc8..9e38523d 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/events/events.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/events/events.dart @@ -24,6 +24,16 @@ class _EventsState extends SampleViewState { _EventsState(); List actionsList = []; final GlobalKey consoleKey = GlobalKey(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + animationDuration: 0, + canShowMarker: false, + enable: true, + ); + super.initState(); + } @override Widget build(BuildContext context) { @@ -32,7 +42,7 @@ class _EventsState extends SampleViewState { ? Column(children: [ Expanded( flex: 6, - child: _getDefaultEventChart(), + child: _buildDefaultEventChart(), ), isCardView ? Container() @@ -55,14 +65,14 @@ class _EventsState extends SampleViewState { padding: EdgeInsets.fromLTRB( 10, 0, 0, 0), child: Align( + alignment: + Alignment.centerLeft, child: Text( 'Event Trace', style: TextStyle( fontWeight: FontWeight.bold), - ), - alignment: - Alignment.centerLeft))), + )))), Expanded( child: Align( alignment: Alignment.centerRight, @@ -71,11 +81,8 @@ class _EventsState extends SampleViewState { icon: Icon(Icons.close), onPressed: () { actionsList.clear(); - (consoleKey.currentWidget - as Console) - .actionsList; consoleKey.currentState - .setState(() {}); + ?.setState(() {}); }, ))), ], @@ -92,7 +99,7 @@ class _EventsState extends SampleViewState { : Row(children: [ Expanded( flex: 6, - child: _getDefaultEventChart(), + child: _buildDefaultEventChart(), ), isCardView ? Container() @@ -115,14 +122,14 @@ class _EventsState extends SampleViewState { padding: EdgeInsets.fromLTRB( 10, 0, 0, 0), child: Align( - child: Text( - 'Event Trace', - style: TextStyle( - fontWeight: - FontWeight.bold), - ), - alignment: - Alignment.centerLeft))), + alignment: Alignment.centerLeft, + child: Text( + 'Event Trace', + style: TextStyle( + fontWeight: + FontWeight.bold), + ), + ))), Expanded( child: Align( alignment: Alignment.centerRight, @@ -131,13 +138,8 @@ class _EventsState extends SampleViewState { icon: Icon(Icons.close), onPressed: () { actionsList.clear(); - (consoleKey.currentWidget - as Console) - .actionsList; - // _scrollController.jumpTo(0.0); - // setState(() {}); consoleKey.currentState - .setState(() {}); + ?.setState(() {}); }, ))), ], @@ -154,48 +156,49 @@ class _EventsState extends SampleViewState { } /// Get default column chart - SfCartesianChart _getDefaultEventChart() { + SfCartesianChart _buildDefaultEventChart() { return SfCartesianChart( - onAxisLabelRender: (AxisLabelRenderArgs args) { + axisLabelFormatter: (AxisLabelRenderDetails details) { if (!isCardView) { - actionsList.insert(0, 'Axis label (${args.text}) was rendered'); + actionsList.insert(0, 'Axis label (${details.text}) was rendered'); } + return ChartAxisLabel(details.text, null); }, onAxisLabelTapped: (AxisLabelTapArgs args) { if (!isCardView) { actionsList.insert(0, 'Axis label (${args.text}) was tapped'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onDataLabelTapped: (DataLabelTapDetails args) { if (!isCardView) { actionsList.insert(0, 'Data label (${args.text}) was tapped'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onPointTapped: (PointTapArgs args) { if (!isCardView) { actionsList.insert( 0, 'Point (${args.pointIndex.toString()}) was tapped'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onChartTouchInteractionDown: (ChartTouchInteractionArgs args) { if (!isCardView) { actionsList.insert(0, 'Chart was tapped down'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onChartTouchInteractionMove: (ChartTouchInteractionArgs args) { if (!isCardView) { actionsList.insert(0, 'Moved on chart area'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onLegendTapped: (LegendTapArgs args) { if (!isCardView) { actionsList.insert(0, 'Legend was tapped'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onMarkerRender: (MarkerRenderArgs args) { @@ -203,8 +206,8 @@ class _EventsState extends SampleViewState { actionsList.insert( 0, 'Marker (${args.pointIndex.toString()}) was rendered'); if (args.pointIndex == 5) { - SchedulerBinding.instance.addPostFrameCallback((_) { - (consoleKey.currentState as _ConsoleState).setState(() {}); + SchedulerBinding.instance?.addPostFrameCallback((_) { + (consoleKey.currentState)?.setState(() {}); }); } } @@ -212,15 +215,15 @@ class _EventsState extends SampleViewState { onTooltipRender: (TooltipArgs args) { if (!isCardView) { actionsList.insert(0, 'Tooltip (${args.text}) is showing'); - SchedulerBinding.instance.addPostFrameCallback((_) { - (consoleKey.currentState as _ConsoleState).setState(() {}); + SchedulerBinding.instance?.addPostFrameCallback((_) { + (consoleKey.currentState)?.setState(() {}); }); } }, onChartTouchInteractionUp: (ChartTouchInteractionArgs args) { if (!isCardView) { actionsList.insert(0, 'Chart was tapped up'); - (consoleKey.currentState as _ConsoleState).setState(() {}); + (consoleKey.currentState)?.setState(() {}); } }, onLegendItemRender: (LegendRenderArgs args) { @@ -248,11 +251,7 @@ class _EventsState extends SampleViewState { legend: Legend( isVisible: isCardView ? false : true, position: LegendPosition.bottom), - tooltipBehavior: TooltipBehavior( - animationDuration: 0, - canShowMarker: false, - enable: true, - ), + tooltipBehavior: _tooltipBehavior, ); } @@ -280,10 +279,12 @@ class _EventsState extends SampleViewState { } } -class CustomColumnSeriesRenderer extends ColumnSeriesRenderer {} - +/// Renders the console for evets class Console extends StatefulWidget { + /// Creates the console for events Console(this.actionsList, Key consoleKey) : super(key: consoleKey); + + /// collections of actions performed final List actionsList; @override _ConsoleState createState() => _ConsoleState(); @@ -302,8 +303,11 @@ class _ConsoleState extends State { setState(() {}); } + @override Widget build(BuildContext context) { return Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.withOpacity(0.4))), child: Padding( padding: EdgeInsets.all(5), child: ListView.separated( @@ -320,8 +324,6 @@ class _ConsoleState extends State { ); }, )), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey.withOpacity(0.4))), ); } } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart b/lib/samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart index 1cc357ed..ecb0c298 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/events/navigation_with_events.dart @@ -27,9 +27,13 @@ class _NavigationWithEventsState extends SampleViewState { double _xLabelsExtent = 20; bool _isEnableLabelExtend = false; bool _isEnableMaximumLabelWidth = true; - List _isSelected; + late List _isSelected; + late TooltipBehavior _tooltipBehavior; String _selectedType = 'Maximum label width'; - List _typeList = ['Maximum label width', 'Labels extent']; + final List _typeList = [ + 'Maximum label width', + 'Labels extent' + ]; final List _chartData = [ ChartSampleData(x: 'Goldin\nFinance 117', y: 597), ChartSampleData(x: 'Ping An\nFinance Center', y: 599), @@ -37,20 +41,27 @@ class _NavigationWithEventsState extends SampleViewState { ChartSampleData(x: 'Shanghai\nTower', y: 632), ChartSampleData(x: 'Burj\nKhalifa', y: 828) ]; - GlobalKey _scaffoldKey = GlobalKey(); + final GlobalKey _scaffoldKey = + GlobalKey(); @override void initState() { _isSelected = [true, false]; + _tooltipBehavior = TooltipBehavior( + enable: true, + canShowMarker: false, + header: '', + activationMode: ActivationMode.longPress); super.initState(); } @override Widget build(BuildContext context) { - return Scaffold( + return ScaffoldMessenger( key: _scaffoldKey, - backgroundColor: model.cardThemeColor, - body: _getmaximumLabelWidthChart()); + child: Scaffold( + backgroundColor: model.cardThemeColor, + body: _buildmaximumLabelWidthChart())); } @override @@ -64,19 +75,6 @@ class _NavigationWithEventsState extends SampleViewState { alignment: Alignment.center, child: ToggleButtons( constraints: BoxConstraints(maxWidth: 150, minHeight: 40), - children: [ - Padding( - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - child: Text( - 'Maximum label \nwidth', - textAlign: TextAlign.center, - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - child: Text('Labels extent', textAlign: TextAlign.center), - ) - ], onPressed: (int index) { setState(() { for (int buttonIndex = 0; @@ -90,6 +88,19 @@ class _NavigationWithEventsState extends SampleViewState { }); }, isSelected: _isSelected, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + child: Text( + 'Maximum label \nwidth', + textAlign: TextAlign.center, + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + child: Text('Labels extent', textAlign: TextAlign.center), + ) + ], )), Padding( padding: EdgeInsets.fromLTRB(0, 10, 0, 0), @@ -164,7 +175,7 @@ class _NavigationWithEventsState extends SampleViewState { } /// Returns the Cartesian chart with sorting options. - SfCartesianChart _getmaximumLabelWidthChart() { + SfCartesianChart _buildmaximumLabelWidthChart() { return SfCartesianChart( title: ChartTitle(text: isCardView ? '' : "World's tallest buildings"), plotAreaBorderWidth: 0, @@ -172,14 +183,14 @@ class _NavigationWithEventsState extends SampleViewState { args.text = args.dataPoints[args.pointIndex].y.toString() + ' m'; }, onTooltipRender: (TooltipArgs args) { - args.text = args.dataPoints[args.pointIndex].x.toString() + + args.text = args.dataPoints![args.pointIndex!.toInt()].x.toString() + ' : ' + - args.dataPoints[args.pointIndex].y.toString() + + args.dataPoints![args.pointIndex!.toInt()].y.toString() + ' m'; }, onDataLabelTapped: (DataLabelTapDetails args) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - width: model.isWeb + _scaffoldKey.currentState?.showSnackBar(SnackBar( + width: model.isWebFullView ? _measureText( 'Data label tapped/clicked. Navigating to the link.') .width @@ -188,13 +199,13 @@ class _NavigationWithEventsState extends SampleViewState { shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 2000), - content: Text("Data label tapped/clicked. Navigating to the link."), + content: Text('Data label tapped/clicked. Navigating to the link.'), )); launchHyperLink(args.text); }, onAxisLabelTapped: (AxisLabelTapArgs args) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - width: model.isWeb + _scaffoldKey.currentState?.showSnackBar(SnackBar( + width: model.isWebFullView ? _measureText( 'Axis label tapped/clicked. Navigating to the link.') .width @@ -203,13 +214,13 @@ class _NavigationWithEventsState extends SampleViewState { shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 2000), - content: Text("Axis label tapped/clicked. Navigating to the link."), + content: Text('Axis label tapped/clicked. Navigating to the link.'), )); launchHyperLink(args.value.toString()); }, onPointTapped: (PointTapArgs args) { - _scaffoldKey.currentState.showSnackBar(SnackBar( - width: model.isWeb + _scaffoldKey.currentState?.showSnackBar(SnackBar( + width: model.isWebFullView ? _measureText( 'Data point tapped/clicked. Navigating to the link.') .width @@ -218,7 +229,7 @@ class _NavigationWithEventsState extends SampleViewState { shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 2000), - content: Text("Data point tapped/clicked. Navigating to the link."), + content: Text('Data point tapped/clicked. Navigating to the link.'), )); launchHyperLink(args.pointIndex.toString()); }, @@ -235,11 +246,7 @@ class _NavigationWithEventsState extends SampleViewState { axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)), series: _getDefaultSortingSeries(), - tooltipBehavior: TooltipBehavior( - enable: true, - canShowMarker: false, - header: '', - activationMode: ActivationMode.longPress), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/pagination.dart b/lib/samples/chart/cartesian_charts/user_interactions/pagination.dart new file mode 100644 index 00000000..4efffc1a --- /dev/null +++ b/lib/samples/chart/cartesian_charts/user_interactions/pagination.dart @@ -0,0 +1,330 @@ +import 'dart:ui'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import '../../../../model/sample_view.dart'; + +/// Renders the pagination sample +class Pagination extends SampleView { + /// Creates the pagination chart + const Pagination(Key key) : super(key: key); + + @override + _PaginationState createState() => _PaginationState(); +} + +class _PaginationState extends SampleViewState { + late double height, width, _segmentedControlWidth; + late double _containerWidth, _containerHeight; + double? diff; + int segmentedControlGroupValue = 0; + int degree = 25; + String day = 'Friday, 01:00 am'; + String _imageName = 'images/sunny_image.png'; + double _visibleMin = 0; + double _visibleMax = 5; + final List _daysWithTime = const [ + 'Friday, 01:00 am', + 'Saturday, 01:00 am', + 'Sunday, 01:00 am', + 'Monday, 01:00 am', + 'Tuesday, 01:00 am' + ]; + final List _temperatue = const [ + '25°19°', + '25°20°', + '24°18°', + '19°14°', + '18°14°' + ]; + final List _images = const [ + 'sunny_image.png', + 'sunny_image.png', + 'cloudy.png', + 'cloudy.png', + 'rainy.png' + ]; + final List _days = const ['Fri', 'Sat', 'Sun', 'Mon', 'Tue']; + final List _minValues = const [0, 6, 12, 18, 24]; + final List _maxValues = const [5, 11, 17, 23, 29]; + final List _degrees = const [25, 25, 24, 19, 18]; + + List chartData = [ + ChartSampleData(xValue: '0', x: '1 am', y: 20), + ChartSampleData(xValue: '1', x: '4 am', y: 20), + ChartSampleData(xValue: '2', x: '7 am', y: 20), + ChartSampleData(xValue: '3', x: '10 am', y: 21), + ChartSampleData(xValue: '4', x: '1 pm', y: 21), + ChartSampleData(xValue: '5', x: '4 pm', y: 24), + ChartSampleData(xValue: '6', x: '1 am', y: 19), + ChartSampleData(xValue: '7', x: '4 am', y: 20), + ChartSampleData(xValue: '8', x: '7 am', y: 20), + ChartSampleData(xValue: '9', x: '10 am', y: 21), + ChartSampleData(xValue: '10', x: '1 pm', y: 24), + ChartSampleData(xValue: '11', x: '4 pm', y: 24), + ChartSampleData(xValue: '12', x: '1 am', y: 21), + ChartSampleData(xValue: '13', x: '4 am', y: 21), + ChartSampleData(xValue: '14', x: '7 am', y: 21), + ChartSampleData(xValue: '15', x: '10 am', y: 22), + ChartSampleData(xValue: '16', x: '1 pm', y: 23), + ChartSampleData(xValue: '17', x: '4 pm', y: 24), + ChartSampleData(xValue: '18', x: '1 am', y: 20), + ChartSampleData(xValue: '19', x: '4 am', y: 19), + ChartSampleData(xValue: '20', x: '7 am', y: 19), + ChartSampleData(xValue: '21', x: '10 am', y: 18), + ChartSampleData(xValue: '22', x: '1 pm', y: 19), + ChartSampleData(xValue: '23', x: '4 pm', y: 19), + ChartSampleData(xValue: '24', x: '1 am', y: 16), + ChartSampleData(xValue: '25', x: '4 am', y: 15), + ChartSampleData(xValue: '26', x: '7 am', y: 14), + ChartSampleData(xValue: '27', x: '10 am', y: 15), + ChartSampleData(xValue: '28', x: '1 pm', y: 16), + ChartSampleData(xValue: '29', x: '4 pm', y: 18), + ]; + + @override + Widget build(BuildContext context) { + width = MediaQuery.of(context).size.width; + final Orientation orientation = MediaQuery.of(context).orientation; + _segmentedControlWidth = width > 500 + ? model.isWebFullView + ? width * 0.5 + : width * 0.7 + : double.infinity; + height = MediaQuery.of(context).size.height; + _calculateHeight(); + _containerHeight = 30; + return Center( + child: Column(children: [ + Container( + width: _segmentedControlWidth, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row(children: [ + Container( + margin: EdgeInsets.only(left: 5), + height: height * 0.085, + width: model.isWebFullView ? 50 : width * 0.08, + decoration: BoxDecoration( + image: + DecorationImage(image: ExactAssetImage(_imageName)))), + Container( + height: height * 0.1, + child: Row(children: [ + Container( + child: Text('$degree', + style: TextStyle( + fontSize: orientation == Orientation.landscape + ? height * 0.08 + : height * 0.06))), + Container( + padding: EdgeInsets.only(right: 30), + child: Text('°C | °F', style: TextStyle(fontSize: 16))), + ])) + ]), + Container( + margin: EdgeInsets.fromLTRB(0, 0, 8, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text('USA, Texas', + style: TextStyle(fontSize: height * 0.045)), + Text(day, style: TextStyle(fontSize: height * 0.025)), + ])) + ], + ), + ), + Expanded( + child: Container( + alignment: Alignment.center, + width: _segmentedControlWidth, + child: _buildCartesianChart())), + Visibility( + visible: height < 350 ? false : true, + child: Container( + padding: model.isWebFullView + ? EdgeInsets.fromLTRB(0, 16, 0, 16) + : EdgeInsets.fromLTRB(0, 8, 0, 8), + width: _segmentedControlWidth, + child: CupertinoSlidingSegmentedControl( + groupValue: segmentedControlGroupValue, + children: _getButtons(orientation), + onValueChanged: (int? i) => _loadGroupValue(i!)))) + ])); + } + + /// Method to calculate widget height + void _calculateHeight() { + height = !model.isWebFullView ? height - 46 : height; + height = model.isWebFullView && !kIsWeb ? height * 0.6 : height; + if (kIsWeb && + model.webOutputContainerState != null && + model.webOutputContainerState.outputScaffoldKey != null && + (model.webOutputContainerState.outputScaffoldKey) + .currentContext + ?.size != + null) { + height = (model.webOutputContainerState.outputScaffoldKey) + .currentContext! + .size! + .height; + + if (diff == null) { + diff = MediaQuery.of(context).size.height - height; + } else { + height = MediaQuery.of(context).size.height - diff!; + } + } + } + + /// Returns the item of segmented control + Map _getButtons(Orientation _orientation) { + _containerWidth = _segmentedControlWidth == double.infinity + ? width / 5 + : _segmentedControlWidth / 5; + final Color color = model.currentThemeData?.brightness == Brightness.light + ? const Color.fromRGBO(104, 104, 104, 1) + : const Color.fromRGBO(242, 242, 242, 1); + final ButtonStyle style = ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith(getColor), + ); + final Map buttons = {}; + for (int i = 0; i <= 4; i++) { + buttons.putIfAbsent( + i, + () => Container( + width: _containerWidth, + child: TextButton( + onPressed: () => _loadGroupValue(i), + style: style, + child: Column( + children: [ + Text(_days[i], + style: TextStyle(fontSize: 12, color: color)), + _getContainer('images/' + _images[i]), + Text(_temperatue[i], + style: TextStyle(fontSize: 12, color: color)), + ], + ))), + ); + } + + return buttons; + } + + /// Return the image container + Container _getContainer(String imageName) { + return Container( + height: _containerHeight, + margin: EdgeInsets.fromLTRB(0, 4, 0, 4), + decoration: BoxDecoration( + image: DecorationImage( + image: ExactAssetImage(imageName), + ), + ), + ); + } + + /// Returns color for the button based on interaction performed + Color? getColor(Set states) { + if (states.contains(MaterialState.hovered)) { + return model.currentThemeData?.brightness == Brightness.light + ? Color.fromRGBO(235, 235, 235, 1) + : Color.fromRGBO(104, 104, 104, 1); + } else if (states.contains(MaterialState.focused) || + states.contains(MaterialState.pressed)) { + return Color.fromRGBO(224, 224, 224, 1); + } else { + return null; + } + } + + /// Calls while performing the swipe operation + void performSwipe(ChartSwipeDirection direction) { + int? index; + if (_visibleMin == 0 && _visibleMax == 5) { + index = direction == ChartSwipeDirection.end ? 1 : null; + } else if (_visibleMin == 6 && _visibleMax == 11) { + index = direction == ChartSwipeDirection.end ? 2 : 0; + } else if (_visibleMin == 12 && _visibleMax == 17) { + index = direction == ChartSwipeDirection.end ? 3 : 1; + } else if (_visibleMin == 18 && _visibleMax == 23) { + index = direction == ChartSwipeDirection.end ? 4 : 2; + } else if (_visibleMin == 24 && _visibleMax == 29) { + index = direction == ChartSwipeDirection.end ? null : 3; + } + + if (index != null) { + _loadGroupValue(index); + } + } + + /// load the values based on the provided index + void _loadGroupValue(int index) { + setState(() { + _visibleMin = _minValues[index]; + _visibleMax = _maxValues[index]; + segmentedControlGroupValue = index; + degree = _degrees[index]; + day = _daysWithTime[index]; + _imageName = 'images/' + _images[index]; + }); + } + + /// Returns the cartesian chart + SfCartesianChart _buildCartesianChart() { + return SfCartesianChart( + axisLabelFormatter: (AxisLabelRenderDetails details) { + if (details.orientation == AxisOrientation.horizontal) { + for (final ChartSampleData sampleData in chartData) { + if (sampleData.xValue == details.actualText) { + return ChartAxisLabel(sampleData.x, details.textStyle); + } + } + } + return ChartAxisLabel(details.text, details.textStyle); + }, + primaryYAxis: NumericAxis( + interval: 2, + minimum: 0, + maximum: 26, + isVisible: false, + anchorRangeToVisiblePoints: true, + axisLine: AxisLine(width: 0), + majorTickLines: MajorTickLines(color: Colors.transparent), + ), + primaryXAxis: CategoryAxis( + visibleMaximum: _visibleMax, + visibleMinimum: _visibleMin, + labelPlacement: LabelPlacement.onTicks, + interval: 1, + axisLine: AxisLine(width: 0, color: Colors.transparent), + edgeLabelPlacement: EdgeLabelPlacement.shift, + majorGridLines: MajorGridLines(width: 0)), + plotAreaBorderWidth: 0, + series: getSeries(), + onPlotAreaSwipe: (direction) => performSwipe(direction), + ); + } + + /// Returns the chart series + List> getSeries() { + return >[ + SplineAreaSeries( + dataSource: chartData, + borderColor: Color.fromRGBO(255, 204, 5, 1), + borderWidth: 2, + color: Color.fromRGBO(255, 245, 211, 1), + dataLabelSettings: DataLabelSettings( + isVisible: true, labelAlignment: ChartDataLabelAlignment.outer), + xValueMapper: (ChartSampleData sales, _) => sales.xValue, + yValueMapper: (ChartSampleData sales, _) => sales.y, + ), + ]; + } +} diff --git a/lib/samples/chart/cartesian_charts/user_interactions/selection/dynamic_selection.dart b/lib/samples/chart/cartesian_charts/user_interactions/selection/dynamic_selection.dart index d4d79909..2976b693 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/selection/dynamic_selection.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/selection/dynamic_selection.dart @@ -24,12 +24,14 @@ class _DefaultSelectionState extends SampleViewState { final List _seriesIndexList = ['0', '1', '2'].toList(); final List _pointIndexList = ['0', '1', '2', '3', '4'].toList(); - int _seriesIndex; - int _pointIndex; - SelectionBehavior _selectionBehavior; + late int _seriesIndex; + late int _pointIndex; + late SelectionBehavior _selectionBehavior; @override void initState() { + _selectionBehavior = + SelectionBehavior(enable: true, unselectedOpacity: 0.5); _seriesIndex = 0; _pointIndex = 0; super.initState(); @@ -37,10 +39,7 @@ class _DefaultSelectionState extends SampleViewState { @override Widget build(BuildContext context) { - _selectionBehavior = - SelectionBehavior(enable: true, unselectedOpacity: 0.5); - - return _getDefaultSelectionChart(); + return _buildDefaultSelectionChart(); } @override @@ -109,8 +108,11 @@ class _DefaultSelectionState extends SampleViewState { Container( child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 25, 0), - child: RaisedButton( - color: model.backgroundColor, + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + ), onPressed: () { selection(_seriesIndex, _pointIndex); }, @@ -125,7 +127,7 @@ class _DefaultSelectionState extends SampleViewState { } /// Returns the cartesian chart with default selection. - SfCartesianChart _getDefaultSelectionChart() { + SfCartesianChart _buildDefaultSelectionChart() { return SfCartesianChart( onSelectionChanged: (SelectionArgs args) { setState(() { diff --git a/lib/samples/chart/cartesian_charts/user_interactions/selection/selection_modes.dart b/lib/samples/chart/cartesian_charts/user_interactions/selection/selection_modes.dart index 2d5d28f2..4f999527 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/selection/selection_modes.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/selection/selection_modes.dart @@ -19,90 +19,90 @@ class DefaultSelection extends SampleView { /// State class of the chart with default selection. class _DefaultSelectionState extends SampleViewState { _DefaultSelectionState(); - bool _enableMultiSelect = false; + late bool _enableMultiSelect; final List _modeList = ['point', 'series', 'cluster'].toList(); - String _selectedMode = 'point'; - SelectionBehavior _selectionBehavior; - SelectionType _mode = SelectionType.point; + late String _selectedMode; + late SelectionBehavior _selectionBehavior; + late SelectionType _mode; @override void initState() { _selectedMode = 'point'; _mode = SelectionType.point; _enableMultiSelect = false; + _selectionBehavior = + SelectionBehavior(enable: true, unselectedOpacity: 0.5); super.initState(); } @override Widget build(BuildContext context) { - _selectionBehavior = - SelectionBehavior(enable: true, unselectedOpacity: 0.5); - - return _getDefaultSelectionChart(); + return _buildDefaultSelectionChart(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - children: [ - Text('Mode ', - style: TextStyle(color: model.textColor, fontSize: 16)), - Container( - padding: const EdgeInsets.fromLTRB(145, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'point', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onModeTypeChange(value); - stateSetter(() {}); - }), - ), - ], - ), - ), - Container( - child: Row( - children: [ - Text('Enable multi-selection', - style: TextStyle(color: model.textColor, fontSize: 16)), - Container( - width: 75, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _enableMultiSelect, - onChanged: (bool value) { - setState(() { - _enableMultiSelect = value; - stateSetter(() {}); - }); - })) - ], - ), - ), + ListTile( + title: Text('Mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + isExpanded: true, + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'point', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onModeTypeChange(value); + stateSetter(() {}); + }), + )), + ListTile( + title: Text('Enable multi-selection', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.4 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: _enableMultiSelect, + onChanged: (bool? value) { + setState(() { + _enableMultiSelect = value!; + stateSetter(() {}); + }); + }))), ], ); }); } /// Returns the cartesian chart with default selection. - SfCartesianChart _getDefaultSelectionChart() { + SfCartesianChart _buildDefaultSelectionChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: !isCardView ? 'Age distribution by country' : ''), diff --git a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/default_tooltip.dart b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/default_tooltip.dart index 1deb34fb..57b9da9b 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/default_tooltip.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/default_tooltip.dart @@ -22,11 +22,11 @@ class _DefaultTooltipState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultTooltipChart(); + return _buildDefaultTooltipChart(); } /// Returns the cartesian chart with default tootlip. - SfCartesianChart _getDefaultTooltipChart() { + SfCartesianChart _buildDefaultTooltipChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Labour force'), diff --git a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_position.dart b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_position.dart index 93fdb293..c58baa62 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_position.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_position.dart @@ -33,7 +33,7 @@ class _TooltipPositionState extends SampleViewState { @override Widget build(BuildContext context) { - return _getCartesianTooltipPositionChart(); + return _buildCartesianTooltipPositionChart(); } @override @@ -78,7 +78,7 @@ class _TooltipPositionState extends SampleViewState { } /// Returns the cartesian chart with tooltip position option. - SfCartesianChart _getCartesianTooltipPositionChart() { + SfCartesianChart _buildCartesianTooltipPositionChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Age distribution'), @@ -154,5 +154,5 @@ class _ChartData { _ChartData(this.x, this.y1, [this.color]); final String x; final double y1; - final Color color; + final Color? color; } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_template.dart b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_template.dart index 68b2af17..a915cfcb 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_template.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/tooltip/tooltip_template.dart @@ -19,13 +19,49 @@ class TooltipTemplate extends SampleView { /// State class of the chart with various marker shapes. class _TooltipTemplateState extends SampleViewState { _TooltipTemplateState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = TooltipBehavior( + enable: true, + color: Colors.grey[400], + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + return Container( + alignment: Alignment.center, + height: 40, + width: 70, + decoration: BoxDecoration( + color: Colors.grey[400], + borderRadius: BorderRadius.all(Radius.circular(6.0)), + ), + child: Padding( + padding: EdgeInsets.fromLTRB(4, 0, 0, 0), + child: Row(children: [ + SizedBox( + height: 30, + width: 35, + child: Image.asset(_getImageTemplate(pointIndex)), + ), + Text( + (data.y.toString() + '%'), + style: TextStyle(fontSize: 12, color: Colors.black), + textScaleFactor: 1.0, + ), + ]))); + }); + + super.initState(); + } + @override Widget build(BuildContext context) { - return _getTooltipTemplateChart(); + return _buildTooltipTemplateChart(); } /// Returns the chart with various marker shapes. - SfCartesianChart _getTooltipTemplateChart() { + SfCartesianChart _buildTooltipTemplateChart() { return SfCartesianChart( title: ChartTitle( text: isCardView @@ -40,41 +76,14 @@ class _TooltipTemplateState extends SampleViewState { interval: 20, maximum: isCardView ? 120 : 100, majorTickLines: MajorTickLines(size: 0)), - tooltipBehavior: TooltipBehavior( - enable: true, - color: Colors.grey[400], - builder: (dynamic data, dynamic point, dynamic series, int pointIndex, - int seriesIndex) { - return Container( - alignment: Alignment.center, - height: 40, - width: 70, - decoration: BoxDecoration( - color: Colors.grey[400], - borderRadius: BorderRadius.all(Radius.circular(6.0)), - ), - child: Padding( - padding: EdgeInsets.fromLTRB(4, 0, 0, 0), - child: Row(children: [ - SizedBox( - child: Image.asset(_getImageTemplate(pointIndex)), - height: 30, - width: 35, - ), - Text( - (data.y.toString() + '%'), - style: TextStyle(fontSize: 12, color: Colors.black), - textScaleFactor: 1.0, - ), - ]))); - }), + tooltipBehavior: _tooltipBehavior, series: _getMarkeSeries(), ); } //ignore: unused_element - Color _getTooltipBorderColor(int pointIndex) { - Color color; + Color? _getTooltipBorderColor(int pointIndex) { + Color? color; if (pointIndex == 0) { color = Color.fromRGBO(192, 33, 39, 1); } else if (pointIndex == 1) { @@ -122,7 +131,6 @@ class _TooltipTemplateState extends SampleViewState { ChartSampleData( x: 'Instagram', y: 63, - // pointColor: gradientColors, ), ChartSampleData( x: 'Snapchat', @@ -151,7 +159,7 @@ class _TooltipTemplateState extends SampleViewState { } String _getImageTemplate(int pointIndex) { - String path = (pointIndex == 0 + final String path = (pointIndex == 0 ? 'images/youtube.png' : (pointIndex == 1 ? 'images/maps_twitter.png' @@ -175,23 +183,24 @@ class _CustomColumnSeriesRenderer extends ColumnSeriesRenderer { class _ColumnCustomPainter extends ColumnSegment { @override - int get currentSegmentIndex => super.currentSegmentIndex; + int get currentSegmentIndex => super.currentSegmentIndex!; @override void onPaint(Canvas canvas) { - Paint myPaint = fillPaint; - if (currentSegmentIndex == 0) + Paint? myPaint = fillPaint; + if (currentSegmentIndex == 0) { myPaint = Paint()..color = Color.fromRGBO(192, 33, 39, 1); - else if (currentSegmentIndex == 1) + } else if (currentSegmentIndex == 1) { myPaint = Paint()..color = const Color.fromRGBO(26, 157, 235, 1); - else if (currentSegmentIndex == 2) + } else if (currentSegmentIndex == 2) { myPaint = fillPaint; - else if (currentSegmentIndex == 3) + } else if (currentSegmentIndex == 3) { myPaint = Paint()..color = const Color.fromRGBO(254, 250, 55, 1); - else if (currentSegmentIndex == 4) + } else if (currentSegmentIndex == 4) { myPaint = Paint()..color = const Color.fromRGBO(60, 92, 156, 1); + } final Rect rect = Rect.fromLTRB(segmentRect.left, segmentRect.top, segmentRect.right * animationFactor, segmentRect.bottom); - canvas.drawRect(rect, myPaint); + canvas.drawRect(rect, myPaint!); } } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart b/lib/samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart index 0f838246..14ad1e20 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/trackball/chart_with_trackball.dart @@ -21,24 +21,26 @@ class DefaultTrackball extends SampleView { /// State class the chart with default trackball. class _DefaultTrackballState extends SampleViewState { _DefaultTrackballState(); - double duration = 2; - bool showAlways = false; + late double duration; + late bool showAlways; + late bool canShowMarker; final List _modeList = ['floatAllPoints', 'groupAllPoints', 'nearestPoint'].toList(); - String _selectedMode = 'floatAllPoints'; + late String _selectedMode; - TrackballDisplayMode _mode = TrackballDisplayMode.floatAllPoints; + late TrackballDisplayMode _mode; final List _alignmentList = ['center', 'far', 'near'].toList(); - String _tooltipAlignment = 'center'; - bool _showMarker; + late String _tooltipAlignment; + late bool _showMarker; ChartAlignment _alignment = ChartAlignment.center; @override void initState() { duration = 2; showAlways = false; + canShowMarker = true; _selectedMode = 'floatAllPoints'; _mode = TrackballDisplayMode.floatAllPoints; _tooltipAlignment = 'center'; @@ -48,11 +50,13 @@ class _DefaultTrackballState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultTrackballChart(); + return _buildDefaultTrackballChart(); } @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( @@ -66,147 +70,145 @@ class _DefaultTrackballState extends SampleViewState { shrinkWrap: true, physics: const ClampingScrollPhysics(), children: [ - Container( - child: Row( - children: [ - Text('Mode ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(100, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container( - color: Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: - (value != null) ? value : 'point', - child: Text('$value', - style: TextStyle( - color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - setState(() { - onModeTypeChange(value); - stateSetter(() {}); - }); - }), - ), - ], + ListTile( + title: Text('Mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.6 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container( + color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'point', + child: Text('$value', + style: + TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + setState(() { + onModeTypeChange(value); + stateSetter(() {}); + }); + }), ), ), - Container( - child: Row( - children: [ - Text('Alignment', - style: TextStyle( - color: _selectedMode != 'groupAllPoints' - ? const Color.fromRGBO(0, 0, 0, 0.3) - : model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(70, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container( - color: Color(0xFFBDBDBD), height: 1), - value: _tooltipAlignment, - items: _selectedMode != 'groupAllPoints' - ? null - : _alignmentList.map((String value) { - return DropdownMenuItem( - value: (value != null) - ? value - : 'center', - child: Text('$value', - style: TextStyle( - color: - model.textColor))); - }).toList(), - onChanged: (dynamic value) { - onAlignmentChange(value); - stateSetter(() {}); - })), - ], - ), + ListTile( + title: Text('Alignment', + style: TextStyle( + color: _selectedMode != 'groupAllPoints' + ? model.textColor.withOpacity(0.3) + : model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.6 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container( + color: Color(0xFFBDBDBD), height: 1), + value: _tooltipAlignment, + items: _selectedMode != 'groupAllPoints' + ? null + : _alignmentList.map((String value) { + return DropdownMenuItem( + value: (value != null) + ? value + : 'center', + child: Text('$value', + style: TextStyle( + color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + onAlignmentChange(value); + stateSetter(() {}); + })), ) ])); }), - Container( - child: Row( - children: [ - Text('Show always ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: showAlways, - onChanged: (bool value) { - setState(() { - showAlways = value; - stateSetter(() {}); - }); - })) - ], + ListTile( + title: Text('Show always ', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.6 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: showAlways, + onChanged: (bool? value) { + setState(() { + showAlways = value!; + stateSetter(() {}); + }); + }))), + ListTile( + title: + Text('Hide delay ', style: TextStyle(color: model.textColor)), + trailing: Container( + width: 0.6 * screenWidth, + padding: EdgeInsets.only(left: 0.03 * screenWidth), + child: CustomDirectionalButtons( + maxValue: 10, + initialValue: duration, + onChanged: (double val) => setState(() { + duration = val; + }), + step: 2, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Hide delay ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(44, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 10, - initialValue: duration, - onChanged: (double val) => setState(() { - duration = val; - }), - step: 2, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], - ), + ListTile( + title: Text('Show track\nmarker', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.6 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: _showMarker, + onChanged: (bool? value) { + setState(() { + _showMarker = value!; + stateSetter(() {}); + }); + })), ), - Container( - child: Row( - children: [ - Text('Show track\nmarker', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Padding( - padding: EdgeInsets.fromLTRB(20, 0, 0, 0), - child: Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _showMarker, - onChanged: (bool value) { - setState(() { - _showMarker = value; - stateSetter(() {}); - }); - }))), - ], - ), + ListTile( + title: Text('Show marker\nin tooltip', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.6 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: canShowMarker, + onChanged: (bool? value) { + setState(() { + canShowMarker = value!; + stateSetter(() {}); + }); + })), ), ], ); @@ -214,7 +216,7 @@ class _DefaultTrackballState extends SampleViewState { } /// Returns the cartesian chart with default trackball. - SfCartesianChart _getDefaultTrackballChart() { + SfCartesianChart _buildDefaultTrackballChart() { return SfCartesianChart( title: ChartTitle(text: !isCardView ? 'Average sales per person' : ''), plotAreaBorderWidth: 0, @@ -241,12 +243,16 @@ class _DefaultTrackballState extends SampleViewState { width: 10, borderWidth: 1, ), - hideDelay: (duration ?? 2.0) * 1000, + hideDelay: (duration) * 1000, activationMode: ActivationMode.singleTap, tooltipAlignment: _alignment, tooltipDisplayMode: _mode, - tooltipSettings: InteractiveTooltip(format: 'point.x: point.y'), - shouldAlwaysShow: showAlways ?? true, + tooltipSettings: InteractiveTooltip( + format: _mode != TrackballDisplayMode.groupAllPoints + ? 'series.name : point.y' + : null, + canShowMarker: canShowMarker), + shouldAlwaysShow: showAlways, ), ); } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart b/lib/samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart index 8cd13ae6..4145a173 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/trackball/customized_trackball.dart @@ -42,7 +42,7 @@ class _TrackballTemplateState extends SampleViewState { @override Widget build(BuildContext context) { - return _getTrackballTemplateChart(); + return _buildTrackballTemplateChart(); } @override @@ -71,8 +71,10 @@ class _TrackballTemplateState extends SampleViewState { Container( padding: const EdgeInsets.fromLTRB(60, 0, 0, 0), height: 50, + width: 190, alignment: Alignment.bottomLeft, child: DropdownButton( + isExpanded: true, underline: Container( color: Color(0xFFBDBDBD), height: 1), value: _selectedMode, @@ -85,9 +87,9 @@ class _TrackballTemplateState extends SampleViewState { style: TextStyle( color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { setState(() { - onModeTypeChange(value); + onModeTypeChange(value!); stateSetter(() {}); }); }), @@ -110,9 +112,9 @@ class _TrackballTemplateState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _isTemplate, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _isTemplate = value; + _isTemplate = value!; stateSetter(() {}); }); })) @@ -125,14 +127,14 @@ class _TrackballTemplateState extends SampleViewState { } /// Returns the cartesian chart with default trackball. - SfCartesianChart _getTrackballTemplateChart() { + SfCartesianChart _buildTrackballTemplateChart() { return SfCartesianChart( plotAreaBorderWidth: 0, title: ChartTitle(text: isCardView ? '' : 'Monthly expense of a family'), legend: Legend(isVisible: !isCardView, toggleSeriesVisibility: false), primaryXAxis: CategoryAxis( majorGridLines: MajorGridLines(width: 0), - labelRotation: isCardView || model.isWeb ? 0 : -45, + labelRotation: isCardView || model.isWebFullView ? 0 : -45, ), primaryYAxis: NumericAxis( maximum: 200, @@ -159,7 +161,7 @@ class _TrackballTemplateState extends SampleViewState { padding: EdgeInsets.all(0), child: Container( height: _mode == TrackballDisplayMode.groupAllPoints - ? model.isWeb + ? model.isWebFullView ? 125 : 105 : 50, @@ -201,7 +203,7 @@ class _TrackballTemplateState extends SampleViewState { } Column getGroupingTemplateWidgets(TrackballDetails _trackballDetails) { - Column _columnWidgets = Column( + final Column _columnWidgets = Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [], @@ -211,7 +213,7 @@ class _TrackballTemplateState extends SampleViewState { child: Padding( padding: EdgeInsets.only(left: 0), child: Text( - '${_trackballDetails.groupingModeInfo.points[0].x.toString()}', + '${_trackballDetails.groupingModeInfo!.points[0].x.toString()}', style: TextStyle( color: model.themeData.brightness == Brightness.dark ? Color.fromRGBO(0, 0, 0, 1) @@ -225,19 +227,19 @@ class _TrackballTemplateState extends SampleViewState { ? const Color.fromRGBO(61, 61, 61, 1) : const Color.fromRGBO(238, 238, 238, 1), ))); - Column _columnChildWidgets = Column( + final Column _columnChildWidgets = Column( crossAxisAlignment: _mode == TrackballDisplayMode.groupAllPoints ? CrossAxisAlignment.start : CrossAxisAlignment.center, children: [], ); - List seriesIndices = - _trackballDetails.groupingModeInfo.visibleSeriesIndices; + final List seriesIndices = + _trackballDetails.groupingModeInfo!.visibleSeriesIndices; for (int i = 0; i < seriesIndices.length; i++) { _columnChildWidgets.children.add( Container( child: Text( - '${_trackballDetails.groupingModeInfo.visibleSeriesList[i].name.toString()} : \$${_trackballDetails.groupingModeInfo.points[i].y.toString()}', + '${_trackballDetails.groupingModeInfo!.visibleSeriesList[i].name.toString()} : \$${_trackballDetails.groupingModeInfo!.points[i].y.toString()}', textAlign: TextAlign.left, style: _getTrackballTextStyle())), ); @@ -245,10 +247,10 @@ class _TrackballTemplateState extends SampleViewState { _columnWidgets.children.add(_columnChildWidgets); } else { _columnWidgets.children.add(Text( - '${_trackballDetails.point.x.toString()}', + '${_trackballDetails.point!.x.toString()}', style: _getTrackballTextStyle())); _columnWidgets.children.add(Text( - '\$${_trackballDetails.point.y.toString()}', + '\$${_trackballDetails.point!.y.toString()}', style: TextStyle( fontWeight: FontWeight.bold, color: model.themeData.brightness == Brightness.dark @@ -335,7 +337,7 @@ class _TrackballTemplateState extends SampleViewState { String _getImageTemplate(TrackballDetails _pointInfo) { String _path; - int _seriesIndex = _pointInfo.seriesIndex; + final int? _seriesIndex = _pointInfo.seriesIndex; _path = _seriesIndex == 0 ? 'images/People_Circle12.png' diff --git a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/pinch_zooming.dart b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/pinch_zooming.dart index d7ab3b63..e5bca323 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/pinch_zooming.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/pinch_zooming.dart @@ -22,16 +22,11 @@ class DefaultPanning extends SampleView { class _DefaultPanningState extends SampleViewState { _DefaultPanningState(); final List _zoomModeTypeList = ['x', 'y', 'xy'].toList(); - String _selectedModeType = 'x'; - ZoomMode _zoomModeType = ZoomMode.x; - ZoomPanBehavior _zoomingBehavior; - bool _enableAnchor; - // bool _visible = false; + late String _selectedModeType = 'x'; + late ZoomMode _zoomModeType = ZoomMode.x; + late bool _enableAnchor; GlobalKey chartKey = GlobalKey(); - StateSetter refreshSetState; num left = 0, top = 0; - num screenSizeWidth; - bool isSameSize; @override void initState() { _selectedModeType = 'x'; @@ -42,51 +37,8 @@ class _DefaultPanningState extends SampleViewState { @override Widget build(BuildContext context) { - _zoomingBehavior = ZoomPanBehavior( - - /// To enable the pinch zooming as true. - enablePinching: true, - zoomMode: _zoomModeType, - enablePanning: true, - enableMouseWheelZooming: model.isWeb ? true : false); - - // screenSizeWidth ??= MediaQuery.of(context).size.width; - // final num currentSizeWidth = MediaQuery.of(context).size.width; - // if (currentSizeWidth != screenSizeWidth) { - // isSameSize = false; - // // _visible = false; - // } else { - // isSameSize = true; - // } - // screenSizeWidth = currentSizeWidth; - return Stack(children: [ - _getDefaultPanningChart(), - // isCardView - // ? Container() - // : StatefulBuilder( - // builder: (BuildContext context, StateSetter setState) { - // print('refresh'); - // refreshSetState = setState; - // Widget currentWidget; - // if (_visible) { - // isSameSize = true; - // currentWidget = Container( - // padding: EdgeInsets.only( - // left: left.abs().toDouble(), top: top.toDouble()), - // child: FlatButton( - // onPressed: () { - // _zoomingBehavior.reset(); - // setState(() { - // _visible = false; - // }); - // }, - // child: const Icon(Icons.refresh, color: Colors.blue))); - // } else { - // currentWidget = Container(); - // } - // return currentWidget; - // }) + _buildDefaultPanningChart(), ]); } @@ -117,7 +69,7 @@ class _DefaultPanningState extends SampleViewState { child: Text('$value', style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onZoomTypeChange(value.toString()); stateSetter(() {}); }), @@ -139,9 +91,9 @@ class _DefaultPanningState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _enableAnchor, - onChanged: (bool value) { + onChanged: (bool? value) { stateSetter(() { - _enableRangeCalculation(value); + _enableRangeCalculation(value!); _enableAnchor = value; stateSetter(() {}); }); @@ -155,38 +107,9 @@ class _DefaultPanningState extends SampleViewState { } /// Returns the cartesian chart with pinch zoomings. - SfCartesianChart _getDefaultPanningChart() { + SfCartesianChart _buildDefaultPanningChart() { return SfCartesianChart( key: chartKey, - onActualRangeChanged: (ActualRangeChangedArgs args) { - // final RenderBox renderBox = - // chartKey.currentContext.findRenderObject(); - // if (renderBox.hasSize) { - // final BoxConstraints constraints = renderBox.constraints; - // final num width = constraints.maxWidth; - // final num height = constraints.maxHeight; - // left = (width * 0.9) - 30 / 2; - // top = height * 0.001; - // if (!_visible) { - // if (!isSameSize) { - // Future.delayed(const Duration(milliseconds: 1), () { - // refreshSetState(() { - // _visible = true; - // }); - // }); - // } - // } - // } - }, - onZoomEnd: (ZoomPanArgs args) { - if (args.currentZoomFactor < 1) { - // setState(() { - // _visible = true; - - // refreshSetState(() {}); - // }); - } - }, plotAreaBorderWidth: 0, primaryXAxis: DateTimeAxis( name: 'X-Axis', majorGridLines: MajorGridLines(width: 0)), @@ -195,15 +118,21 @@ class _DefaultPanningState extends SampleViewState { anchorRangeToVisiblePoints: _enableAnchor, majorTickLines: MajorTickLines(size: 0)), series: getDefaultPanningSeries(), - zoomPanBehavior: _zoomingBehavior); + zoomPanBehavior: ZoomPanBehavior( + + /// To enable the pinch zooming as true. + enablePinching: true, + zoomMode: _zoomModeType, + enablePanning: true, + enableMouseWheelZooming: model.isWebFullView ? true : false)); } /// Returns the list of chart series /// which need to render on the chart with pinch zooming. List> getDefaultPanningSeries() { final List color = []; - color.add(Colors.teal[50]); - color.add(Colors.teal[200]); + color.add(Colors.teal[50]!); + color.add(Colors.teal[200]!); color.add(Colors.teal); final List stops = []; diff --git a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/selection_zooming.dart b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/selection_zooming.dart index c05226ea..5d5c1875 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/selection_zooming.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/selection_zooming.dart @@ -19,33 +19,37 @@ class DefaultZooming extends SampleView { /// State class of the chart with delection zooming. class _DefaultZoomingState extends SampleViewState { _DefaultZoomingState(); - ZoomPanBehavior _zoomingPanBehavior; - + late ZoomPanBehavior _zoomingPanBehavior; @override - Widget build(BuildContext context) { - final double bottomPadding = isCardView || model.isWeb ? 0 : 60; + void initState() { _zoomingPanBehavior = ZoomPanBehavior( enablePanning: true, /// To enable the selection zooming here. enableSelectionZooming: true); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final double bottomPadding = isCardView || model.isWebFullView ? 0 : 60; return Scaffold( backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, 0, 5, bottomPadding), - child: Container(child: _getDefaultZoomingChart()), + child: Container(child: _buildDefaultZoomingChart()), ), floatingActionButton: isCardView ? null : FloatingActionButton( onPressed: () => _zoomingPanBehavior.reset(), - child: const Icon(Icons.refresh, color: Colors.white), backgroundColor: model.backgroundColor, + child: const Icon(Icons.refresh, color: Colors.white), )); } /// Returns the cartesian chart with delection zooming. - SfCartesianChart _getDefaultZoomingChart() { + SfCartesianChart _buildDefaultZoomingChart() { return SfCartesianChart( plotAreaBorderWidth: 0, legend: Legend(isVisible: !isCardView, opacity: 0.8), diff --git a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/zooming_with_custom_buttons.dart b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/zooming_with_custom_buttons.dart index b6609e10..1607b032 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/zooming_with_custom_buttons.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/zooming_and_panning/zooming_with_custom_buttons.dart @@ -19,21 +19,25 @@ class ButtonZooming extends SampleView { /// State class of the chart with custom zooming buttons. class _ButtonZoomingState extends SampleViewState { _ButtonZoomingState(); - ZoomPanBehavior _zoomPan; - + late ZoomPanBehavior _zoomPan; @override - Widget build(BuildContext context) { + void initState() { _zoomPan = ZoomPanBehavior( enableDoubleTapZooming: true, enablePanning: true, enablePinching: true, enableSelectionZooming: true, ); + super.initState(); + } + + @override + Widget build(BuildContext context) { return Scaffold( backgroundColor: model.cardThemeColor, body: Padding( padding: EdgeInsets.fromLTRB(5, 0, 5, isCardView ? 0 : 50), - child: Container(child: getButtonZoomingChart()), + child: Container(child: _buildButtonZoomingChart()), ), floatingActionButton: isCardView ? null @@ -48,7 +52,7 @@ class _ButtonZoomingState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -65,7 +69,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -82,7 +86,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -99,7 +103,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -116,7 +120,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -133,7 +137,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -150,7 +154,7 @@ class _ButtonZoomingState extends SampleViewState { ), ), Container( - width: model.isWeb + width: model.isWebFullView ? null : (MediaQuery.of(context).size.width / 7) * 0.9, @@ -176,7 +180,7 @@ class _ButtonZoomingState extends SampleViewState { } /// Returns the Cartesian chart with custom zooming buttons. - SfCartesianChart getButtonZoomingChart() { + SfCartesianChart _buildButtonZoomingChart() { return SfCartesianChart( plotAreaBorderWidth: 0, primaryXAxis: NumericAxis(majorGridLines: MajorGridLines(width: 0)), diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart index 6c4e3ed1..65502c12 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/default_doughnut_chart.dart @@ -22,11 +22,11 @@ class _DoughnutDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultDoughnutChart(); + return _buildDefaultDoughnutChart(); } /// Return the circular chart with default doughnut series. - SfCircularChart _getDefaultDoughnutChart() { + SfCircularChart _buildDefaultDoughnutChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Composition of ocean water'), legend: Legend( diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart index 079104b6..2c0bdcbd 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_center_elevation.dart @@ -22,11 +22,11 @@ class _DoughnutDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getElevationDoughnutChart(); + return _buildElevationDoughnutChart(); } /// Returns the circular charts with center elevation dughnut series. - SfCircularChart _getElevationDoughnutChart() { + SfCircularChart _buildElevationDoughnutChart() { return SfCircularChart( /// It used to set the annotation on circular chart. annotations: [ @@ -35,11 +35,12 @@ class _DoughnutDefaultState extends SampleViewState { width: '100%', widget: Container( child: PhysicalModel( - child: Container(), - shape: BoxShape.circle, - elevation: 10, - shadowColor: Colors.black, - color: const Color.fromRGBO(230, 230, 230, 1)))), + shape: BoxShape.circle, + elevation: 10, + shadowColor: Colors.black, + color: const Color.fromRGBO(230, 230, 230, 1), + child: Container(), + ))), CircularChartAnnotation( widget: Container( child: const Text('62%', diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart index e4846046..50207609 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_color_mapping.dart @@ -22,11 +22,11 @@ class _DoughnutDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDoughnutCustomizationChart(); + return _buildDoughnutCustomizationChart(); } /// Returns the circular chart with color mapping doughnut series. - SfCircularChart _getDoughnutCustomizationChart() { + SfCircularChart _buildDoughnutCustomizationChart() { return SfCircularChart( annotations: [ CircularChartAnnotation( diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_gradient.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_gradient.dart new file mode 100644 index 00000000..593799e0 --- /dev/null +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_gradient.dart @@ -0,0 +1,216 @@ +/// Package import +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Render the default pie series. +class DoughnutGradient extends SampleView { + /// Creates the default pie series. + const DoughnutGradient(Key key) : super(key: key); + + @override + _DoughnutGradientState createState() => _DoughnutGradientState(); +} + +/// State class of pie series. +class _DoughnutGradientState extends SampleViewState { + _DoughnutGradientState(); + late List colors; + + late List stops; + late String _shaderType; + late List _shader; + late List customStops; + + @override + void initState() { + _initializeVariables(); + super.initState(); + } + + @override + Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + return ListView( + shrinkWrap: true, + children: [ + ListTile( + title: Text('Gradient mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _shaderType, + items: _shader.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'point', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + setState(() { + onShaderTyeChange(value); + stateSetter(() {}); + }); + }), + ), + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + return _buildGradientDoughnutChart(); + } + + void _initializeVariables() { + colors = const [ + Color.fromRGBO(96, 87, 234, 1), + Color.fromRGBO(59, 141, 236, 1), + Color.fromRGBO(112, 198, 129, 1), + Color.fromRGBO(237, 241, 81, 1) + ]; + _shaderType = 'sweep'; + _shader = ['linear', 'sweep', 'radial'].toList(); + stops = [0.25, 0.5, 0.75, 1]; + } + + /// Returns the circular chart with pie series. + SfCircularChart _buildGradientDoughnutChart() { + return SfCircularChart( + onCreateShader: (ChartShaderDetails chartShaderDetails) { + if (chartShaderDetails.renderType == 'series') { + customStops = _calculateDoughnut(colors, stops, + chartShaderDetails.outerRect, chartShaderDetails.innerRect!); + } + if (_shaderType == 'linear') { + return ui.Gradient.linear(chartShaderDetails.outerRect.topRight, + chartShaderDetails.outerRect.centerLeft, colors, stops); + } else if (_shaderType == 'radial') { + return ui.Gradient.radial( + chartShaderDetails.outerRect.center, + chartShaderDetails.outerRect.right - + chartShaderDetails.outerRect.center.dx, + colors, + customStops); + } else { + return ui.Gradient.sweep( + chartShaderDetails.outerRect.center, + colors, + stops, + TileMode.clamp, + _degreeToRadian(0), + _degreeToRadian(360), + _resolveTransform( + chartShaderDetails.outerRect, TextDirection.ltr)); + } + }, + title: ChartTitle(text: isCardView ? '' : 'Sales by sales person'), + legend: Legend(isVisible: !isCardView), + series: _getGradientDoughnutSeries(), + ); + } + + /// Returns the pie series. + List> _getGradientDoughnutSeries() { + final List pieData = [ + ChartSampleData(x: 'David', y: 14, text: '14%'), + ChartSampleData(x: 'Steve', y: 15, text: '15%'), + ChartSampleData(x: 'Jack', y: 30, text: '30%'), + ChartSampleData(x: 'Others', y: 41, text: '41%') + ]; + return >[ + DoughnutSeries( + dataSource: pieData, + explodeAll: true, + radius: isCardView ? '85%' : '63%', + explodeOffset: '3%', + explode: true, + strokeColor: model.currentThemeData?.brightness == Brightness.light + ? Colors.black.withOpacity(0.3) + : Colors.white.withOpacity(0.3), + strokeWidth: 1.5, + dataLabelSettings: DataLabelSettings( + isVisible: true, + labelPosition: ChartDataLabelPosition.outside, + connectorLineSettings: ConnectorLineSettings( + color: model.currentThemeData?.brightness == Brightness.light + ? Colors.black.withOpacity(0.5) + : Colors.white, + width: 1.5, + length: isCardView ? '7%' : '10%', + type: ConnectorType.curve, + ), + ), + xValueMapper: (ChartSampleData data, _) => data.x, + yValueMapper: (ChartSampleData data, _) => data.y, + dataLabelMapper: (ChartSampleData data, _) => data.text), + ]; + } + + dynamic _resolveTransform(Rect bounds, TextDirection textDirection) { + final GradientTransform transform = GradientRotation(_degreeToRadian(-90)); + return transform.transform(bounds, textDirection: textDirection)!.storage; + } + + void onShaderTyeChange(String item) { + _shaderType = item; + setState(() { + if (_shaderType == 'linear') { + _shaderType = 'linear'; + } + + if (_shaderType == 'radial') { + _shaderType = 'radial'; + } + if (_shaderType == 'sweep') { + _shaderType = 'sweep'; + } + }); + } + + // Convert degree to radian + double _degreeToRadian(int deg) => deg * (3.141592653589793 / 180); + + dynamic _calculateDoughnut( + List colors, List stops, Rect outerRect, Rect innerRect) { + final List stopOffsets = []; + final num _chartStart = innerRect.right; + final Offset _chartCenter = outerRect.center; + final num _chartend = outerRect.right; + num diffCenterEnd; + num diffStartEnd; + num diffCenterStart; + num centerStops; + diffCenterEnd = _chartend - _chartCenter.dx; + diffStartEnd = _chartend - _chartStart; + diffCenterStart = _chartStart - _chartCenter.dx; + centerStops = diffCenterStart / diffCenterEnd; + for (int i = 0; i < colors.length; i++) { + if (i == 0) { + stopOffsets.add(centerStops += diffStartEnd * stops[i] / diffCenterEnd); + } else { + stopOffsets.add(centerStops += + (diffStartEnd * (stops[i] - stops[i - 1])) / diffCenterEnd); + } + } + return stopOffsets; + } +} diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart index 066873f0..36e0d393 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/doughnut_with_rounded_corners.dart @@ -22,11 +22,11 @@ class _DoughnutRoundedState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRoundedDoughnutChart(); + return _buildRoundedDoughnutChart(); } /// Returns the circular charts with rounded corner doughnut series. - SfCircularChart _getRoundedDoughnutChart() { + SfCircularChart _buildRoundedDoughnutChart() { return SfCircularChart( legend: Legend( isVisible: !isCardView, overflowMode: LegendItemOverflowMode.wrap), diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart index b9c5aaeb..ae042ce5 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart @@ -84,11 +84,11 @@ class _SemiDoughnutChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSemiDoughnutChart(); + return _buildSemiDoughnutChart(); } /// Returns the circular series with semi doughunut series. - SfCircularChart _getSemiDoughnutChart() { + SfCircularChart _buildSemiDoughnutChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Sales by sales person'), legend: Legend(isVisible: !isCardView), @@ -101,18 +101,18 @@ class _SemiDoughnutChartState extends SampleViewState { /// Returns semi doughnut series. List> _getSemiDoughnutSeries() { final List chartData = [ - ChartSampleData(x: 'David', y: 75, text: 'David 74%'), - ChartSampleData(x: 'Steve', y: 35, text: 'Steve 35%'), - ChartSampleData(x: 'Jack', y: 39, text: 'Jack 39%'), - ChartSampleData(x: 'Others', y: 75, text: 'Others 75%') + ChartSampleData(x: 'David', y: 45, text: 'David 45%'), + ChartSampleData(x: 'Steve', y: 15, text: 'Steve 15%'), + ChartSampleData(x: 'Jack', y: 21, text: 'Jack 21%'), + ChartSampleData(x: 'Others', y: 19, text: 'Others 19%') ]; return >[ DoughnutSeries( dataSource: chartData, innerRadius: '70%', radius: isCardView ? '100%' : '59%', - startAngle: startAngle ?? 270, - endAngle: endAngle ?? 90, + startAngle: startAngle, + endAngle: endAngle, xValueMapper: (ChartSampleData data, _) => data.x, yValueMapper: (ChartSampleData data, _) => data.y, dataLabelMapper: (ChartSampleData data, _) => data.text, diff --git a/lib/samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart b/lib/samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart index 84667c96..b8969edb 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/default_pie_chart.dart @@ -22,11 +22,11 @@ class _PieDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultPieChart(); + return _buildDefaultPieChart(); } /// Returns the circular chart with pie series. - SfCircularChart _getDefaultPieChart() { + SfCircularChart _buildDefaultPieChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Sales by sales person'), legend: Legend(isVisible: !isCardView), @@ -37,10 +37,10 @@ class _PieDefaultState extends SampleViewState { /// Returns the pie series. List> _getDefaultPieSeries() { final List pieData = [ - ChartSampleData(x: 'David', y: 30, text: 'David \n 30%'), - ChartSampleData(x: 'Steve', y: 35, text: 'Steve \n 35%'), - ChartSampleData(x: 'Jack', y: 39, text: 'Jack \n 39%'), - ChartSampleData(x: 'Others', y: 75, text: 'Others \n 75%'), + ChartSampleData(x: 'David', y: 13, text: 'David \n 13%'), + ChartSampleData(x: 'Steve', y: 24, text: 'Steve \n 24%'), + ChartSampleData(x: 'Jack', y: 25, text: 'Jack \n 25%'), + ChartSampleData(x: 'Others', y: 38, text: 'Others \n 38%'), ]; return >[ PieSeries( diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_gradient.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_gradient.dart new file mode 100644 index 00000000..da7be0ab --- /dev/null +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_gradient.dart @@ -0,0 +1,177 @@ +/// Package import +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Render the default pie series. +class PieGradient extends SampleView { + /// Creates the default pie series. + const PieGradient(Key key) : super(key: key); + + @override + _PieGradientState createState() => _PieGradientState(); +} + +/// State class of pie series. +class _PieGradientState extends SampleViewState { + _PieGradientState(); + late List colors; + + late List stops; + late String _shaderType; + late List _shader; + + @override + void initState() { + _initializeVariables(); + super.initState(); + } + + @override + Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + return ListView( + shrinkWrap: true, + children: [ + ListTile( + title: Text('Gradient mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _shaderType, + items: _shader.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'point', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + setState(() { + onShaderTyeChange(value); + stateSetter(() {}); + }); + }), + ), + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + return _buildDefaultPieChart(); + } + + void _initializeVariables() { + colors = const [ + Color.fromRGBO(96, 87, 234, 1), + Color.fromRGBO(59, 141, 236, 1), + Color.fromRGBO(112, 198, 129, 1), + Color.fromRGBO(237, 241, 81, 1) + ]; + stops = [0.25, 0.5, 0.75, 1]; + _shader = ['linear', 'sweep', 'radial'].toList(); + _shaderType = 'sweep'; + } + + /// Returns the circular chart with pie series. + SfCircularChart _buildDefaultPieChart() { + return SfCircularChart( + onCreateShader: (ChartShaderDetails chartShaderDetails) { + if (_shaderType == 'linear') { + return ui.Gradient.linear(chartShaderDetails.outerRect.topRight, + chartShaderDetails.outerRect.centerLeft, colors, stops); + } else if (_shaderType == 'radial') { + return ui.Gradient.radial( + chartShaderDetails.outerRect.center, + chartShaderDetails.outerRect.right - + chartShaderDetails.outerRect.center.dx, + colors, + stops); + } else { + return ui.Gradient.sweep( + chartShaderDetails.outerRect.center, + colors, + stops, + TileMode.clamp, + _degreeToRadian(0), + _degreeToRadian(360), + _resolveTransform( + chartShaderDetails.outerRect, TextDirection.ltr)); + } + }, + title: ChartTitle(text: isCardView ? '' : 'Sales by sales person'), + legend: Legend(isVisible: !isCardView), + series: _getDefaultPieSeries(), + ); + } + + /// Returns the pie series. + List> _getDefaultPieSeries() { + final List pieData = [ + ChartSampleData(x: 'David', y: 17, text: 'David \n 17%'), + ChartSampleData(x: 'Steve', y: 20, text: 'Steve \n 20%'), + ChartSampleData(x: 'Jack', y: 25, text: 'Jack \n 25%'), + ChartSampleData(x: 'Others', y: 38, text: 'Others \n 38%') + ]; + return >[ + PieSeries( + dataSource: pieData, + explodeAll: true, + explodeOffset: '3%', + explode: true, + strokeColor: model.currentThemeData?.brightness == Brightness.light + ? Colors.black.withOpacity(0.3) + : Colors.white.withOpacity(0.3), + strokeWidth: 1.5, + dataLabelSettings: DataLabelSettings( + isVisible: true, + textStyle: TextStyle(fontSize: 13, color: Colors.white), + ), + xValueMapper: (ChartSampleData data, _) => data.x, + yValueMapper: (ChartSampleData data, _) => data.y, + dataLabelMapper: (ChartSampleData data, _) => data.text), + ]; + } + + dynamic _resolveTransform(Rect bounds, TextDirection textDirection) { + final GradientTransform transform = GradientRotation(_degreeToRadian(-90)); + return transform.transform(bounds, textDirection: textDirection)!.storage; + } + + void onShaderTyeChange(String item) { + _shaderType = item; + setState(() { + if (_shaderType == 'linear') { + _shaderType = 'linear'; + } + + if (_shaderType == 'radial') { + _shaderType = 'radial'; + } + if (_shaderType == 'sweep') { + _shaderType = 'sweep'; + } + }); + } + + // Convert degree to radian + double _degreeToRadian(int deg) => deg * (3.141592653589793 / 180); +} diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart index 6863b127..a4c84c31 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_grouping.dart @@ -18,18 +18,25 @@ class PieGrouping extends SampleView { class _PieGroupingState extends SampleViewState { _PieGroupingState(); + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.y%'); + super.initState(); + } + @override Widget build(BuildContext context) { - return _getGroupingPieChart(); + return _buildGroupingPieChart(); } /// Return the circular charts with pie series. - SfCircularChart _getGroupingPieChart() { + SfCircularChart _buildGroupingPieChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Electricity sectors'), series: _getGroupingPieSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.y%'), + tooltipBehavior: _tooltipBehavior, ); } @@ -60,24 +67,27 @@ class _PieGroupingState extends SampleViewState { x: 'Solar\nPower', y: 8, text: 'Solar Power: 28,679.21 MW (8.0%)', - pointColor: const Color.fromRGBO(198, 201, 207, 1)), + pointColor: null), ChartSampleData( x: 'Biomass', y: 2.6, text: 'Biomass: 9,269.8 MW (2.6%)', - pointColor: null), + pointColor: const Color.fromRGBO(198, 201, 207, 1)), ChartSampleData( x: 'Nuclear', y: 1.9, text: 'Nuclear: 6,780 MW (1.9%)', - pointColor: null), + pointColor: const Color.fromRGBO(198, 201, 207, 1)), ChartSampleData( - x: 'Gas', y: 7, text: 'Gas: 24,937.22 MW (7.0%)', pointColor: null), + x: 'Gas', + y: 7, + text: 'Gas: 24,937.22 MW (7.0%)', + pointColor: const Color.fromRGBO(198, 201, 207, 1)), ChartSampleData( x: 'Diesel', y: 0.2, text: 'Diesel: 637.63 MW (0.2%)', - pointColor: null) + pointColor: const Color.fromRGBO(198, 201, 207, 1)) ]; return >[ PieSeries( diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart new file mode 100644 index 00000000..eba21f82 --- /dev/null +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart @@ -0,0 +1,188 @@ +/// Package import +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// WIdget to be rendered. +Widget? renderWidget; + +/// Render the default pie series. +class PieImageShader extends SampleView { + /// Creates the default pie series. + const PieImageShader(Key key) : super(key: key); + + @override + _PieImageShaderState createState() => _PieImageShaderState(); +} + +/// State class of pie series. +class _PieImageShaderState extends SampleViewState { + _PieImageShaderState(); + + @override + void initState() { + super.initState(); + } + + ui.Image? image1; + ui.Image? image2; + ui.Image? image3; + ui.Image? image4; + + void getImage() async { + final Completer completer = Completer(); + final ImageProvider imageProvider = AssetImage('images/apple.png'); + imageProvider + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((ImageInfo info, bool _) async { + completer.complete(info); + final ImageInfo imageInfo = await completer.future; + + image1 = imageInfo.image; + })); + + final Completer completer1 = Completer(); + final ImageProvider imageProvider1 = AssetImage('images/orange.png'); + imageProvider1 + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((ImageInfo info, bool _) async { + completer1.complete(info); + final ImageInfo imageInfo1 = await completer1.future; + image2 = imageInfo1.image; + })); + + final Completer completer2 = Completer(); + final ImageProvider imageProvider2 = AssetImage('images/pears.png'); + imageProvider2 + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((ImageInfo info, bool _) async { + completer2.complete(info); + final ImageInfo imageInfo2 = await completer2.future; + + image3 = imageInfo2.image; + })); + + final Completer completer3 = Completer(); + final ImageProvider imageProvider3 = AssetImage('images/other_fruits.png'); + imageProvider3 + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((ImageInfo info, bool _) async { + completer3.complete(info); + final ImageInfo imageInfo4 = await completer3.future; + image4 = imageInfo4.image; + if (mounted) { + setState(() {}); + } + })); + } + + @override + Widget build(BuildContext context) { + getImage(); + if (image1 != null && image2 != null && image3 != null && image4 != null) { + renderWidget = SfCircularChart( + title: ChartTitle( + text: isCardView ? '' : 'Sales comparison of fruits in a shop'), + legend: Legend(isVisible: isCardView ? false : true), + series: >[ + PieSeries<_ChartShaderData, String>( + dataSource: <_ChartShaderData>[ + _ChartShaderData( + 'Apple', + 25, + '25%', + ui.ImageShader( + image1!, + TileMode.repeated, + TileMode.repeated, + Matrix4.identity().scaled(0.5).storage, + ), + ), + _ChartShaderData( + 'Orange', + 35, + '35%', + ui.ImageShader( + image2!, + TileMode.repeated, + TileMode.repeated, + Matrix4.identity().scaled(0.6).storage, + ), + ), + _ChartShaderData( + 'Pears', + 22, + '22%', + ui.ImageShader( + image3!, + TileMode.repeated, + TileMode.repeated, + Matrix4.identity().scaled(0.6).storage, + ), + ), + _ChartShaderData( + 'Others', + 18, + '18%', + ui.ImageShader( + image4!, + TileMode.repeated, + TileMode.repeated, + Matrix4.identity().scaled(0.5).storage, + ), + ), + ], + xValueMapper: (_ChartShaderData data, _) => data.x, + strokeColor: model.currentThemeData?.brightness == Brightness.light + ? Colors.black.withOpacity(0.5) + : Colors.transparent, + strokeWidth: 1.5, + explodeAll: true, + explodeOffset: '3%', + explode: true, + yValueMapper: (_ChartShaderData data, _) => data.y, + dataLabelMapper: (_ChartShaderData data, _) => data.text, + pointShaderMapper: + (_ChartShaderData data, _, Color color, Rect rect) => + data.shader, + dataLabelSettings: DataLabelSettings( + isVisible: true, + labelPosition: ChartDataLabelPosition.outside, + connectorLineSettings: ConnectorLineSettings( + color: model.currentThemeData?.brightness == Brightness.light + ? Colors.black.withOpacity(0.5) + : Colors.white, + width: 1.5, + length: isCardView ? '10%' : '15%', + type: ConnectorType.curve, + )), + radius: isCardView ? '85%' : '63%', + ), + ], + ); + } else { + getImage(); + renderWidget = Center(child: CircularProgressIndicator()); + } + return renderWidget!; + } +} + +class _ChartShaderData { + _ChartShaderData(this.x, this.y, this.text, this.shader); + + final String x; + + final num y; + + final String text; + + final Shader shader; +} diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart index bf151232..b4065134 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_labels.dart @@ -25,8 +25,9 @@ class _PieSmartLabelsState extends SampleViewState { String _connectorLine = 'curve'; bool isZeroVisible = false; bool isSmartLabelMode = true; - ChartDataLabelPosition _labelPosition; - ConnectorType _connectorType; + late ChartDataLabelPosition _labelPosition; + late ConnectorType _connectorType; + late TooltipBehavior _tooltipBehavior; @override Widget buildSettings(BuildContext context) { @@ -79,9 +80,9 @@ class _PieSmartLabelsState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: isSmartLabelMode, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - isSmartLabelMode = value; + isSmartLabelMode = value!; stateSetter(() {}); }); })), @@ -131,9 +132,9 @@ class _PieSmartLabelsState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: isZeroVisible, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - isZeroVisible = value; + isZeroVisible = value!; stateSetter(() {}); }); })), @@ -147,16 +148,16 @@ class _PieSmartLabelsState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSmartLabelPieChart(); + return _buildSmartLabelPieChart(); } /// Returns the circular charts with pie series. - SfCircularChart _getSmartLabelPieChart() { + SfCircularChart _buildSmartLabelPieChart() { return SfCircularChart( title: ChartTitle( text: isCardView ? '' : 'Monthly expenditure of an individual'), series: _gettSmartLabelPieSeries(), - tooltipBehavior: TooltipBehavior(enable: true), + tooltipBehavior: _tooltipBehavior, ); } @@ -200,6 +201,7 @@ class _PieSmartLabelsState extends SampleViewState { void initState() { _labelPosition = ChartDataLabelPosition.outside; _connectorType = ConnectorType.curve; + _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_various_radius.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_various_radius.dart index 1c1d624b..55b724a2 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_various_radius.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_various_radius.dart @@ -22,11 +22,11 @@ class _PieRadiusState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadiusPieChart(); + return _buildRadiusPieChart(); } /// Returns the circular charts with pie series. - SfCircularChart _getRadiusPieChart() { + SfCircularChart _buildRadiusPieChart() { return SfCircularChart( title: ChartTitle( text: isCardView diff --git a/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart b/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart new file mode 100644 index 00000000..9c753883 --- /dev/null +++ b/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart @@ -0,0 +1,144 @@ +/// Package import +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Render the pie series with grouping datapoints. +class PiePointRenderMode extends SampleView { + /// Creates the pie series with grouping datapoints. + const PiePointRenderMode(Key key) : super(key: key); + + @override + _PiePointRenderModeState createState() => _PiePointRenderModeState(); +} + +class _PiePointRenderModeState extends SampleViewState { + _PiePointRenderModeState(); + final List _modeList = ['gradient', 'segment'].toList(); + String _selectedMode = 'gradient'; + PointRenderMode _mode = PointRenderMode.segment; + @override + void initState() { + _selectedMode = 'gradient'; + _mode = PointRenderMode.gradient; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return _buildGroupingPieChart(); + } + + @override + Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + return ListView( + shrinkWrap: true, + children: [ + StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Container( + height: 60, + child: ListView( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + children: [ + ListTile( + title: Text('Point rendering mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container( + color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: + (value != null) ? value : 'Render mode', + child: Text('$value', + style: + TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + setState(() { + onModeTypeChange(value); + stateSetter(() {}); + }); + }), + ), + ), + ])); + }), + ], + ); + }); + } + + /// Return the circular charts with pie series. + SfCircularChart _buildGroupingPieChart() { + return SfCircularChart( + title: ChartTitle( + text: isCardView ? '' : 'Monthly expenditure of an individual'), + series: _getGroupingPieSeries(), + ); + } + + /// Return the pie series which need to be grouping. + List> _getGroupingPieSeries() { + final List pieData = [ + ChartSampleData(x: 'Food', y: 15, text: 'Food\n15%', pointColor: null), + ChartSampleData( + x: 'Medical', y: 28, text: 'Medical\n28%', pointColor: null), + ChartSampleData( + x: 'Travel', y: 15, text: 'Travel\n15%', pointColor: null), + ChartSampleData( + x: 'Shopping', y: 17, text: 'Shopping\n17%', pointColor: null), + ChartSampleData( + x: 'Others', + y: 25, + text: 'Others\n25%', + pointColor: const Color.fromRGBO(198, 201, 207, 1)) + ]; + return >[ + PieSeries( + radius: isCardView ? '70%' : '58%', + dataLabelMapper: (ChartSampleData data, _) => data.text, + dataLabelSettings: DataLabelSettings( + isVisible: true, labelPosition: ChartDataLabelPosition.outside), + dataSource: pieData, + pointRenderMode: _mode, + + /// To enable and specify the group mode for pie chart. + groupMode: CircularChartGroupMode.value, + groupTo: 7, + xValueMapper: (ChartSampleData data, _) => data.x, + yValueMapper: (ChartSampleData data, _) => data.y) + ]; + } + + void onModeTypeChange(String item) { + _selectedMode = item; + if (_selectedMode == 'segment') { + _mode = PointRenderMode.segment; + } + if (_selectedMode == 'gradient') { + _mode = PointRenderMode.gradient; + } + setState(() { + /// update the trackball display type changes + }); + } +} diff --git a/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart b/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart index 0d1c3a5c..f30bb555 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart @@ -21,6 +21,13 @@ class _SemiPieChartState extends SampleViewState { _SemiPieChartState(); int _startAngle = 270; int _endAngle = 90; + late TooltipBehavior _tooltipBehavior; + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.y%'); + super.initState(); + } @override Widget buildSettings(BuildContext context) { @@ -84,11 +91,11 @@ class _SemiPieChartState extends SampleViewState { @override Widget build(BuildContext context) { - return _getSemiPieChartChart(); + return _buildSemiPieChartChart(); } /// Return the circular chart with semi pie series. - SfCircularChart _getSemiPieChartChart() { + SfCircularChart _buildSemiPieChartChart() { return SfCircularChart( centerY: '60%', title: ChartTitle( @@ -96,8 +103,7 @@ class _SemiPieChartState extends SampleViewState { legend: Legend( isVisible: !isCardView, overflowMode: LegendItemOverflowMode.wrap), series: _getSemiPieChartSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.y%'), + tooltipBehavior: _tooltipBehavior, ); } @@ -119,8 +125,8 @@ class _SemiPieChartState extends SampleViewState { /// If we set start and end angle given below /// it will render as semi pie chart. - startAngle: _startAngle ?? 270, - endAngle: _endAngle ?? 90, + startAngle: _startAngle, + endAngle: _endAngle, dataLabelSettings: DataLabelSettings( isVisible: true, labelPosition: ChartDataLabelPosition.inside)) ]; diff --git a/lib/samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart b/lib/samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart index 8325c71d..e2ff2600 100644 --- a/lib/samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/radial_bar/customized_radial_bar_chart.dart @@ -20,14 +20,22 @@ class RadialBarCustomized extends SampleView { /// State class of radial bar customization. class _RadialBarCustomizedState extends SampleViewState { _RadialBarCustomizedState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.y%'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getCustomizedRadialBarChart(); + return _buildCustomizedRadialBarChart(); } /// Return the circular chart with radial customization. - SfCircularChart _getCustomizedRadialBarChart() { + SfCircularChart _buildCustomizedRadialBarChart() { final List dataSources = [ ChartSampleData( x: 'Vehicle', @@ -153,8 +161,7 @@ class _RadialBarCustomizedState extends SampleViewState { }, ), series: _getRadialBarCustomizedSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.y%'), + tooltipBehavior: _tooltipBehavior, annotations: [ CircularChartAnnotation( angle: 0, diff --git a/lib/samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart b/lib/samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart index 2200688e..a0c97ade 100644 --- a/lib/samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/radial_bar/default_radial_bar_chart.dart @@ -19,19 +19,27 @@ class RadialBarDefault extends SampleView { /// State class of radial bar. class _RadialBarDefaultState extends SampleViewState { _RadialBarDefaultState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.ym'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getDefaultRadialBarChart(); + return _buildDefaultRadialBarChart(); } /// Returns the circular chart with radial series. - SfCircularChart _getDefaultRadialBarChart() { + SfCircularChart _buildDefaultRadialBarChart() { return SfCircularChart( + key: GlobalKey(), title: ChartTitle(text: isCardView ? '' : 'Shot put distance'), series: _getRadialBarDefaultSeries(), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.ym'), + tooltipBehavior: _tooltipBehavior, ); } diff --git a/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_gradient.dart b/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_gradient.dart new file mode 100644 index 00000000..f11c3a25 --- /dev/null +++ b/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_gradient.dart @@ -0,0 +1,114 @@ +/// Package import +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Chart import +import 'package:syncfusion_flutter_charts/charts.dart'; + +/// Local imports +import '../../../../../model/sample_view.dart'; + +/// Render the default radial bar. +class RadialBarGradient extends SampleView { + /// Creates the default radial bar. + const RadialBarGradient(Key key) : super(key: key); + + @override + _RadialBarGradientState createState() => _RadialBarGradientState(); +} + +/// State class of radial bar. +class _RadialBarGradientState extends SampleViewState { + _RadialBarGradientState(); + late TooltipBehavior _tooltipBehavior; + + late List colors; + + late List stops; + + @override + void initState() { + colors = const [ + Colors.red, + Colors.yellow, + Colors.green, + ]; + stops = [0.3, 0.6, 0.9]; + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.ym'); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return _buildDefaultRadialBarChart(); + } + + /// Returns the circular chart with radial series. + SfCircularChart _buildDefaultRadialBarChart() { + return SfCircularChart( + key: GlobalKey(), + onCreateShader: (ChartShaderDetails chartShaderDetails) { + return ui.Gradient.sweep( + chartShaderDetails.outerRect.center, + colors, + stops, + TileMode.clamp, + _degreeToRadian(0), + _degreeToRadian(360), + _resolveTransform( + chartShaderDetails.outerRect, TextDirection.ltr)); + }, + legend: Legend( + isVisible: !isCardView, + iconHeight: 20, + iconWidth: 20, + textStyle: TextStyle(fontSize: 15)), + title: ChartTitle(text: isCardView ? '' : 'Shot put distance'), + series: _getRadialBarGradientSeries(), + tooltipBehavior: _tooltipBehavior); + } + + /// Returns default radial series. + List> + _getRadialBarGradientSeries() { + final List<_ChartShaderData> chartData = <_ChartShaderData>[ + _ChartShaderData('John', 10, '100%'), + _ChartShaderData('Almaida', 11, '100%'), + _ChartShaderData('Don', 12, '100%'), + ]; + return >[ + RadialBarSeries<_ChartShaderData, String>( + maximumValue: 15, + dataLabelSettings: DataLabelSettings( + isVisible: true, textStyle: const TextStyle(fontSize: 10.0)), + dataSource: chartData, + cornerStyle: CornerStyle.bothCurve, + gap: '10%', + radius: '90%', + xValueMapper: (_ChartShaderData data, _) => data.x, + yValueMapper: (_ChartShaderData data, _) => data.y, + pointRadiusMapper: (_ChartShaderData data, _) => data.text, + dataLabelMapper: (_ChartShaderData data, _) => data.x) + ]; + } + + dynamic _resolveTransform(Rect bounds, TextDirection textDirection) { + final GradientTransform transform = GradientRotation(_degreeToRadian(-90)); + return transform.transform(bounds, textDirection: textDirection)!.storage; + } + + // Convert degree to radian + double _degreeToRadian(int deg) => deg * (3.141592653589793 / 180); +} + +class _ChartShaderData { + _ChartShaderData(this.x, this.y, this.text); + + final String x; + + final num y; + + final String text; +} diff --git a/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart b/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart index 8e6128c8..aed0f7fe 100644 --- a/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart +++ b/lib/samples/chart/circular_charts/chart_types/radial_bar/radial_bar_with_legend.dart @@ -19,14 +19,21 @@ class RadialBarAngle extends SampleView { /// State class of radial series with legend. class _RadialBarAngleState extends SampleViewState { _RadialBarAngleState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = TooltipBehavior(enable: true, format: 'point.x'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getAngleRadialBarChart(); + return _buildAngleRadialBarChart(); } /// Retunrs the circular charts with radial series. - SfCircularChart _getAngleRadialBarChart() { + SfCircularChart _buildAngleRadialBarChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Activity tracker'), @@ -36,7 +43,7 @@ class _RadialBarAngleState extends SampleViewState { iconHeight: 20, iconWidth: 20, overflowMode: LegendItemOverflowMode.wrap), - tooltipBehavior: TooltipBehavior(enable: true, format: 'point.x'), + tooltipBehavior: _tooltipBehavior, series: _getRadialBarSeries(), ); } diff --git a/lib/samples/chart/circular_charts/export.dart b/lib/samples/chart/circular_charts/export.dart index c90c6d9a..fdcdbd8f 100644 --- a/lib/samples/chart/circular_charts/export.dart +++ b/lib/samples/chart/circular_charts/export.dart @@ -28,15 +28,15 @@ class ExportCircular extends SampleView { } class _ExportState extends SampleViewState { - final GlobalKey _circularChartKey = GlobalKey(); _ExportState(); + final GlobalKey _circularChartKey = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: model.cardThemeColor, body: Column(children: [ - Expanded(child: _getCircularChart()), + Expanded(child: _buildCircularChart()), Container( padding: EdgeInsets.only(bottom: 10), child: Row( @@ -53,14 +53,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, duration: Duration(milliseconds: 100), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), content: - Text("Chart has been exported as PNG image"), + Text('Chart has been exported as PNG image'), )); _renderCircularImage(); }, @@ -78,14 +78,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, duration: Duration(milliseconds: 2000), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), content: - Text("Chart is being exported as PDF document"), + Text('Chart is being exported as PDF document'), )); _renderPdf(); }, @@ -97,7 +97,7 @@ class _ExportState extends SampleViewState { } /// Get default circular chart - SfCircularChart _getCircularChart() { + SfCircularChart _buildCircularChart() { return SfCircularChart( backgroundColor: model.cardThemeColor, key: _circularChartKey, @@ -159,8 +159,8 @@ class _ExportState extends SampleViewState { await getApplicationDocumentsDirectory(); final String path = documentDirectory.path; final String imageName = 'circularchart.png'; - imageCache.clear(); - File file = new File('$path/$imageName'); + imageCache!.clear(); + final File file = File('$path/$imageName'); file.writeAsBytesSync(bytes); await Navigator.of(context).push( @@ -195,13 +195,13 @@ class _ExportState extends SampleViewState { final Size pageSize = page.getClientSize(); page.graphics.drawImage( bitmap, Rect.fromLTWH(0, 0, pageSize.width, pageSize.height)); - Scaffold.of(context).hideCurrentSnackBar(); - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 200), - content: Text("Chart has been exported as PDF document."), + content: Text('Chart has been exported as PDF document.'), )); final List bytes = document.save(); @@ -210,9 +210,9 @@ class _ExportState extends SampleViewState { } Future> _readImageData() async { - dart_ui.Image data = - await _circularChartKey.currentState.toImage(pixelRatio: 3.0); + final dart_ui.Image data = + await _circularChartKey.currentState!.toImage(pixelRatio: 3.0); final bytes = await data.toByteData(format: dart_ui.ImageByteFormat.png); - return bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); + return bytes!.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); } } diff --git a/lib/samples/chart/circular_charts/legend/chart_with_legend.dart b/lib/samples/chart/circular_charts/legend/chart_with_legend.dart index cce9126d..46cb3a0e 100644 --- a/lib/samples/chart/circular_charts/legend/chart_with_legend.dart +++ b/lib/samples/chart/circular_charts/legend/chart_with_legend.dart @@ -21,11 +21,11 @@ class _LegendDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLegendDefaultChart(); + return _buildLegendDefaultChart(); } ///Get the default circular series with legend - SfCircularChart _getLegendDefaultChart() { + SfCircularChart _buildLegendDefaultChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Electricity sectors'), legend: diff --git a/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart b/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart index f999e4f1..f403f6b9 100644 --- a/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart +++ b/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart @@ -30,90 +30,81 @@ class _LegendOptionsState extends SampleViewState { @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - children: [ - Text('Position ', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(75, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _positionList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'auto', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onPositionTypeChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('Position ', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _positionList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'auto', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onPositionTypeChange(value.toString()); + stateSetter(() {}); + }), ), ), - Container( - child: Row( - children: [ - Text('Overflow mode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(30, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: - Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'wrap', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onModeTypeChange(value); - stateSetter(() {}); - })), - ], - ), + ListTile( + title: Text('Overflow mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'wrap', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onModeTypeChange(value); + stateSetter(() {}); + })), ), - Container( - child: Row( - children: [ - Text('Toggle visibility', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - width: 75, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: toggleVisibility, - onChanged: (bool value) { - setState(() { - toggleVisibility = value; - stateSetter(() {}); - }); - })), - ], - ), + ListTile( + title: Text('Toggle visibility', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.4 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: toggleVisibility, + onChanged: (bool? value) { + setState(() { + toggleVisibility = value!; + stateSetter(() {}); + }); + })), ), ], ); @@ -122,11 +113,11 @@ class _LegendOptionsState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLegendOptionsChart(); + return _buildLegendOptionsChart(); } ///Get the circular chart which has legend - SfCircularChart _getLegendOptionsChart() { + SfCircularChart _buildLegendOptionsChart() { return SfCircularChart( title: ChartTitle(text: isCardView ? '' : 'Expenses by category'), legend: Legend( diff --git a/lib/samples/chart/circular_charts/user_interactions/dynamic_selection.dart b/lib/samples/chart/circular_charts/user_interactions/dynamic_selection.dart index b4e17454..7bcabc99 100644 --- a/lib/samples/chart/circular_charts/user_interactions/dynamic_selection.dart +++ b/lib/samples/chart/circular_charts/user_interactions/dynamic_selection.dart @@ -16,14 +16,16 @@ class DynamicCircularSelection extends SampleView { } class _CircularSelectionState extends SampleViewState { - SelectionBehavior selectionBehavior = SelectionBehavior(enable: true); _CircularSelectionState(); + late SelectionBehavior selectionBehavior; + final List _pointIndexList = ['0', '1', '2', '3', '4', '5', '6'].toList(); - int _pointIndex; + late int _pointIndex; @override void initState() { _pointIndex = 0; + selectionBehavior = SelectionBehavior(enable: true); super.initState(); } @@ -69,8 +71,11 @@ class _CircularSelectionState extends SampleViewState { Container( child: Padding( padding: EdgeInsets.fromLTRB(0, 0, 25, 0), - child: RaisedButton( - color: model.backgroundColor, + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + ), onPressed: () { selectionBehavior.selectDataPoints(_pointIndex); }, @@ -85,10 +90,10 @@ class _CircularSelectionState extends SampleViewState { @override Widget build(BuildContext context) { - return getCircularSelectionChart(); + return _buildCircularSelectionChart(); } - SfCircularChart getCircularSelectionChart() { + SfCircularChart _buildCircularSelectionChart() { return SfCircularChart( onSelectionChanged: (SelectionArgs args) { _pointIndex = args.pointIndex; diff --git a/lib/samples/chart/circular_charts/user_interactions/selection.dart b/lib/samples/chart/circular_charts/user_interactions/selection.dart index ce24f561..77d62dd2 100644 --- a/lib/samples/chart/circular_charts/user_interactions/selection.dart +++ b/lib/samples/chart/circular_charts/user_interactions/selection.dart @@ -17,10 +17,17 @@ class CircularSelection extends SampleView { } class _CircularSelectionState extends SampleViewState { - SelectionBehavior selectionBehavior = SelectionBehavior(enable: true); _CircularSelectionState(); + late SelectionBehavior selectionBehavior; + bool enableMultiSelect = false; + @override + void initState() { + selectionBehavior = SelectionBehavior(enable: true); + super.initState(); + } + @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -37,9 +44,9 @@ class _CircularSelectionState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: enableMultiSelect, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - enableMultiSelect = value; + enableMultiSelect = value!; stateSetter(() {}); }); })) @@ -50,16 +57,16 @@ class _CircularSelectionState extends SampleViewState { @override Widget build(BuildContext context) { - return getCircularSelectionChart(); + return _buildCircularSelectionChart(); } - SfCircularChart getCircularSelectionChart() { + SfCircularChart _buildCircularSelectionChart() { return SfCircularChart( title: ChartTitle( text: isCardView ? '' : 'Age distribution by country - 5 to 50 years'), selectionGesture: ActivationMode.singleTap, - enableMultiSelection: enableMultiSelect ?? false, + enableMultiSelection: enableMultiSelect, series: getCircularSelectionSeries(), ); } diff --git a/lib/samples/chart/circular_charts/user_interactions/tooltip.dart b/lib/samples/chart/circular_charts/user_interactions/tooltip.dart index 148d5a61..9a561101 100644 --- a/lib/samples/chart/circular_charts/user_interactions/tooltip.dart +++ b/lib/samples/chart/circular_charts/user_interactions/tooltip.dart @@ -94,10 +94,10 @@ class _PieTooltipPositionState extends SampleViewState { @override Widget build(BuildContext context) { - return getPieTooltipPositionChart(); + return _buildPieTooltipPositionChart(); } - SfCircularChart getPieTooltipPositionChart() { + SfCircularChart _buildPieTooltipPositionChart() { return SfCircularChart( title: ChartTitle( text: isCardView @@ -112,7 +112,7 @@ class _PieTooltipPositionState extends SampleViewState { tooltipBehavior: TooltipBehavior( enable: true, tooltipPosition: _tooltipPosition, - duration: (duration ?? 2.0) * 1000, + duration: (duration) * 1000, ), ); } diff --git a/lib/samples/chart/funnel_charts/default_funnel_chart.dart b/lib/samples/chart/funnel_charts/default_funnel_chart.dart index 59e08c92..65d2dab5 100644 --- a/lib/samples/chart/funnel_charts/default_funnel_chart.dart +++ b/lib/samples/chart/funnel_charts/default_funnel_chart.dart @@ -26,103 +26,85 @@ class _FunnelDefaultState extends SampleViewState { @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Gap ratio ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 0.5, - initialValue: gapRatio, - onChanged: (double val) => setState(() { - gapRatio = val; - }), - step: 0.1, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], + ListTile( + title: + Text('Gap ratio ', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.03 * screenWidth), + width: 0.5 * screenWidth, + child: CustomDirectionalButtons( + maxValue: 0.5, + initialValue: gapRatio, + onChanged: (double val) => setState(() { + gapRatio = val; + }), + step: 0.1, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Neck height ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(25, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: neckHeight.toDouble(), - onChanged: (double val) => setState(() { - neckHeight = val.toInt(); - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], + ListTile( + title: + Text('Neck height ', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.03 * screenWidth), + width: 0.5 * screenWidth, + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: neckHeight.toDouble(), + onChanged: (double val) => setState(() { + neckHeight = val.toInt(); + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Neck width', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(35, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: neckWidth.toDouble(), - onChanged: (double val) => setState(() { - neckWidth = val.toInt(); - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], - ), - ), - Container( - child: Row( - children: [ - Text('Explode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - const Padding(padding: EdgeInsets.fromLTRB(30, 0, 0, 0)), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: explode, - onChanged: (bool value) { - setState(() { - explode = value; - stateSetter(() {}); - }); - })) - ], + ListTile( + title: Text('Neck width', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.03 * screenWidth), + width: 0.5 * screenWidth, + child: CustomDirectionalButtons( + maxValue: 50, + initialValue: neckWidth.toDouble(), + onChanged: (double val) => setState(() { + neckWidth = val.toInt(); + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), + ListTile( + title: Text('Explode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.5 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: explode, + onChanged: (bool? value) { + setState(() { + explode = value!; + stateSetter(() {}); + }); + }))), ], ); }); @@ -130,11 +112,11 @@ class _FunnelDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultFunnelChart(); + return _buildDefaultFunnelChart(); } ///Get the default funnel chart - SfFunnelChart _getDefaultFunnelChart() { + SfFunnelChart _buildDefaultFunnelChart() { return SfFunnelChart( smartLabelMode: SmartLabelMode.shift, title: ChartTitle(text: isCardView ? '' : 'Website conversion rate'), @@ -146,10 +128,10 @@ class _FunnelDefaultState extends SampleViewState { /// This method returns the funnel series and /// its correspoding values to chart. FunnelSeries _getFunnelSeries() { - gapRatio = gapRatio ?? 0; - neckWidth = neckWidth ?? 20; - neckHeight = neckHeight ?? 20; - explode = explode ?? true; + gapRatio = gapRatio; + neckWidth = neckWidth; + neckHeight = neckHeight; + explode = explode; final List pieData = [ ChartSampleData(x: 'Purchased ', y: 150), ChartSampleData(x: 'Requested price list', y: 300), diff --git a/lib/samples/chart/funnel_charts/funnel_with_legend.dart b/lib/samples/chart/funnel_charts/funnel_with_legend.dart index 2220926a..5a81af74 100644 --- a/lib/samples/chart/funnel_charts/funnel_with_legend.dart +++ b/lib/samples/chart/funnel_charts/funnel_with_legend.dart @@ -18,14 +18,22 @@ class FunnelLegend extends SampleView { class _FunnelLegendState extends SampleViewState { _FunnelLegendState(); + late TooltipBehavior _tooltipBehavior; + + @override + void initState() { + _tooltipBehavior = + TooltipBehavior(enable: true, format: 'point.x : point.y%'); + super.initState(); + } @override Widget build(BuildContext context) { - return _getLegendFunnelChart(); + return _buildLegendFunnelChart(); } ///Get the funnel chart which contains the legend - SfFunnelChart _getLegendFunnelChart() { + SfFunnelChart _buildLegendFunnelChart() { return SfFunnelChart( smartLabelMode: SmartLabelMode.none, title: ChartTitle( @@ -34,8 +42,7 @@ class _FunnelLegendState extends SampleViewState { /// To enable the legend for funnel chart. legend: Legend(isVisible: true, overflowMode: LegendItemOverflowMode.wrap), - tooltipBehavior: - TooltipBehavior(enable: true, format: 'point.x : point.y%'), + tooltipBehavior: _tooltipBehavior, series: _getFunnelSeries(), ); } diff --git a/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart b/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart index 21d0a788..a93bc3c1 100644 --- a/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart +++ b/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart @@ -29,66 +29,59 @@ class _FunnelSmartLabelState extends SampleViewState { @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Label Position ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _labelPosition.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'outside', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onLabelPositionChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('Label Position ', + style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _labelPosition.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'outside', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onLabelPositionChange(value.toString()); + stateSetter(() {}); + }), ), ), - Container( - child: Row( - children: [ - Text('Smart label mode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(22, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _smartLabelMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'shift', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onSmartLabelModeChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('Smart label mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _smartLabelMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'shift', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onSmartLabelModeChange(value.toString()); + stateSetter(() {}); + }), ), ), ], @@ -98,13 +91,13 @@ class _FunnelSmartLabelState extends SampleViewState { @override Widget build(BuildContext context) { - return _getFunnelSmartLabelChart(); + return _buildFunnelSmartLabelChart(); } ///Get the funnel chart with smart data label - SfFunnelChart _getFunnelSmartLabelChart() { + SfFunnelChart _buildFunnelSmartLabelChart() { return SfFunnelChart( - smartLabelMode: _mode ?? SmartLabelMode.shift, + smartLabelMode: _mode, title: ChartTitle(text: isCardView ? '' : 'Tournament details'), tooltipBehavior: TooltipBehavior( enable: true, diff --git a/lib/samples/chart/pyramid_charts/default_pyramid_chart.dart b/lib/samples/chart/pyramid_charts/default_pyramid_chart.dart index c2d01fca..6da9dabc 100644 --- a/lib/samples/chart/pyramid_charts/default_pyramid_chart.dart +++ b/lib/samples/chart/pyramid_charts/default_pyramid_chart.dart @@ -27,85 +27,72 @@ class _PyramidDefaultState extends SampleViewState { @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Pyramid mode', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _pyramidMode.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'Linear', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onPyramidModeChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: + Text('Pyramid mode', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.5 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _pyramidMode.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Linear', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onPyramidModeChange(value.toString()); + stateSetter(() {}); + }), ), ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Gap ratio ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(45, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 0.5, - initialValue: gapRatio, - onChanged: (double val) => setState(() { - gapRatio = val; - }), - step: 0.1, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), - ), - ], + ListTile( + title: Text('Gap ratio', style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.03 * screenWidth), + width: 0.5 * screenWidth, + child: CustomDirectionalButtons( + maxValue: 0.5, + initialValue: gapRatio, + onChanged: (double val) => setState(() { + gapRatio = val; + }), + step: 0.1, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ), ), - Container( - child: Row( - children: [ - Text('Explode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Padding( - padding: EdgeInsets.fromLTRB(40, 0, 0, 0), - child: Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: explode, - onChanged: (bool value) { - setState(() { - explode = value; - stateSetter(() {}); - }); - }))), - ], - ), + ListTile( + title: Text('Explode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.05 * screenWidth), + width: 0.5 * screenWidth, + child: CheckboxListTile( + controlAffinity: ListTileControlAffinity.leading, + contentPadding: EdgeInsets.zero, + activeColor: model.backgroundColor, + value: explode, + onChanged: (bool? value) { + setState(() { + explode = value!; + stateSetter(() {}); + }); + })), ), ], ); @@ -114,11 +101,11 @@ class _PyramidDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultPyramidChart(); + return _buildDefaultPyramidChart(); } ///Get the default pyramid chart - SfPyramidChart _getDefaultPyramidChart() { + SfPyramidChart _buildDefaultPyramidChart() { return SfPyramidChart( smartLabelMode: SmartLabelMode.shift, title: ChartTitle(text: isCardView ? '' : 'Comparison of calories'), diff --git a/lib/samples/chart/pyramid_charts/pyramid_with_legend.dart b/lib/samples/chart/pyramid_charts/pyramid_with_legend.dart index 17658019..5b4552b0 100644 --- a/lib/samples/chart/pyramid_charts/pyramid_with_legend.dart +++ b/lib/samples/chart/pyramid_charts/pyramid_with_legend.dart @@ -21,16 +21,16 @@ class _PyramidLegendState extends SampleViewState { @override Widget build(BuildContext context) { - return _getLegendPyramidChart(); + return _buildLegendPyramidChart(); } ///Get the pyramid chart - SfPyramidChart _getLegendPyramidChart() { + SfPyramidChart _buildLegendPyramidChart() { return SfPyramidChart( onTooltipRender: (TooltipArgs args) { List data; String text; - text = args.dataPoints[args.pointIndex].y.toString(); + text = args.dataPoints![args.pointIndex!.toInt()].y.toString(); if (text.contains('.')) { data = text.split('.'); final String newTe = diff --git a/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart b/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart index c02d549b..9dba82b6 100644 --- a/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart +++ b/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart @@ -30,66 +30,59 @@ class _PyramidSmartLabelState extends SampleViewState { @override Widget buildSettings(BuildContext context) { + final double screenWidth = + model.isWebFullView ? 245 : MediaQuery.of(context).size.width; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text('Label position ', - style: TextStyle(fontSize: 16.0, color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _labelPosition.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'outside', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onLabelPositionChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('Label position ', + style: TextStyle(color: model.textColor)), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _labelPosition.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'outside', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onLabelPositionChange(value.toString()); + stateSetter(() {}); + }), ), ), - Container( - child: Row( - children: [ - Text('Smart label mode', - style: TextStyle( - color: model.textColor, - fontSize: 16, - )), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - underline: Container(color: Color(0xFFBDBDBD), height: 1), - value: _smartLabelMode, - items: _modeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'shift', - child: Text('$value', - style: TextStyle(color: model.textColor))); - }).toList(), - onChanged: (dynamic value) { - _onSmartLabelModeChange(value.toString()); - stateSetter(() {}); - }), - ), - ], + ListTile( + title: Text('Smart label mode', + style: TextStyle( + color: model.textColor, + )), + trailing: Container( + padding: EdgeInsets.only(left: 0.07 * screenWidth), + width: 0.4 * screenWidth, + height: 50, + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _smartLabelMode, + items: _modeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'shift', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + _onSmartLabelModeChange(value.toString()); + stateSetter(() {}); + }), ), ), ], @@ -99,23 +92,24 @@ class _PyramidSmartLabelState extends SampleViewState { @override Widget build(BuildContext context) { - return _getPyramidSmartLabelChart(); + return _buildPyramidSmartLabelChart(); } ///Get the pyramid chart with smart data labels - SfPyramidChart _getPyramidSmartLabelChart() { + SfPyramidChart _buildPyramidSmartLabelChart() { return SfPyramidChart( onTooltipRender: (TooltipArgs args) { final NumberFormat format = NumberFormat.decimalPattern(); - args.text = - format.format(args.dataPoints[args.pointIndex].y).toString(); + args.text = format + .format(args.dataPoints![args.pointIndex!.toInt()].y) + .toString(); }, title: ChartTitle( text: isCardView ? '' : 'Top 10 populated countries - 2019'), tooltipBehavior: TooltipBehavior(enable: true), /// To specify the smart label mode for pyramid chart. - smartLabelMode: _mode ?? SmartLabelMode.shift, + smartLabelMode: _mode, series: _getPyramidSeries(), ); } diff --git a/lib/samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart b/lib/samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart index 9fc377c1..edbb5046 100644 --- a/lib/samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart +++ b/lib/samples/datagrid/apperance/conditional_styling/datagrid_conditional_styling.dart @@ -1,6 +1,8 @@ ///Dart import import 'dart:math' as math; +import 'package:flutter/foundation.dart'; + /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; @@ -8,170 +10,113 @@ import 'package:intl/intl.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; -///Core theme import -import 'package:syncfusion_flutter_core/theme.dart'; - /// Local import import '../../../../model/sample_view.dart'; /// Render data grid with conditional styling class ConditionalStylingDataGrid extends SampleView { /// Creates data grid with conditional styling - const ConditionalStylingDataGrid({Key key}) : super(key: key); + const ConditionalStylingDataGrid({Key? key}) : super(key: key); @override _ConditionalStylingDataGridState createState() => _ConditionalStylingDataGridState(); } -List<_Stock> _stockData; - class _ConditionalStylingDataGridState extends SampleViewState { - _ConditionalStylingDataGridState(); - - final math.Random _random = math.Random(); - - final _ConditionalStyleDataGridSource _conditionalStyleDataGridSource = + /// DataGridSource required for SfDataGrid to obtain the row data. + final _ConditionalStyleDataGridSource conditionalStyleDataGridSource = _ConditionalStyleDataGridSource(); - final List _names = [ - 'Maciej', - 'Shelley', - 'Linda', - 'Shanon', - 'Jauna', - 'Michael', - 'Terry', - 'Julie', - 'Twanna', - 'Gary', - 'Carol', - 'James', - 'Martha' - ]; + late bool isWebOrDesktop; - List<_Stock> _generateList(int count) { - final List<_Stock> stockData = <_Stock>[]; - for (int i = 1; i < count; i++) { - stockData.add(_Stock( - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - 1800.0 + _random.nextInt(2000), - 1500.0 + _random.nextInt(1000), - 2000.0 + _random.nextInt(3000), - 1400.0 + _random.nextInt(4000), - )); - } - - return stockData; + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); } - SfDataGrid _dataGridsample() { + SfDataGrid _buildDataGrid() { return SfDataGrid( - source: _conditionalStyleDataGridSource, + source: conditionalStyleDataGridSource, columnWidthMode: ColumnWidthMode.fill, - onQueryCellStyle: (QueryCellStyleArgs args) { - if (args.column.mappingName == 'name') { - return null; - } - if (args.column.mappingName == 'qs1') { - if (double.parse(args.cellValue.toString()) > 2000 && - double.parse(args.cellValue.toString()) < 2500) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFF4C5B9), - textStyle: TextStyle(color: Colors.black)); - } else if (double.parse(args.cellValue.toString()) > 2500) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFEB552C), - textStyle: TextStyle(color: Colors.white)); - } else { - return const DataGridCellStyle( - backgroundColor: Color(0xFFEF8465), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } - } else if (args.column.mappingName == 'qs2') { - if (double.parse(args.cellValue.toString()) > 2000 && - double.parse(args.cellValue.toString()) < 2500) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFF5BD16), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } else if (double.parse(args.cellValue.toString()) > 2500) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFF8DBAE), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } else { - return const DataGridCellStyle( - backgroundColor: Color(0xFFF8DBAE), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } - } else if (args.column.mappingName == 'qs3') { - if (double.parse(args.cellValue.toString()) > 2000 && - double.parse(args.cellValue.toString()) < 4000) { - return const DataGridCellStyle( - backgroundColor: Color(0xFF8A3D94), - textStyle: TextStyle(color: Color.fromRGBO(255, 255, 255, 1))); - } else if (double.parse(args.cellValue.toString()) > 4000) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFC390C1), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } else { - return const DataGridCellStyle( - backgroundColor: Color(0xFFDEB6D5), - textStyle: TextStyle(color: Color.fromRGBO(0, 0, 0, 1))); - } - } else if (double.parse(args.cellValue.toString()) > 2000 && - double.parse(args.cellValue.toString()) < 3000) { - return const DataGridCellStyle( - backgroundColor: Color(0xFF7BC282), - textStyle: TextStyle(color: Colors.black)); - } else if (double.parse(args.cellValue.toString()) > 3000) { - return const DataGridCellStyle( - backgroundColor: Color(0xFFC1DCA7), - textStyle: TextStyle(color: Colors.black)); - } else { - return const DataGridCellStyle( - backgroundColor: Color(0xFF4CAC4C), - textStyle: TextStyle(color: Color.fromRGBO(255, 255, 255, 1))); - } - }, columns: [ - GridTextColumn(mappingName: 'name', headerText: 'Name'), - GridNumericColumn( - mappingName: 'qs1', - headerTextAlignment: Alignment.center, - headerText: 'Q1', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - padding: model.isWeb ? null : const EdgeInsets.all(4)), - GridNumericColumn( - mappingName: 'qs2', - headerTextAlignment: Alignment.center, - headerText: 'Q2', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - padding: model.isWeb ? null : const EdgeInsets.all(4)), - GridNumericColumn( - mappingName: 'qs3', - headerTextAlignment: Alignment.center, - headerText: 'Q3', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - padding: model.isWeb ? null : const EdgeInsets.all(4)), - GridNumericColumn( - mappingName: 'qs4', - headerTextAlignment: Alignment.center, - headerText: 'Q4', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - padding: model.isWeb ? null : const EdgeInsets.all(4)), + GridTextColumn( + columnName: 'name', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150 : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'qs1', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150 : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + child: Center( + child: Text( + 'Q1', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), + GridTextColumn( + columnName: 'qs2', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150 : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + child: Center( + child: Text( + 'Q2', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), + GridTextColumn( + columnName: 'qs3', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150 : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + child: Center( + child: Text( + 'Q3', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), + GridTextColumn( + columnName: 'qs4', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150 : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + child: Center( + child: Text( + 'Q4', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), ], ); } - @override - void initState() { - super.initState(); - _stockData = _generateList(100); - } - @override Widget build(BuildContext context) { - return Scaffold(body: _dataGridsample()); + return Scaffold(body: _buildDataGrid()); } } @@ -190,31 +135,293 @@ class _Stock { final String name; } -class _ConditionalStyleDataGridSource extends DataGridSource<_Stock> { - _ConditionalStyleDataGridSource(); +class _ConditionalStyleDataGridSource extends DataGridSource { + _ConditionalStyleDataGridSource() { + stocks = getStocks(100); + buildDataGridRows(); + } + + final math.Random random = math.Random(); + + List<_Stock> stocks = []; + + List dataGridRows = []; + + /// Rows are generated once and for CRUD operation we have to refresh + /// the data row. + void buildDataGridRows() { + dataGridRows = stocks + .map((dataGridRow) => DataGridRow(cells: [ + DataGridCell( + columnName: 'name', + value: dataGridRow.name, + ), + DataGridCell( + columnName: 'qs1', + value: dataGridRow.qs1, + ), + DataGridCell( + columnName: 'qs2', + value: dataGridRow.qs2, + ), + DataGridCell( + columnName: 'qs3', + value: dataGridRow.qs3, + ), + DataGridCell( + columnName: 'qs4', + value: dataGridRow.qs4, + ), + ])) + .toList(); + } + + // Building the Widget for each data cells + Widget _buildQ1(double value) { + if (value > 2000 && value < 2500) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFF4C5B9), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Colors.black), + overflow: TextOverflow.ellipsis, + ), + )); + } else if (value > 2500) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFEB552C), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Colors.white), + overflow: TextOverflow.ellipsis, + ), + )); + } else { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFEF8465), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(0, 0, 0, 1)), + overflow: TextOverflow.ellipsis, + ), + )); + } + } + + Widget _buildQ2(double value) { + if (value > 2000 && value < 2500) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFF5BD16), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(0, 0, 0, 1)), + overflow: TextOverflow.ellipsis, + ), + )); + } else if (value > 2500) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFF8DBAE), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle( + color: Color.fromRGBO(0, 0, 0, 1), + ), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } else { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFF8DBAE), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(0, 0, 0, 1)), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } + } + + Widget _buildQ3(double value) { + if (value > 2000 && value < 4000) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFF8A3D94), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(255, 255, 255, 1)), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } else if (value > 4000) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFC390C1), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(0, 0, 0, 1)), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } else { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFDEB6D5), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Color.fromRGBO(0, 0, 0, 1)), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } + } + + Widget _buildQ4(double value) { + if (value > 2000 && value < 3000) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFF7BC282), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Colors.black), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } else if (value > 3000) { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFFC1DCA7), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle(color: Colors.black), + overflow: TextOverflow.ellipsis, + ), + ), + ); + } else { + return Container( + padding: EdgeInsets.all(4.0), + color: Color(0xFF4CAC4C), + child: Align( + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(value) + .toString(), + style: TextStyle( + color: Color.fromRGBO(255, 255, 255, 1), + ), + overflow: TextOverflow.ellipsis, + ), + )); + } + } + + // Override method + @override - List<_Stock> get dataSource => _stockData; + List get rows => dataGridRows; + @override - Object getValue(_Stock _stock, String columnName) { - switch (columnName) { - case 'name': - return _stock.name; - break; - case 'qs1': - return _stock.qs1; - break; - case 'qs2': - return _stock.qs2; - break; - case 'qs3': - return _stock.qs3; - break; - case 'qs4': - return _stock.qs4; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + padding: EdgeInsets.all(8.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text(row.getCells()[0].value)), + ), + _buildQ1(row.getCells()[1].value), + _buildQ2(row.getCells()[2].value), + _buildQ3(row.getCells()[3].value), + _buildQ4(row.getCells()[4].value) + ]); + } + + // Generating the stock data collection + + final List names = [ + 'Maciej', + 'Shelley', + 'Linda', + 'Shanon', + 'Jauna', + 'Michael', + 'Terry', + 'Julie', + 'Twanna', + 'Gary', + 'Carol', + 'James', + 'Martha' + ]; + + List<_Stock> getStocks(int count) { + final List<_Stock> stockData = <_Stock>[]; + for (int i = 1; i < count; i++) { + stockData.add(_Stock( + names[i < names.length ? i : random.nextInt(names.length - 1)], + 1800.0 + random.nextInt(2000), + 1500.0 + random.nextInt(1000), + 2000.0 + random.nextInt(3000), + 1400.0 + random.nextInt(4000), + )); } + return stockData; } } diff --git a/lib/samples/datagrid/apperance/styling/datagrid_styling.dart b/lib/samples/datagrid/apperance/styling/datagrid_styling.dart index a0b42450..6f00dadb 100644 --- a/lib/samples/datagrid/apperance/styling/datagrid_styling.dart +++ b/lib/samples/datagrid/apperance/styling/datagrid_styling.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -12,78 +13,39 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:syncfusion_flutter_core/theme.dart'; /// Local import +import '../../../../model/model.dart'; import '../../../../model/sample_view.dart'; /// render data grid widget class StylingDataGrid extends SampleView { /// Creates data grid widget - const StylingDataGrid({Key key}) : super(key: key); + const StylingDataGrid({Key? key}) : super(key: key); @override _StylingDataGridState createState() => _StylingDataGridState(); } -List<_Employee> _employeeData; - class _StylingDataGridState extends SampleViewState { - _StylingDataGridState(); - - final math.Random _random = math.Random(); - - final _StylingDataGridSource _stylingDataGridSource = - _StylingDataGridSource(); - - bool panelOpen; - bool _isLandscapeInMobileView; + /// Supported to notify the panel visibility final ValueNotifier frontPanelVisible = ValueNotifier(true); + void _subscribeToValueNotifier() => panelOpen = frontPanelVisible.value; + bool panelOpen = false; - String _gridLinesVisibility; + /// Determine to decide whether the device in landscape or in portrait + bool isLandscapeInMobileView = false; - GridLinesVisibility gridLineVisibility; + /// Required for SfDataGrid to obtain the row data. + late _StylingDataGridSource stylingDataGridSource; - final List _names = [ - 'Folko', - 'Warth', - 'Alfki', - 'Frans', - 'Welli', - 'Folig', - 'Seves', - 'Furib', - 'Picco', - 'Linod', - 'Simob', - 'Vaffe', - 'Rascu', - 'Blonp', - 'Merep' - ]; - final List _citys = [ - 'Graz', - 'Bruxelles', - 'Rosario', - 'Recife', - 'Campinas', - 'Montreal', - 'Tsawassen', - 'Resende', - ]; + /// Determine to set the gridLineVisibility of SfDataGrid. + late String gridLinesVisibility; - List<_Employee> _generateList(int count) { - final List<_Employee> employeeData = <_Employee>[]; - for (int i = 1; i < count; i++) { - employeeData.add(_Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _citys[_random.nextInt(_citys.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - 1500.0 + _random.nextInt(100), - )); - } - return employeeData; - } + /// Determine to set the gridLineVisibility of SfDataGrid. + late GridLinesVisibility gridLineVisibility; + late bool isWebOrDesktop; + + /// GridLineVisibility strings for drop down widget. final List _encoding = [ 'Both', 'Horizontal', @@ -91,9 +53,9 @@ class _StylingDataGridState extends SampleViewState { 'Vertical', ]; - void _onGridLinesVisibilitychanges(String item) { - _gridLinesVisibility = item; - switch (_gridLinesVisibility) { + void _onGridLinesVisibilityChanges(String item) { + gridLinesVisibility = item; + switch (gridLinesVisibility) { case 'Both': gridLineVisibility = GridLinesVisibility.both; break; @@ -111,81 +73,164 @@ class _StylingDataGridState extends SampleViewState { } List getColumns() { - return model.isWeb + final textStyle = TextStyle(color: Color.fromRGBO(255, 255, 255, 1)); + return isWebOrDesktop ? [ - GridNumericColumn( - mappingName: 'orderId', - headerText: 'Order ID', - headerTextAlignment: Alignment.centerRight), - GridNumericColumn( - mappingName: 'customerId', - headerText: 'Customer ID', - headerTextAlignment: Alignment.centerRight), GridTextColumn( - mappingName: 'name', - headerText: 'Name', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'freight', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight', - headerTextAlignment: Alignment.centerRight), + columnName: 'orderId', + width: (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Order ID', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'customerId', + width: 120.0, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Customer ID', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'name', + width: (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Name', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'freight', + width: (isWebOrDesktop && model.isMobileResolution) + ? 100.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Freight', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + width: (isWebOrDesktop && model.isMobileResolution) + ? 100.0 + : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'City', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'city', - headerText: 'City', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'price', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Price') + columnName: 'price', + width: (isWebOrDesktop && model.isMobileResolution) + ? 115.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Price', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ) ] : [ - GridNumericColumn( - mappingName: 'orderId', - headerTextAlignment: Alignment.centerRight, - headerText: 'Order ID'), - GridNumericColumn( - mappingName: 'customerId', - padding: const EdgeInsets.all(8), - columnWidthMode: _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.header, - headerTextAlignment: Alignment.centerRight, - headerText: 'Customer ID'), GridTextColumn( - mappingName: 'name', - headerTextAlignment: Alignment.centerLeft, - headerText: 'Name'), + columnName: 'orderId', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'city', - headerTextAlignment: Alignment.centerLeft, - headerText: 'City') + width: 100, + columnName: 'customerId', + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'name', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + style: textStyle, + overflow: TextOverflow.ellipsis, + ), + ), + ) ]; } - SfDataGridTheme _dataGridSample([GridLinesVisibility gridLineVisibility]) { + SfDataGridTheme _buildDataGrid(GridLinesVisibility gridLineVisibility) { return SfDataGridTheme( data: SfDataGridThemeData( brightness: model.themeData.brightness, - headerStyle: DataGridHeaderCellStyle( - backgroundColor: Color(0xFF6C59CF), - textStyle: TextStyle(color: Color.fromRGBO(255, 255, 255, 1)), - hoverColor: Color(0xFF9588D7).withOpacity(0.6))), + headerHoverColor: Colors.white.withOpacity(0.3), + headerColor: model.backgroundColor), child: SfDataGrid( - source: _stylingDataGridSource, + source: stylingDataGridSource, columnWidthMode: ColumnWidthMode.fill, gridLinesVisibility: gridLineVisibility, - onQueryRowStyle: (QueryRowStyleArgs args) { - return ((args.rowIndex) % 2 == 0) - ? DataGridCellStyle( - backgroundColor: model.themeData.brightness == Brightness.dark - ? const Color(0xFF2E2946) - : const Color.fromRGBO(245, 244, 255, 1), - ) - : null; - }, columns: getColumns(), ), ); @@ -194,21 +239,22 @@ class _StylingDataGridState extends SampleViewState { @override void initState() { super.initState(); - _gridLinesVisibility = 'None'; + isWebOrDesktop = (model.isWeb || model.isDesktop); + stylingDataGridSource = + _StylingDataGridSource(model: model, isWebOrDesktop: isWebOrDesktop); + gridLinesVisibility = 'None'; gridLineVisibility = GridLinesVisibility.horizontal; panelOpen = frontPanelVisible.value; frontPanelVisible.addListener(_subscribeToValueNotifier); - _employeeData = _generateList(100); } @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + isLandscapeInMobileView = !isWebOrDesktop && MediaQuery.of(context).orientation == Orientation.landscape; } - void _subscribeToValueNotifier() => panelOpen = frontPanelVisible.value; @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -225,7 +271,7 @@ class _StylingDataGridState extends SampleViewState { trailing: Theme( data: ThemeData(canvasColor: model.bottomSheetBackgroundColor), child: DropdownButton( - value: _gridLinesVisibility, + value: gridLinesVisibility, items: _encoding.map((String value) { return DropdownMenuItem( value: (value != null) ? value : 'None', @@ -234,7 +280,7 @@ class _StylingDataGridState extends SampleViewState { style: TextStyle(color: model.textColor))); }).toList(), onChanged: (dynamic value) { - _onGridLinesVisibilitychanges(value); + _onGridLinesVisibilityChanges(value); stateSetter(() {}); }), ), @@ -243,9 +289,34 @@ class _StylingDataGridState extends SampleViewState { }); } + BoxDecoration drawBorder() { + final borderSide = BorderSide( + width: 1.0, + color: model.themeData.brightness == Brightness.light + ? const Color.fromRGBO(0, 0, 0, 0.26) + : const Color.fromRGBO(255, 255, 255, 0.26)); + return BoxDecoration( + border: + Border(left: borderSide, right: borderSide, bottom: borderSide)); + } + @override Widget build(BuildContext context) { - return _dataGridSample(gridLineVisibility); + return Container( + color: model.themeData.brightness == Brightness.light + ? Color(0xFFFAFAFA) + : null, + child: Card( + margin: isWebOrDesktop + ? const EdgeInsets.all(24.0) + : const EdgeInsets.all(16.0), + clipBehavior: Clip.antiAlias, + elevation: 1.0, + child: Padding( + padding: EdgeInsets.all(16.0), + child: Container( + decoration: drawBorder(), + child: _buildDataGrid(gridLineVisibility))))); } } @@ -260,34 +331,187 @@ class _Employee { final double price; } -class _StylingDataGridSource extends DataGridSource<_Employee> { - _StylingDataGridSource(); +class _StylingDataGridSource extends DataGridSource { + _StylingDataGridSource({required this.model, required this.isWebOrDesktop}) { + employees = getEmployees(100); + buildDataGridRows(); + } + + final math.Random random = math.Random(); + final SampleModel model; + List<_Employee> employees = []; + List dataGridRows = []; + final bool isWebOrDesktop; + + /// Build DataGridRow collection + + void buildDataGridRows() { + dataGridRows = isWebOrDesktop + ? employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'orderId', value: dataGridRow.orderId), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false) + : employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'orderId', value: dataGridRow.orderId), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'city', value: dataGridRow.city), + ]); + }).toList(growable: false); + } + + // Overrides + @override - List<_Employee> get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(_Employee _employee, String columnName) { - switch (columnName) { - case 'orderId': - return _employee.orderId; - break; - case 'customerId': - return _employee.customerId; - break; - case 'name': - return _employee.name; - break; - case 'freight': - return _employee.freight; - break; - case 'price': - return _employee.price; - break; - case 'city': - return _employee.city; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + final rowIndex = dataGridRows.indexOf(row); + var backgroundColor = Colors.transparent; + if ((rowIndex % 2) == 0) { + backgroundColor = model.backgroundColor.withOpacity(0.07); + } + + if (isWebOrDesktop) { + return DataGridRowAdapter(color: backgroundColor, cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + ]); + } else { + return DataGridRowAdapter(color: backgroundColor, cells: [ + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[3].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } + } + + // _Employee data sets + + final List names = [ + 'Folko', + 'Warth', + 'Alfki', + 'Frans', + 'Welli', + 'Folig', + 'Seves', + 'Furib', + 'Picco', + 'Linod', + 'Simob', + 'Vaffe', + 'Rascu', + 'Blonp', + 'Merep' + ]; + final List cities = [ + 'Graz', + 'Bruxelles', + 'Rosario', + 'Recife', + 'Campinas', + 'Montreal', + 'Tsawassen', + 'Resende', + ]; + + List<_Employee> getEmployees(int count) { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < count; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + cities[random.nextInt(cities.length - 1)], + random.nextInt(1000) + random.nextDouble(), + 1500.0 + random.nextInt(100), + )); } + return employeeData; } } diff --git a/lib/samples/datagrid/auto_row_height/datagrid_auto_row_height.dart b/lib/samples/datagrid/auto_row_height/datagrid_auto_row_height.dart deleted file mode 100644 index 1c061c67..00000000 --- a/lib/samples/datagrid/auto_row_height/datagrid_auto_row_height.dart +++ /dev/null @@ -1,379 +0,0 @@ -/// Flutter package imports -import 'package:flutter/material.dart'; - -/// Barcode imports -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; -import 'package:syncfusion_flutter_core/theme.dart'; - -/// Local imports -import '../../../model/sample_view.dart'; - -///Renders data grid with auto row height - -List _employees; - -class AutoRowHeightDataGrid extends SampleView { - ///Creates data grid with auto row height - const AutoRowHeightDataGrid({Key key}) : super(key: key); - - @override - _AutoRowHeightDataGridState createState() => _AutoRowHeightDataGridState(); -} - -class _AutoRowHeightDataGridState extends SampleViewState { - _AutoRowHeightDataGridState(); - - final _AutoRowHeightDataGridSource _autoRowHeightDataGridSource = - _AutoRowHeightDataGridSource(); - - final ColumnSizer _columnSizer = ColumnSizer(); - - void populateData() { - _employees.add(Employee( - 'ALFKI', - 'Maria Anders', - 'Alfreds Futterkiste', - 'Obere Str. 57', - 'Berlin', - 'Germany', - 'Sales Representative', - '12209', - '030-0074321')); - _employees.add(Employee( - 'ANATR', - 'Ana Trujillo', - 'Ana Trujillo Emparedados y helados', - 'Avda. de la Constitución 2222', - 'México D.F.', - 'Mexico', - 'Owner', - '05021', - '(5) 555-4729')); - _employees.add(Employee( - 'ANTON', - 'Antonio Moreno', - 'Antonio Moreno Taquería', - 'Mataderos 2312', - 'México D.F', - 'Mexico', - 'Owner', - '05023', - '(5) 555-3932')); - _employees.add(Employee( - 'AROUT', - 'Thomas Hardy', - 'Around the Horn', - '120 Hanover Sq.', - 'London', - 'UK', - 'Sales Representative', - 'WA1 1DP', - '(71) 555-7788')); - _employees.add(Employee( - 'BERGS', - 'Christina Berglund', - 'Berglunds snabbköp', - 'Berguvsvägen 8', - 'Luleå', - 'Sweden', - 'Order Administrator', - 'S-958 22', - '0921-12 34 65')); - _employees.add(Employee( - 'BLAUS', - 'Hanna Moos', - 'Blauer See Delikatessen', - 'Forsterstr. 57', - 'Mannheim', - 'Germany', - 'Sales Representative', - '68306', - '0621-08460')); - _employees.add(Employee( - 'BLONP', - 'Frédérique Citeaux', - 'Blondel père et fils', - '24, place Kléber', - 'Strasbourg', - 'France', - 'Marketing Manager', - '67000', - '88.60.15.31')); - _employees.add(Employee( - 'BOLID', - 'Martín Sommer', - 'Bólido Comidas preparadas', - 'C/ Araquil, 67', - 'Madrid', - 'Spain', - 'Marketing Manager' 'Owner', - '28023', - '(91) 555 22 82')); - _employees.add(Employee( - 'BONAP', - 'Laurence Lebihan', - ''' Bon app' ''', - '12, rue des Bouchers', - 'Marseille', - 'France', - 'Owner', - '13008', - '91.24.45.40')); - _employees.add(Employee( - 'BOTTM', - 'Elizabeth Lincoln', - 'Bottom-Dollar Markets', - '23 Tsawassen Blvd.', - 'Tsawassen', - 'Canada', - 'Accounting Manager', - 'T2F 8M4', - '(604) 555-4729')); - _employees.add(Employee( - 'BSBEV', - 'Victoria Ashworth', - '''B's Beverages''', - 'Fauntleroy Circus', - 'London', - 'UK', - 'Sales Representative', - 'EC2 5NT', - '(71) 555-1212')); - _employees.add(Employee( - 'CACTU', - 'Patricio Simpson', - 'Cactus Comidas para llevar', - 'Cerrito 333', - 'Buenos Aires', - 'Argentina', - 'Sales Agent', - '1010', - '(1) 135-5555')); - _employees.add(Employee( - 'CENTC', - 'Francisco Chang', - 'Centro comercial Moctezuma', - 'Sierras de Granada 9993', - 'México D.F.', - 'Mexico', - 'Marketing Manager', - '05022', - '0452-076545')); - _employees.add(Employee( - 'CHOPS', - 'Yang Wang', - 'Chop-suey Chinese', - 'Hauptstr. 29', - 'Bern', - 'Switzerland', - 'Owner', - '3012', - '(5) 555-3392')); - _employees.add(Employee( - 'COMMI', - 'Pedro Afonso', - 'Comércio Mineiro', - 'Av. dos Lusíadas, 23', - 'São Paulo', - 'Brazil', - 'Sales Associate', - '05432-043', - '(11) 555-7647')); - _employees.add(Employee( - 'CONSH', - 'Elizabeth Brown', - 'Consolidated Holdings', - ''' Berkeley Gardens -12 Brewery ''', - 'London', - 'UK', - 'Sales Representative', - 'WX1 6LT', - '7675-3425')); - _employees.add(Employee( - 'DRACD', - 'Sven Ottlieb', - 'Drachenblut Delikatessen', - 'Walserweg 21', - 'Aachen', - 'Germany', - 'Order Administrator', - '52066', - '(71) 555-2282')); - _employees.add(Employee( - 'DUMON', - 'Janine Labrune', - 'Du monde entier', - '67, rue des Cinquante Otages', - 'Nantes', - 'France', - 'Owner', - '44000', - '0241-039123')); - _employees.add(Employee( - 'EASTC', - 'Ann Devon', - 'Eastern Connection', - '35 King George', - 'London', - 'UK', - 'Sales Agent', - 'WX3 6FW', - '40.67.88.88')); - _employees.add(Employee( - 'ERNSH', - 'Roland Mendel', - 'Ernst Handel', - 'Kirchgasse 6', - 'Graz', - 'Austria', - 'Sales Manager', - '8010', - '(71) 555-0297')); - } - - Widget _dataGridSample() { - return SfDataGridTheme( - data: SfDataGridThemeData( - brightness: SfTheme.of(context).brightness, - gridLineStrokeWidth: 1.4, - ), - child: SfDataGrid( - source: _autoRowHeightDataGridSource, - columnSizer: _columnSizer, - onQueryRowHeight: (RowHeightDetails rowHeightDetails) { - final double height = - _columnSizer.getAutoRowHeight(rowHeightDetails.rowIndex); - return height; - }, - columns: [ - GridTextColumn( - mappingName: 'id', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 135 : 90, - headerText: 'ID', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'contactName', - softWrap: true, - columnWidthMode: - model.isWeb ? ColumnWidthMode.auto : ColumnWidthMode.header, - overflow: TextOverflow.clip, - headerText: 'Contact Name', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'companyName', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 165 : 140, - headerText: 'Company Name', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'address', - softWrap: true, - width: model.isWeb ? 180 : 140, - overflow: TextOverflow.clip, - headerText: 'Address', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'city', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 150 : 120, - headerText: 'City', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'country', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 150 : 120, - headerText: 'Country', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'designation', - softWrap: true, - overflow: TextOverflow.clip, - columnWidthMode: ColumnWidthMode.auto, - headerText: 'Designation', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'postalCode', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Postal Code', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - GridTextColumn( - mappingName: 'phoneNumber', - columnWidthMode: ColumnWidthMode.auto, - headerText: 'Phone Number', - padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16)), - ]), - ); - } - - @override - void initState() { - super.initState(); - _employees = []; - populateData(); - } - - @override - Widget build(BuildContext context) { - return Scaffold(body: _dataGridSample()); - } -} - -class Employee { - Employee(this.id, this.contactName, this.companyName, this.address, this.city, - this.country, this.designation, this.postalCode, this.phoneNumber); - final String id; - final String contactName; - final String companyName; - final String address; - final String city; - final String country; - final String designation; - final String postalCode; - final String phoneNumber; -} - -class _AutoRowHeightDataGridSource extends DataGridSource { - @override - List get dataSource => _employees; - @override - Object getValue(Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'companyName': - return _employee.companyName; - break; - case 'contactName': - return _employee.contactName; - break; - case 'address': - return _employee.address; - break; - case 'city': - return _employee.city; - break; - case 'country': - return _employee.country; - break; - case 'designation': - return _employee.designation; - break; - case 'postalCode': - return _employee.postalCode; - break; - case 'phoneNumber': - return _employee.phoneNumber; - break; - default: - return 'empty'; - break; - } - } -} diff --git a/lib/samples/datagrid/columns/datagrid_column_types.dart b/lib/samples/datagrid/columns/datagrid_column_types.dart index 73d3d140..a06747e8 100644 --- a/lib/samples/datagrid/columns/datagrid_column_types.dart +++ b/lib/samples/datagrid/columns/datagrid_column_types.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// Barcode imports import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -14,41 +15,270 @@ import '../../../model/sample_view.dart'; /// Renders column type data grid class ColumnTypeDataGrid extends SampleView { /// Creates column type data grid - const ColumnTypeDataGrid({Key key}) : super(key: key); + const ColumnTypeDataGrid({Key? key}) : super(key: key); @override _ColumnTypesDataGridState createState() => _ColumnTypesDataGridState(); } -List<_Employee> _employeeData; - class _ColumnTypesDataGridState extends SampleViewState { - _ColumnTypesDataGridState(); + /// Required for SfDataGrid to obtain the row data. + final _ColumnTypesDataGridSource columnTypesDataGridSource = + _ColumnTypesDataGridSource(); - final math.Random _random = math.Random(); - bool _isLandscapeInMobileView; + /// Determine to decide whether the device in landscape or in portrait + late bool isLandscapeInMobileView; - final _ColumnTypesDataGridSource _columnTypesDataGridSource = - _ColumnTypesDataGridSource(); + late bool isWebOrDesktop; - List<_Employee> _generateList(int count) { - final List<_Employee> employeeData = <_Employee>[]; - for (int i = 0; i < count; i++) { - employeeData.add(_Employee( - 1100 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _dealers[ - i < _dealers.length ? i : _random.nextInt(_dealers.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _shippedDates[_random.nextInt(_shippedDates.length - 1)], - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); - } - return employeeData; + SfDataGrid _buildDataGrid(BuildContext context) { + return SfDataGrid( + source: columnTypesDataGridSource, + columnWidthMode: isWebOrDesktop + ? (isWebOrDesktop && model.isMobileResolution) + ? ColumnWidthMode.none + : ColumnWidthMode.fill + : ColumnWidthMode.none, + columns: [ + GridTextColumn( + columnName: 'dealer', + width: 90, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + 'Dealer', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'id', + width: !isWebOrDesktop + ? 50 + : (isWebOrDesktop && model.isMobileResolution) + ? 110 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'ID', + overflow: TextOverflow.ellipsis, + ), + ), + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none), + GridTextColumn( + columnName: 'name', + width: + (isWebOrDesktop && model.isMobileResolution) ? 110 : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'freight', + width: + (isWebOrDesktop && model.isMobileResolution) ? 110 : double.nan, + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + label: Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8.0), + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'shippedDate', + width: 110, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Shipped Date', + overflow: TextOverflow.ellipsis, + ), + ), + //dateFormat: DateFormat.yMd() + ), + GridTextColumn( + columnName: 'city', + width: isWebOrDesktop ? 110.0 : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'price', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + )) + ]); + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + isLandscapeInMobileView = !isWebOrDesktop && + MediaQuery.of(context).orientation == Orientation.landscape; + } + + @override + Widget build(BuildContext context) { + return Scaffold(body: _buildDataGrid(context)); + } +} + +class _Employee { + _Employee( + this.id, + this.name, + this.dealer, + this.freight, + this.shippedDate, + this.city, + this.price, + ); + final int id; + final String name; + final double price; + final DateTime shippedDate; + final Image dealer; + final double freight; + final String city; +} + +class _ColumnTypesDataGridSource extends DataGridSource { + _ColumnTypesDataGridSource() { + employees = getEmployees(100); + buildDataGridRows(); + } + + final math.Random random = math.Random(); + List dataGridRows = []; + List<_Employee> employees = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'dealer', value: dataGridRow.dealer), + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'shippedDate', value: dataGridRow.shippedDate), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false); } - final List _dealers = [ + // Overrides + + @override + List get rows => dataGridRows; + + Widget buildDealer(dynamic value) { + return Container( + padding: const EdgeInsets.all(3), + alignment: Alignment.center, + child: value, + ); + } + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + buildDealer(row.getCells()[0].value), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + DateFormat.yMd().format(row.getCells()[4].value).toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[6].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } + + // _Employee Data set + + final List dealers = [ Image.asset('images/People_Circle2.png'), Image.asset('images/People_Circle18.png'), Image.asset('images/People_Circle3.png'), @@ -76,7 +306,7 @@ class _ColumnTypesDataGridState extends SampleViewState { Image.asset('images/People_Circle27.png'), ]; - final List _names = [ + final List names = [ 'Betts', 'Adams', 'Crowley', @@ -92,7 +322,7 @@ class _ColumnTypesDataGridState extends SampleViewState { 'Grimes' ]; - final List _shippedDates = [ + final List shippedDates = [ DateTime.now(), DateTime(2002, 8, 27), DateTime(2015, 7, 4), @@ -108,7 +338,7 @@ class _ColumnTypesDataGridState extends SampleViewState { DateTime(2013, 10, 22), ]; - final List _citys = [ + final List cities = [ 'Graz', 'Bruxelles', 'Rosario', @@ -119,126 +349,19 @@ class _ColumnTypesDataGridState extends SampleViewState { 'Resende', ]; - SfDataGrid _getDataGrid() { - return SfDataGrid( - source: _columnTypesDataGridSource, - columnWidthMode: - model.isWeb ? ColumnWidthMode.fill : ColumnWidthMode.auto, - cellBuilder: (BuildContext context, GridColumn column, int rowIndex) { - return Container( - padding: const EdgeInsets.all(3), - child: _employeeData[rowIndex].dealer, - ); - }, - columns: [ - GridWidgetColumn( - mappingName: 'dealer', width: 90, headerText: 'Dealer'), - GridNumericColumn( - mappingName: 'id', - headerText: ' ID', - columnWidthMode: _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.none, - headerTextAlignment: Alignment.centerRight), - GridTextColumn( - mappingName: 'name', - headerText: 'Name', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'freight', - textAlignment: Alignment.center, - headerTextAlignment: Alignment.center, - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - columnWidthMode: _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.none, - headerText: 'Freight'), - GridDateTimeColumn( - mappingName: 'shippedDate', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Shipped Date', - dateFormat: DateFormat.yMd()), - GridTextColumn( - mappingName: 'city', - headerText: 'City', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'price', - headerTextAlignment: Alignment.centerRight, - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - columnWidthMode: ColumnWidthMode.lastColumnFill, - headerText: 'Price') - ]); - } - - @override - void initState() { - super.initState(); - _employeeData = _generateList(100); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && - MediaQuery.of(context).orientation == Orientation.landscape; - } - - @override - Widget build(BuildContext context) { - return Scaffold(body: _getDataGrid()); - } -} - -class _Employee { - _Employee( - this.id, - this.name, - this.dealer, - this.freight, - this.shippedDate, - this.city, - this.price, - ); - final int id; - final String name; - final double price; - final DateTime shippedDate; - final Image dealer; - final double freight; - final String city; -} - -class _ColumnTypesDataGridSource extends DataGridSource<_Employee> { - _ColumnTypesDataGridSource(); - @override - List<_Employee> get dataSource => _employeeData; - @override - Object getValue(_Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'name': - return _employee.name; - break; - case 'shippedDate': - return _employee.shippedDate; - break; - case 'freight': - return _employee.freight; - break; - case 'city': - return _employee.city; - break; - case 'price': - return _employee.price; - break; - default: - return 'empty'; - break; + List<_Employee> getEmployees(int count) { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < count; i++) { + employeeData.add(_Employee( + 1100 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + dealers[i < dealers.length ? i : random.nextInt(dealers.length - 1)], + random.nextInt(1000) + random.nextDouble(), + shippedDates[random.nextInt(shippedDates.length - 1)], + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); } + return employeeData; } } diff --git a/lib/samples/datagrid/columns/datagrid_custom_header.dart b/lib/samples/datagrid/columns/datagrid_custom_header.dart index 4619521a..e473d134 100644 --- a/lib/samples/datagrid/columns/datagrid_custom_header.dart +++ b/lib/samples/datagrid/columns/datagrid_custom_header.dart @@ -1,34 +1,41 @@ +import 'dart:math'; + +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:flutter_examples/model/sample_view.dart'; -import 'package:syncfusion_flutter_core/theme.dart'; -import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; -import 'dart:math'; - -List _productData; -Random _random = Random(); +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:collection/collection.dart'; +/// Renders custom header data grid sample class CustomHeaderDataGrid extends SampleView { - CustomHeaderDataGrid({Key key}) : super(key: key); + /// Creates custom header data grid sample + CustomHeaderDataGrid({Key? key}) : super(key: key); @override _CustomHeaderDataGridState createState() => _CustomHeaderDataGridState(); } class _CustomHeaderDataGridState extends SampleViewState { - _SortingDataSource _source; - List _columns; GlobalKey key = GlobalKey(); - List _showMenuItems = ['Ascending', 'Descending', 'Clear Sorting']; + /// DataGridSource required for SfDataGrid to obtain the row data. + late _SortingDataSource source; + + /// Collection of GridColumn and it required for SfDataGrid + late List columns; + + /// Default sorting operating in drop down widget + List showMenuItems = ['Ascending', 'Descending', 'Clear Sorting']; + + late bool isWebOrDesktop; @override void initState() { super.initState(); - _productData = generateList(20); - _source = _SortingDataSource(); - _columns = getColumns(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + columns = getColumns(); + source = _SortingDataSource(); } Widget buildMenuItem(GridColumn column, String value) { @@ -44,36 +51,35 @@ class _CustomHeaderDataGridState extends SampleViewState { List buildMenuItems(GridColumn column) { List menuItems; - final sortColumn = _source.sortedColumns.firstWhere( - (sortColumn) => sortColumn.name == column.mappingName, - orElse: () => null); + final sortColumn = source.sortedColumns + .firstWhereOrNull((sortColumn) => sortColumn.name == column.columnName); menuItems = [ PopupMenuItem( - child: buildMenuItem(column, _showMenuItems[0]), - value: _showMenuItems[0], + value: showMenuItems[0], enabled: sortColumn != null ? sortColumn.sortDirection == DataGridSortDirection.ascending ? false : true : true, + child: buildMenuItem(column, showMenuItems[0]), ), PopupMenuItem( - child: buildMenuItem(column, _showMenuItems[1]), - value: _showMenuItems[1], + value: showMenuItems[1], enabled: sortColumn != null ? sortColumn.sortDirection == DataGridSortDirection.descending ? false : true : true, + child: buildMenuItem(column, showMenuItems[1]), ), ]; if (sortColumn != null) { menuItems.add(PopupMenuItem( - child: buildMenuItem(column, _showMenuItems[2]), - value: _showMenuItems[2], - enabled: _source.sortedColumns.isNotEmpty ? true : false, + value: showMenuItems[2], + enabled: source.sortedColumns.isNotEmpty ? true : false, + child: buildMenuItem(column, showMenuItems[2]), )); } @@ -84,34 +90,30 @@ class _CustomHeaderDataGridState extends SampleViewState { switch (value) { case 'Ascending': case 'Descending': - if (_source.sortedColumns.isNotEmpty) { - _source.sortedColumns.clear(); + if (source.sortedColumns.isNotEmpty) { + source.sortedColumns.clear(); } - _source.sortedColumns.add(SortColumnDetails( - name: gridColumn.mappingName, + source.sortedColumns.add(SortColumnDetails( + name: gridColumn.columnName, sortDirection: value == 'Ascending' ? DataGridSortDirection.ascending : DataGridSortDirection.descending)); - _source.sort(); + source.sort(); break; case 'Clear Sorting': - if (_source.sortedColumns.isNotEmpty) { - _source.sortedColumns.clear(); - _source.sort(); + if (source.sortedColumns.isNotEmpty) { + source.sortedColumns.clear(); + source.sort(); } break; } } - Widget buildHeaderCell(GridColumn column) { - final themeData = - SfDataGridThemeData(brightness: model.themeData.brightness); + Widget buildHeaderCell(Widget headerChild) { return Container( child: Row( children: [ - Flexible( - child: Text(column.headerText, - style: themeData.headerStyle.textStyle)), + Flexible(child: headerChild), Icon( Icons.keyboard_arrow_down, size: 25, @@ -121,17 +123,23 @@ class _CustomHeaderDataGridState extends SampleViewState { )); } - buildShowMenu(BuildContext context, DataGridCellTapDetails details) { + void buildShowMenu(BuildContext context, DataGridCellTapDetails details) { double dx = 0.0, dy = 0.0; final rowHeight = 56.0; - if (kIsWeb) { - RenderBox getBox = context.findRenderObject(); + if (isWebOrDesktop) { + final RenderBox getBox = context.findRenderObject() as RenderBox; final local = getBox.globalToLocal(details.globalPosition); dx = local.dx - details.localPosition.dx; dy = local.dy - details.localPosition.dy + rowHeight; + // After Flutter v2.0, the 8.0 pixels added extra to the showMenu by default in the web and desktop. + // Removed the extra pixels to aligned the pop up in the bottom of header cell. + dy -= 8.0; } else { dx = details.globalPosition.dx - details.localPosition.dx; dy = details.globalPosition.dy - details.localPosition.dy + rowHeight; + // After Flutter v2.0, the 24.0 pixels added extra to the showMenu by default in the mobile. + // Removed the extra pixels to aligned the pop up in the bottom of header cell. + dy -= 24.0; } showMenu( @@ -144,8 +152,8 @@ class _CustomHeaderDataGridState extends SampleViewState { Widget build(BuildContext context) { return SfDataGrid( key: key, - source: _source, - columns: _columns, + source: source, + columns: columns, gridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both, onCellTap: (details) { @@ -153,179 +161,99 @@ class _CustomHeaderDataGridState extends SampleViewState { buildShowMenu(context, details); } }, - headerCellBuilder: (BuildContext context, GridColumn column) { - return buildHeaderCell(column); - }, ); } List getColumns() { List columns; columns = [ - GridNumericColumn(mappingName: 'id', width: 140, headerText: 'Order ID'), - GridNumericColumn( - mappingName: 'productId', width: 150, headerText: 'Product ID'), GridTextColumn( - mappingName: 'name', width: 185, headerText: 'Customer Name'), - GridTextColumn(mappingName: 'product', width: 135, headerText: 'Product'), - GridDateTimeColumn( - mappingName: 'orderDate', + columnName: 'id', + width: 140, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'productId', width: 150, - dateFormat: DateFormat('MM/dd/yyyy'), - headerText: 'Order Date'), - GridNumericColumn( - mappingName: 'quantity', width: 135, headerText: 'Quantity'), - GridTextColumn(mappingName: 'city', width: 130, headerText: 'City'), - GridNumericColumn( - mappingName: 'unitPrice', + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Product ID', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'name', + width: 185, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Customer Name', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'product', + width: 135, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Product', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'orderDate', + width: 150, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Order Date', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'quantity', + width: 135, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Quantity', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'city', + width: 130, + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ))), + GridTextColumn( + columnName: 'unitPrice', width: 140, - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Unit Price'), + label: buildHeaderCell(Container( + padding: EdgeInsets.all(8), + child: Text( + 'Unit Price', + overflow: TextOverflow.ellipsis, + ), + ))), ]; return columns; } } -final List _product = [ - 'Lax', - 'Chocolate', - 'Syrup', - 'Chai', - 'Bags', - 'Meat', - 'Filo', - 'Cashew', - 'Walnuts', - 'Geitost', - 'Cote de', - 'Crab', - 'Chang', - 'Cajun', - 'Gum', - 'Filo', - 'Cashew', - 'Walnuts', - 'Geitost', - 'Bag', - 'Meat', - 'Filo', - 'Cashew', - 'Geitost', - 'Cote de', - 'Crab', - 'Chang', - 'Cajun', - 'Gum', -]; - -final List _cities = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', -]; - -final List _productId = [ - 3524, - 2523, - 1345, - 5243, - 1803, - 4932, - 6532, - 9475, - 2435, - 2123, - 3652, - 4523, - 4263, - 3527, - 3634, - 4932, - 6532, - 9475, - 2435, - 2123, - 6532, - 9475, - 2435, - 2123, - 4523, - 4263, - 3527, - 3634, - 4932, -]; - -final List _orderDate = [ - DateTime.now(), - DateTime(2002, 8, 27), - DateTime(2015, 7, 4), - DateTime(2007, 4, 15), - DateTime(2010, 12, 23), - DateTime(2010, 4, 20), - DateTime(2004, 6, 13), - DateTime(2008, 11, 11), - DateTime(2005, 7, 29), - DateTime(2009, 4, 5), - DateTime(2003, 3, 20), - DateTime(2011, 3, 8), - DateTime(2013, 10, 22), -]; - -List _names = [ - 'Kyle', - 'Gina', - 'Irene', - 'Katie', - 'Michael', - 'Oscar', - 'Ralph', - 'Torrey', - 'William', - 'Bill', - 'Daniel', - 'Frank', - 'Brenda', - 'Danielle', - 'Fiona', - 'Howard', - 'Jack', - 'Larry', - 'Holly', - 'Jennifer', - 'Liz', - 'Pete', - 'Steve', - 'Vince', - 'Zeke' -]; - -List generateList(int count) { - final List productData = []; - for (int i = 0; i < count; i++) { - productData.add( - Product( - i + 1000, - _productId[i], - _product[i], - _random.nextInt(20), - 70.0 + _random.nextInt(100), - _cities[i < _cities.length ? i : _random.nextInt(_cities.length - 1)], - _orderDate[_random.nextInt(_orderDate.length - 1)], - _names[i]), - ); - } - - return productData; -} - -class Product { - Product(this.id, this.productId, this.product, this.quantity, this.unitPrice, +class _Product { + _Product(this.id, this.productId, this.product, this.quantity, this.unitPrice, this.city, this.orderDate, this.name); final int id; final int productId; @@ -337,40 +265,244 @@ class Product { final String name; } -class _SortingDataSource extends DataGridSource { - _SortingDataSource(); +class _SortingDataSource extends DataGridSource { + _SortingDataSource() { + products = getProducts(20); + buildDataGridRows(); + } + + final Random random = Random(); + List<_Product> products = []; + + List dataGridRows = []; + + void buildDataGridRows() { + dataGridRows = products.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'productId', value: dataGridRow.productId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'product', value: dataGridRow.product), + DataGridCell( + columnName: 'orderDate', value: dataGridRow.orderDate), + DataGridCell(columnName: 'quantity', value: dataGridRow.quantity), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell( + columnName: 'unitPrice', value: dataGridRow.unitPrice), + ]); + }).toList(); + } + @override - List get dataSource => _productData; + List get rows => dataGridRows; + @override - Object getValue(Product _product, String columnName) { - switch (columnName) { - case 'id': - return _product.id; - break; - case 'product': - return _product.product; - break; - case 'productId': - return _product.productId; - break; - case 'unitPrice': - return _product.unitPrice; - break; - case 'quantity': - return _product.quantity; - break; - case 'city': - return _product.city; - break; - case 'orderDate': - return _product.orderDate; - break; - case 'name': - return _product.name; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[3].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + DateFormat('MM/dd/yyyy').format(row.getCells()[4].value).toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[6].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[7].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } + + final List product = [ + 'Lax', + 'Chocolate', + 'Syrup', + 'Chai', + 'Bags', + 'Meat', + 'Filo', + 'Cashew', + 'Walnuts', + 'Geitost', + 'Cote de', + 'Crab', + 'Chang', + 'Cajun', + 'Gum', + 'Filo', + 'Cashew', + 'Walnuts', + 'Geitost', + 'Bag', + 'Meat', + 'Filo', + 'Cashew', + 'Geitost', + 'Cote de', + 'Crab', + 'Chang', + 'Cajun', + 'Gum', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + final List productId = [ + 3524, + 2523, + 1345, + 5243, + 1803, + 4932, + 6532, + 9475, + 2435, + 2123, + 3652, + 4523, + 4263, + 3527, + 3634, + 4932, + 6532, + 9475, + 2435, + 2123, + 6532, + 9475, + 2435, + 2123, + 4523, + 4263, + 3527, + 3634, + 4932, + ]; + + final List orderDate = [ + DateTime.now(), + DateTime(2002, 8, 27), + DateTime(2015, 7, 4), + DateTime(2007, 4, 15), + DateTime(2010, 12, 23), + DateTime(2010, 4, 20), + DateTime(2004, 6, 13), + DateTime(2008, 11, 11), + DateTime(2005, 7, 29), + DateTime(2009, 4, 5), + DateTime(2003, 3, 20), + DateTime(2011, 3, 8), + DateTime(2013, 10, 22), + ]; + + List names = [ + 'Kyle', + 'Gina', + 'Irene', + 'Katie', + 'Michael', + 'Oscar', + 'Ralph', + 'Torrey', + 'William', + 'Bill', + 'Daniel', + 'Frank', + 'Brenda', + 'Danielle', + 'Fiona', + 'Howard', + 'Jack', + 'Larry', + 'Holly', + 'Jennifer', + 'Liz', + 'Pete', + 'Steve', + 'Vince', + 'Zeke' + ]; + + List<_Product> getProducts(int count) { + final List<_Product> productData = <_Product>[]; + for (int i = 0; i < count; i++) { + productData.add( + _Product( + i + 1000, + productId[i], + product[i], + random.nextInt(20), + 70.0 + random.nextInt(100), + cities[i < cities.length ? i : random.nextInt(cities.length - 1)], + orderDate[random.nextInt(orderDate.length - 1)], + names[i]), + ); } + return productData; } } diff --git a/lib/samples/datagrid/columns/datagrid_stacked_header.dart b/lib/samples/datagrid/columns/datagrid_stacked_header.dart index c419ce4a..779f5c74 100644 --- a/lib/samples/datagrid/columns/datagrid_stacked_header.dart +++ b/lib/samples/datagrid/columns/datagrid_stacked_header.dart @@ -4,6 +4,7 @@ import 'dart:math'; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// DataGrid import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -14,21 +15,314 @@ import 'package:syncfusion_flutter_core/theme.dart'; /// Local import import '../../../model/sample_view.dart'; +/// Renders stacked header data grid class StackedHeaderDataGrid extends SampleView { - StackedHeaderDataGrid({Key key}) : super(key: key); + /// Creates stacked header data grid + StackedHeaderDataGrid({Key? key}) : super(key: key); @override _StackedHeaderDataGridState createState() => _StackedHeaderDataGridState(); } -List _productData; - class _StackedHeaderDataGridState extends SampleViewState { - final _StackedHeaderDataGridSource _stackedHeaderDataGridSource = + /// DataGridSource required for SfDataGrid to obtain the row data. + final _StackedHeaderDataGridSource stackedHeaderDataGridSource = _StackedHeaderDataGridSource(); - final Random _random = Random(); - final List _product = [ + late bool isWebOrDesktop; + + List _getColumns() { + List columns; + columns = [ + GridTextColumn( + columnName: 'customerName', + width: isWebOrDesktop ? 180 : 140, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Customer Name', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'city', + width: isWebOrDesktop ? 140 : 100, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'orderId', + width: isWebOrDesktop ? 140 : 90, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'orderDate', + width: isWebOrDesktop ? 140 : 110, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Order Date', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'product', + width: isWebOrDesktop ? 160 : 100, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Product', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'productId', + width: isWebOrDesktop ? 150 : 100, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Product ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'quantity', + width: isWebOrDesktop ? 150 : 90, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Quantity', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'unitPrice', + width: isWebOrDesktop ? 140 : 100, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + color: _getHeaderCellBackgroundColor(), + child: Text( + 'Unit Price', + overflow: TextOverflow.ellipsis, + ), + )), + ]; + return columns; + } + + Color _getHeaderCellBackgroundColor() { + return model.themeData.brightness == Brightness.light + ? const Color(0xFFF1F1F1) + : const Color(0xFF3A3A3A); + } + + Widget _getWidgetForStackedHeaderCell(String title) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + color: _getHeaderCellBackgroundColor(), + alignment: Alignment.centerLeft, + child: Text(title)); + } + + List _getStackedHeaderRows() { + List _stackedHeaderRows; + _stackedHeaderRows = [ + StackedHeaderRow(cells: [ + StackedHeaderCell(columnNames: [ + 'customerName', + 'city', + ], child: _getWidgetForStackedHeaderCell('Customer Details')), + StackedHeaderCell(columnNames: [ + 'orderId', + 'orderDate', + ], child: _getWidgetForStackedHeaderCell('Order Details')), + StackedHeaderCell( + columnNames: ['product', 'productId', 'quantity', 'unitPrice'], + child: _getWidgetForStackedHeaderCell('Product Details')) + ]) + ]; + return _stackedHeaderRows; + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + + @override + Widget build(BuildContext context) { + return SfDataGridTheme( + data: SfDataGridThemeData( + brightness: model.themeData.brightness, + headerHoverColor: Colors.transparent, + ), + child: SfDataGrid( + gridLinesVisibility: GridLinesVisibility.both, + headerGridLinesVisibility: GridLinesVisibility.both, + source: stackedHeaderDataGridSource, + columns: _getColumns(), + stackedHeaderRows: _getStackedHeaderRows(), + )); + } +} + +class _Product { + _Product( + this.orderId, + this.productId, + this.product, + this.quantity, + this.unitPrice, + this.city, + this.customerId, + this.orderDate, + this.customerName); + final int orderId; + final int productId; + final String product; + final int quantity; + final double unitPrice; + final String city; + final int customerId; + final DateTime orderDate; + final String customerName; +} + +class _StackedHeaderDataGridSource extends DataGridSource { + _StackedHeaderDataGridSource() { + products = getProducts(30); + buildDataGridRow(); + } + + final Random random = Random(); + + List<_Product> products = []; + + List dataGridRows = []; + + // Building the DataGridRows + + void buildDataGridRow() { + dataGridRows = products.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell( + columnName: 'customerName', value: dataGridRow.customerName), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'orderId', value: dataGridRow.orderId), + DataGridCell(columnName: 'orderDate', value: dataGridRow.orderDate), + DataGridCell(columnName: 'product', value: dataGridRow.product), + DataGridCell(columnName: 'productId', value: dataGridRow.productId), + DataGridCell(columnName: 'quantity', value: dataGridRow.quantity), + DataGridCell(columnName: 'unitPrice', value: dataGridRow.unitPrice), + ]); + }).toList(growable: false); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + DateFormat('MM/dd/yyyy').format(row.getCells()[3].value).toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[6].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[7].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } + + // Products data set collections + + final List product = [ 'Lax', 'Chocolate', 'Syrup', @@ -60,7 +354,7 @@ class _StackedHeaderDataGridState extends SampleViewState { 'Gum', ]; - final List _cities = [ + final List cities = [ 'Bruxelles', 'Rosario', 'Recife', @@ -71,7 +365,7 @@ class _StackedHeaderDataGridState extends SampleViewState { 'Resende', ]; - final List _productId = [ + final List productId = [ 3524, 2523, 1345, @@ -103,7 +397,7 @@ class _StackedHeaderDataGridState extends SampleViewState { 4932, ]; - final List _orderDate = [ + final List orderDate = [ DateTime.now(), DateTime(2002, 8, 27), DateTime(2015, 7, 4), @@ -119,7 +413,7 @@ class _StackedHeaderDataGridState extends SampleViewState { DateTime(2013, 10, 22), ]; - List _names = [ + List names = [ 'Kyle', 'Gina', 'Irene', @@ -147,190 +441,25 @@ class _StackedHeaderDataGridState extends SampleViewState { 'Zeke' ]; - List _generateProductData(int count) { - final List productData = []; + List<_Product> getProducts(int count) { + final List<_Product> productData = <_Product>[]; for (int i = 0; i < count; i++) { productData.add( - Product( + _Product( i + 1000, - _productId[i < _productId.length + productId[i < productId.length ? i - : _random.nextInt(_productId.length - 1)], - _product[ - i < _product.length ? i : _random.nextInt(_product.length - 1)], - _random.nextInt(count), - 70.0 + _random.nextInt(100), - _cities[ - i < _cities.length ? i : _random.nextInt(_cities.length - 1)], - 1700 + _random.nextInt(100), - _orderDate[_random.nextInt(_orderDate.length - 1)], - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)]), + : random.nextInt(productId.length - 1)], + product[ + i < product.length ? i : random.nextInt(product.length - 1)], + random.nextInt(count), + 70.0 + random.nextInt(100), + cities[i < cities.length ? i : random.nextInt(cities.length - 1)], + 1700 + random.nextInt(100), + orderDate[random.nextInt(orderDate.length - 1)], + names[i < names.length ? i : random.nextInt(names.length - 1)]), ); } - return productData; } - - List _getColumns() { - List columns; - columns = [ - GridTextColumn( - mappingName: 'customerName', - width: model.isWeb ? 180 : 140, - headerText: 'Customer Name'), - GridTextColumn( - mappingName: 'city', - width: model.isWeb ? 140 : 100, - headerText: 'City'), - GridNumericColumn( - mappingName: 'orderId', - width: model.isWeb ? 140 : 90, - headerText: 'Order ID'), - GridDateTimeColumn( - mappingName: 'orderDate', - width: model.isWeb ? 140 : 110, - dateFormat: DateFormat('MM/dd/yyyy'), - headerText: 'Order Date'), - GridTextColumn( - mappingName: 'product', - width: model.isWeb ? 160 : 100, - headerText: 'Product'), - GridNumericColumn( - mappingName: 'productId', - width: model.isWeb ? 150 : 100, - headerText: 'Product ID'), - GridNumericColumn( - mappingName: 'quantity', - width: model.isWeb ? 150 : 90, - headerText: 'Quantity'), - GridNumericColumn( - mappingName: 'unitPrice', - width: model.isWeb ? 140 : 100, - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Unit Price'), - ]; - return columns; - } - - Color _getHeaderCellBackgroundColor() { - return model.themeData.brightness == Brightness.light - ? const Color(0xFFF1F1F1) - : const Color(0xFF3A3A3A); - } - - Widget _getWidgetForStackedHeaderCell(String title) { - return Container( - padding: EdgeInsets.all(16.0), - color: _getHeaderCellBackgroundColor(), - alignment: Alignment.centerLeft, - child: Text(title)); - } - - List _getStackedHeaderRows() { - List _stackedHeaderRows; - _stackedHeaderRows = [ - StackedHeaderRow(cells: [ - StackedHeaderCell(columnNames: [ - 'customerName', - 'city', - ], child: _getWidgetForStackedHeaderCell('Customer Details')), - StackedHeaderCell(columnNames: [ - 'orderId', - 'orderDate', - ], child: _getWidgetForStackedHeaderCell('Order Details')), - StackedHeaderCell( - columnNames: ['product', 'productId', 'quantity', 'unitPrice'], - child: _getWidgetForStackedHeaderCell('Product Details')) - ]) - ]; - return _stackedHeaderRows; - } - - @override - void initState() { - super.initState(); - _productData = _generateProductData(30); - } - - @override - Widget build(BuildContext context) { - return SfDataGridTheme( - data: SfDataGridThemeData( - brightness: model.themeData.brightness, - headerStyle: DataGridHeaderCellStyle( - hoverColor: Colors.transparent, - hoverTextStyle: - SfTheme.of(context).dataGridThemeData.headerStyle.textStyle, - backgroundColor: _getHeaderCellBackgroundColor())), - child: SfDataGrid( - gridLinesVisibility: GridLinesVisibility.both, - headerGridLinesVisibility: GridLinesVisibility.both, - source: _stackedHeaderDataGridSource, - columns: _getColumns(), - stackedHeaderRows: _getStackedHeaderRows(), - )); - } -} - -class Product { - Product( - this.orderId, - this.productId, - this.product, - this.quantity, - this.unitPrice, - this.city, - this.customerId, - this.orderDate, - this.customerName); - final int orderId; - final int productId; - final String product; - final int quantity; - final double unitPrice; - final String city; - final int customerId; - final DateTime orderDate; - final String customerName; -} - -class _StackedHeaderDataGridSource extends DataGridSource { - _StackedHeaderDataGridSource(); - @override - List get dataSource => _productData; - @override - Object getValue(Product product, String columnName) { - switch (columnName) { - case 'orderId': - return product.orderId; - break; - case 'product': - return product.product; - break; - case 'productId': - return product.productId; - break; - case 'unitPrice': - return product.unitPrice; - break; - case 'quantity': - return product.quantity; - break; - case 'city': - return product.city; - break; - case 'customerId': - return product.customerId; - break; - case 'orderDate': - return product.orderDate; - break; - case 'customerName': - return product.customerName; - break; - default: - return 'empty'; - break; - } - } } diff --git a/lib/samples/datagrid/data_source/datagrid_json_data_source.dart b/lib/samples/datagrid/data_source/datagrid_json_data_source.dart index 0aa4564b..7d37228d 100644 --- a/lib/samples/datagrid/data_source/datagrid_json_data_source.dart +++ b/lib/samples/datagrid/data_source/datagrid_json_data_source.dart @@ -1,91 +1,135 @@ +import 'dart:convert'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_examples/model/sample_view.dart'; import 'package:flutter/services.dart' show rootBundle; +import 'package:flutter_examples/model/sample_view.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; -import 'dart:convert'; - -List _productList = []; /// Renders column type data grid class JsonDataSourceDataGrid extends SampleView { /// Creates column type data grid - const JsonDataSourceDataGrid({Key key}) : super(key: key); + const JsonDataSourceDataGrid({Key? key}) : super(key: key); @override _JsonDataSourceDataGridState createState() => _JsonDataSourceDataGridState(); } class _JsonDataSourceDataGridState extends SampleViewState { - _JsonDataSourceDataGridState(); + /// DataGridSource Required for SfDataGrid to obtain the row data. + final _JsonDataGridSource jsonDataGridSource = _JsonDataGridSource(); - Widget sampleWidget() => const JsonDataSourceDataGrid(); + late bool isWebOrDesktop; - final _JsonDataGridSource _jsonDataGridSource = _JsonDataGridSource(); + Widget sampleWidget() => const JsonDataSourceDataGrid(); List getColumns() { List columns; columns = ([ GridTextColumn( - mappingName: 'id', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 135 : 90, - headerText: 'ID'), + columnName: 'id', + width: isWebOrDesktop ? 135 : 90, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'ID', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'contactName', - softWrap: true, - columnWidthMode: - model.isWeb ? ColumnWidthMode.auto : ColumnWidthMode.header, - overflow: TextOverflow.clip, - headerText: 'Contact Name'), + columnName: 'contactName', + width: 150, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Contact Name', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'companyName', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 165 : 140, - headerText: 'Company'), + columnName: 'companyName', + width: isWebOrDesktop ? 165 : 140, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Company', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'city', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 150 : 120, - headerText: 'City'), + columnName: 'city', + width: isWebOrDesktop ? 150 : 120, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'country', - softWrap: true, - overflow: TextOverflow.clip, - width: model.isWeb ? 150 : 120, - headerText: 'Country'), + columnName: 'country', + width: isWebOrDesktop ? 150 : 120, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Country', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'designation', - softWrap: true, - overflow: TextOverflow.clip, - columnWidthMode: ColumnWidthMode.auto, - headerText: 'Job Title'), + columnName: 'designation', + width: 170, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Job Title', + overflow: TextOverflow.clip, + softWrap: true, + ), + ), + ), GridTextColumn( - mappingName: 'postalCode', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Postal Code'), + columnName: 'postalCode', + width: 110, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text('Postal Code'), + ), + ), GridTextColumn( - mappingName: 'phoneNumber', - columnWidthMode: ColumnWidthMode.auto, - headerText: 'Phone Number') + columnName: 'phoneNumber', + width: 150, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text('Phone Number'), + ), + ) ]); return columns; } - generateProductList() async { - String responseBody = - await rootBundle.loadString("assets/product_data.json"); - var list = json.decode(responseBody).cast>(); - _productList = list.map((json) => Product.fromJson(json)).toList(); - } - @override void initState() { super.initState(); - generateProductList(); + isWebOrDesktop = (model.isWeb || model.isDesktop); } @override @@ -95,28 +139,39 @@ class _JsonDataSourceDataGridState extends SampleViewState { future: Future.delayed( Duration(milliseconds: 500), () => 'Loaded'), builder: (BuildContext context, AsyncSnapshot snapshot) { - return !_productList.isEmpty - ? SfDataGrid( - source: _jsonDataGridSource, columns: getColumns()) - : Center( + return jsonDataGridSource.products.isEmpty + ? Center( child: CircularProgressIndicator( strokeWidth: 3, ), - ); + ) + : SfDataGrid( + source: jsonDataGridSource, columns: getColumns()); })); } } -class Product { - Product( - {this.id, - this.contactName, - this.companyName, - this.city, - this.country, - this.designation, - this.postalCode, - this.phoneNumber}); +class _Product { + factory _Product.fromJson(Map json) { + return _Product( + id: json['id'], + contactName: json['contactName'], + companyName: json['companyName'], + city: json['city'], + country: json['country'], + designation: json['designation'], + postalCode: json['postalCode'], + phoneNumber: json['phoneNumber']); + } + _Product( + {required this.id, + required this.contactName, + required this.companyName, + required this.city, + required this.country, + required this.designation, + required this.postalCode, + required this.phoneNumber}); final String id; final String contactName; final String companyName; @@ -125,54 +180,76 @@ class Product { final String designation; final String postalCode; final String phoneNumber; +} - factory Product.fromJson(Map json) { - return Product( - id: json['id'] as String, - contactName: json['contactName'] as String, - companyName: json['companyName'] as String, - city: json['city'] as String, - country: json['country'] as String, - designation: json['designation'] as String, - postalCode: json['postalCode'] as String, - phoneNumber: json['phoneNumber'] as String); +class _JsonDataGridSource extends DataGridSource { + _JsonDataGridSource() { + populateData(); } -} -class _JsonDataGridSource extends DataGridSource { - _JsonDataGridSource(); + List dataGridRows = []; + + List<_Product> products = []; + + // Populate Data from the json file + + Future generateProductList() async { + final String responseBody = + await rootBundle.loadString('assets/product_data.json'); + final list = await json.decode(responseBody).cast>(); + products = + await list.map<_Product>((json) => _Product.fromJson(json)).toList(); + } + + Future populateData() async { + await generateProductList(); + buildDataGridRow(); + } + + // Building DataGridRows + + void buildDataGridRow() { + dataGridRows = products.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'contactName', value: dataGridRow.contactName), + DataGridCell( + columnName: 'companyName', value: dataGridRow.companyName), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'country', value: dataGridRow.country), + DataGridCell( + columnName: 'designation', value: dataGridRow.designation), + DataGridCell( + columnName: 'postalCode', value: dataGridRow.postalCode), + DataGridCell( + columnName: 'phoneNumber', value: dataGridRow.phoneNumber), + ]); + }).toList(growable: false); + } + + // Overrides + @override - List get dataSource => _productList; + List get rows => dataGridRows; + @override - Object getValue(Product _product, String columnName) { - switch (columnName) { - case 'id': - return _product.id; - break; - case 'companyName': - return _product.companyName; - break; - case 'contactName': - return _product.contactName; - break; - case 'city': - return _product.city; - break; - case 'country': - return _product.country; - break; - case 'designation': - return _product.designation; - break; - case 'postalCode': - return _product.postalCode; - break; - case 'phoneNumber': - return _product.phoneNumber; - break; - default: - return 'empty'; - break; - } + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + if (dataCell.columnName == 'phoneNumber') { + return Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text(dataCell.value.toString(), maxLines: 1)); + } else { + return Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text(dataCell.value.toString(), + maxLines: (dataCell.columnName == 'companyName') ? 1 : null), + ); + } + }).toList()); } } diff --git a/lib/samples/datagrid/data_source/datagrid_list_data_source.dart b/lib/samples/datagrid/data_source/datagrid_list_data_source.dart index 34548f34..bdfd2c27 100644 --- a/lib/samples/datagrid/data_source/datagrid_list_data_source.dart +++ b/lib/samples/datagrid/data_source/datagrid_list_data_source.dart @@ -1,138 +1,167 @@ +/// Dart import +import 'dart:math' as math; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_examples/model/sample_view.dart'; -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:intl/intl.dart'; - -/// Dart import -import 'dart:math' as math; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; /// Renders column type data grid class ListDataSourceDataGrid extends SampleView { /// Creates column type data grid - const ListDataSourceDataGrid({Key key}) : super(key: key); + const ListDataSourceDataGrid({Key? key}) : super(key: key); @override _ListDataSourceDataGridState createState() => _ListDataSourceDataGridState(); } -List _employeeData; - class _ListDataSourceDataGridState extends SampleViewState { - _ListDataSourceDataGridState(); - - Widget sampleWidget() => const ListDataSourceDataGrid(); - - final math.Random _random = math.Random(); - bool _isLandscapeInMobileView; - - final _ListDataGridSource _listDataGridSource = _ListDataGridSource(); - - final List _names = [ - 'Welli', - 'Blonp', - 'Folko', - 'Furip', - 'Folig', - 'Picco', - 'Frans', - 'Warth', - 'Linod', - 'Simop', - 'Merep', - 'Riscu', - 'Seves', - 'Vaffe', - 'Alfki', - ]; + /// DataGridSource required for SfDataGrid to obtain the row data. + late _ListDataGridSource listDataGridSource; - final List _citys = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', - ]; + /// Determine to decide whether the device in landscape or in portrait + bool isLandscapeInMobileView = false; - List generateList(int count) { - final List employeeData = []; - for (int i = 0; i < count; i++) { - employeeData.add(Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); - } + late bool isWebOrDesktop; - return employeeData; - } + Widget sampleWidget() => const ListDataSourceDataGrid(); List getColumns() { List columns; - columns = kIsWeb + columns = isWebOrDesktop ? ([ - GridNumericColumn( - mappingName: 'id', - headerText: 'Order ID', + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'id', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + columnName: 'customerId', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'name', + label: Container( padding: const EdgeInsets.all(8), - headerTextAlignment: Alignment.centerRight, - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.auto), - GridNumericColumn( - mappingName: 'customerId', - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.header, - headerText: 'Customer ID', - headerTextAlignment: Alignment.centerRight), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'name', - headerText: 'Name', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'freight', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight', - headerTextAlignment: Alignment.centerRight), + width: (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + columnName: 'freight', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'city', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'city', - headerTextAlignment: Alignment.centerLeft, - headerText: 'City', - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.auto), - GridNumericColumn( - mappingName: 'price', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Price') + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'price', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + ), + ) ]) : ([ - GridNumericColumn( - mappingName: 'id', - headerText: 'ID', + GridTextColumn( + columnName: 'id', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'customerId', + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + label: Container( padding: const EdgeInsets.all(8), - headerTextAlignment: Alignment.centerRight), - GridNumericColumn( - mappingName: 'customerId', - headerTextAlignment: Alignment.centerRight, - columnWidthMode: _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.header, - headerText: 'Customer ID'), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'name', - headerTextAlignment: Alignment.centerLeft, - headerText: 'Name'), + columnName: 'name', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridTextColumn( - mappingName: 'city', - headerText: 'City', - headerTextAlignment: Alignment.centerLeft, + columnName: 'city', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), columnWidthMode: ColumnWidthMode.lastColumnFill), ]); return columns; @@ -141,13 +170,14 @@ class _ListDataSourceDataGridState extends SampleViewState { @override void initState() { super.initState(); - _employeeData = generateList(100); + isWebOrDesktop = (model.isWeb || model.isDesktop); + listDataGridSource = _ListDataGridSource(isWebOrDesktop: isWebOrDesktop); } @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + isLandscapeInMobileView = !isWebOrDesktop && MediaQuery.of(context).orientation == Orientation.landscape; } @@ -156,13 +186,13 @@ class _ListDataSourceDataGridState extends SampleViewState { return Container( child: SfDataGrid( columnWidthMode: ColumnWidthMode.fill, - source: _listDataGridSource, + source: listDataGridSource, columns: getColumns())); } } -class Employee { - Employee( +class _Employee { + _Employee( this.id, this.customerId, this.name, this.freight, this.city, this.price); final int id; final int customerId; @@ -172,34 +202,173 @@ class Employee { final double price; } -class _ListDataGridSource extends DataGridSource { - _ListDataGridSource(); +class _ListDataGridSource extends DataGridSource { + _ListDataGridSource({required this.isWebOrDesktop}) { + employees = getEmployees(100); + buildDataGridRows(); + } + + final bool isWebOrDesktop; + final math.Random random = math.Random(); + List<_Employee> employees = []; + List dataGridRows = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = isWebOrDesktop + ? employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell( + columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell( + columnName: 'price', value: dataGridRow.price), + ]); + }).toList() + : employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'city', value: dataGridRow.city), + ]); + }).toList(); + } + + // Overrides + @override - List get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'name': - return _employee.name; - break; - case 'customerId': - return _employee.customerId; - break; - case 'freight': - return _employee.freight; - break; - case 'price': - return _employee.price; - break; - case 'city': - return _employee.city; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + if (isWebOrDesktop) { + return DataGridRowAdapter(cells: [ + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[2].value.toString(), + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text(NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString()), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text(NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[5].value) + .toString()), + ), + ]); + } else { + Widget buildWidget({ + AlignmentGeometry alignment = Alignment.centerLeft, + EdgeInsetsGeometry padding = const EdgeInsets.all(8.0), + TextOverflow textOverflow = TextOverflow.ellipsis, + required Object value, + }) { + return Container( + padding: padding, + alignment: alignment, + child: Text( + value.toString(), + overflow: textOverflow, + ), + ); + } + + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + if (dataCell.columnName == 'id' || + dataCell.columnName == 'customerId') { + return buildWidget( + alignment: Alignment.centerRight, value: dataCell.value); + } else { + return buildWidget(value: dataCell.value); + } + }).toList(growable: false)); + } + } + + // Employee Data's + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(int count) { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < count; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); } + return employeeData; } } diff --git a/lib/samples/datagrid/freeze_panes/datagrid_freeze_panes.dart b/lib/samples/datagrid/freeze_panes/datagrid_freeze_panes.dart index e89a560a..268bd53e 100644 --- a/lib/samples/datagrid/freeze_panes/datagrid_freeze_panes.dart +++ b/lib/samples/datagrid/freeze_panes/datagrid_freeze_panes.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -14,24 +15,260 @@ import '../../../model/sample_view.dart'; /// Renders datagrid with selection option(single/multiple and select/unselect) class FreezePanesDataGrid extends SampleView { /// Creates datagrid with selection option(single/multiple and select/unselect) - const FreezePanesDataGrid({Key key}) : super(key: key); + const FreezePanesDataGrid({Key? key}) : super(key: key); @override _FreezePanesDataGridPageState createState() => _FreezePanesDataGridPageState(); } -List _productData; - class _FreezePanesDataGridPageState extends SampleViewState { - _FreezePanesDataGridPageState(); + /// DataGridSource required for SfDataGrid to obtain the row data. + _FreezePanesDataGridSource freezePanesDataGridSource = + _FreezePanesDataGridSource(); - final math.Random _random = math.Random(); + late bool isWebOrDesktop; - final _FreezePanesDataGridSource _freezePanesDataGridSource = - _FreezePanesDataGridSource(); + List getColumns() { + List columns; + columns = [ + GridTextColumn( + columnName: 'id', + width: isWebOrDesktop ? 140 : 90, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'productId', + width: isWebOrDesktop ? 150 : 100, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Product ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'name', + width: isWebOrDesktop ? 180 : 140, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Customer Name', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'product', + width: isWebOrDesktop ? 160 : 100, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Product', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'orderDate', + width: isWebOrDesktop ? 140 : 110, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Order Date', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'quantity', + width: isWebOrDesktop ? 150 : 90, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Quantity', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'city', + width: isWebOrDesktop ? 140 : 100, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'unitPrice', + width: isWebOrDesktop ? 140 : 100, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Unit Price', + overflow: TextOverflow.ellipsis, + ), + )), + ]; + return columns; + } + + SfDataGrid _buildDataGrid() { + return SfDataGrid( + source: freezePanesDataGridSource, + frozenRowsCount: 1, + frozenColumnsCount: 1, + columns: getColumns(), + ); + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _buildDataGrid(), + ); + } +} + +class _Product { + _Product(this.id, this.productId, this.product, this.quantity, this.unitPrice, + this.city, this.orderDate, this.name); + final int id; + final int productId; + final String product; + final int quantity; + final double unitPrice; + final String city; + final DateTime orderDate; + final String name; +} + +class _FreezePanesDataGridSource extends DataGridSource { + _FreezePanesDataGridSource() { + products = getProducts(20); + buildDataGridRows(); + } + + final math.Random random = math.Random(); + + List dataGridRows = []; + + List<_Product> products = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = products.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'productId', value: dataGridRow.productId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'product', value: dataGridRow.product), + DataGridCell(columnName: 'orderDate', value: dataGridRow.orderDate), + DataGridCell(columnName: 'quantity', value: dataGridRow.quantity), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'unitPrice', value: dataGridRow.unitPrice), + ]); + }).toList(growable: false); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[3].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + DateFormat('MM/dd/yyyy').format(row.getCells()[4].value).toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[6].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[7].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } - final List _product = [ + // Products data's + + final List _products = [ 'Lax', 'Chocolate', 'Syrup', @@ -63,7 +300,7 @@ class _FreezePanesDataGridPageState extends SampleViewState { 'Gum', ]; - final List _cities = [ + final List cities = [ 'Bruxelles', 'Rosario', 'Recife', @@ -74,7 +311,7 @@ class _FreezePanesDataGridPageState extends SampleViewState { 'Resende', ]; - final List _productId = [ + final List productIds = [ 3524, 2523, 1345, @@ -106,7 +343,7 @@ class _FreezePanesDataGridPageState extends SampleViewState { 4932, ]; - final List _orderDate = [ + final List orderDates = [ DateTime.now(), DateTime(2002, 8, 27), DateTime(2015, 7, 4), @@ -122,7 +359,7 @@ class _FreezePanesDataGridPageState extends SampleViewState { DateTime(2013, 10, 22), ]; - List _names = [ + List names = [ 'Kyle', 'Gina', 'Irene', @@ -150,135 +387,21 @@ class _FreezePanesDataGridPageState extends SampleViewState { 'Zeke' ]; - List generateList(int count) { - final List productData = []; + List<_Product> getProducts(int count) { + final List<_Product> productData = <_Product>[]; for (int i = 0; i < count; i++) { productData.add( - Product( + _Product( i + 1000, - _productId[i], - _product[i], - _random.nextInt(20), - 70.0 + _random.nextInt(100), - _cities[ - i < _cities.length ? i : _random.nextInt(_cities.length - 1)], - _orderDate[_random.nextInt(_orderDate.length - 1)], - _names[i]), + productIds[i], + _products[i], + random.nextInt(20), + 70.0 + random.nextInt(100), + cities[i < cities.length ? i : random.nextInt(cities.length - 1)], + orderDates[random.nextInt(orderDates.length - 1)], + names[i]), ); } - return productData; } - - List getColumns() { - List columns; - columns = [ - GridNumericColumn( - mappingName: 'id', width: model.isWeb ? 140 : 90, headerText: 'ID'), - GridNumericColumn( - mappingName: 'productId', - width: model.isWeb ? 150 : 100, - headerText: 'Product ID'), - GridTextColumn( - mappingName: 'name', - width: model.isWeb ? 180 : 140, - headerText: 'Customer Name'), - GridTextColumn( - mappingName: 'product', - width: model.isWeb ? 160 : 100, - headerText: 'Product'), - GridDateTimeColumn( - mappingName: 'orderDate', - width: model.isWeb ? 140 : 110, - dateFormat: DateFormat('MM/dd/yyyy'), - headerText: 'Order Date'), - GridNumericColumn( - mappingName: 'quantity', - width: model.isWeb ? 150 : 90, - headerText: 'Quantity'), - GridTextColumn( - mappingName: 'city', - width: model.isWeb ? 140 : 100, - headerText: 'City'), - GridNumericColumn( - mappingName: 'unitPrice', - width: model.isWeb ? 140 : 100, - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Unit Price'), - ]; - return columns; - } - - SfDataGrid _dataGridSample() { - return SfDataGrid( - source: _freezePanesDataGridSource, - frozenRowsCount: 1, - frozenColumnsCount: 1, - columns: getColumns(), - ); - } - - @override - void initState() { - super.initState(); - _productData = generateList(20); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: _dataGridSample(), - ); - } -} - -class Product { - Product(this.id, this.productId, this.product, this.quantity, this.unitPrice, - this.city, this.orderDate, this.name); - final int id; - final int productId; - final String product; - final int quantity; - final double unitPrice; - final String city; - final DateTime orderDate; - final String name; -} - -class _FreezePanesDataGridSource extends DataGridSource { - _FreezePanesDataGridSource(); - @override - List get dataSource => _productData; - @override - Object getValue(Product _product, String columnName) { - switch (columnName) { - case 'id': - return _product.id; - break; - case 'product': - return _product.product; - break; - case 'productId': - return _product.productId; - break; - case 'unitPrice': - return _product.unitPrice; - break; - case 'quantity': - return _product.quantity; - break; - case 'city': - return _product.city; - break; - case 'orderDate': - return _product.orderDate; - break; - case 'name': - return _product.name; - break; - default: - return 'empty'; - break; - } - } } diff --git a/lib/samples/datagrid/getting_started/datagrid_getting_started.dart b/lib/samples/datagrid/getting_started/datagrid_getting_started.dart index c1eb3a0b..18687ce9 100644 --- a/lib/samples/datagrid/getting_started/datagrid_getting_started.dart +++ b/lib/samples/datagrid/getting_started/datagrid_getting_started.dart @@ -4,36 +4,647 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; -///Core theme import -import 'package:syncfusion_flutter_core/theme.dart'; - /// Local import import '../../../model/sample_view.dart'; /// Render getting started data grid class GettingStartedDataGrid extends SampleView { /// Creates getting started data grid - const GettingStartedDataGrid({Key key}) : super(key: key); + const GettingStartedDataGrid({Key? key}) : super(key: key); @override _GettingStartedDataGridState createState() => _GettingStartedDataGridState(); } -List<_Team> _teamData; -List<_Employee> _employeeCollection; - class _GettingStartedDataGridState extends SampleViewState { - _GettingStartedDataGridState(); + /// DataGridSource required for SfDataGrid to obtain the row data. + _TeamDataGridSource teamDataGridSource = _TeamDataGridSource(); + + /// DataGridSource required for SfDataGrid to obtain the row data. + late _EmployeeDataGridSource employeeDataGridSource; + + late bool isWebOrDesktop; + + SfDataGrid _buildDataGridForMobile() { + return SfDataGrid( + source: teamDataGridSource, + columnWidthMode: ColumnWidthMode.fill, + rowHeight: 50, + columns: [ + GridTextColumn( + columnName: 'image', + width: 51, + label: SizedBox.shrink(), + ), + GridTextColumn( + columnName: 'team', + width: !isWebOrDesktop ? 90 : double.nan, + label: Container( + alignment: Alignment.centerLeft, + child: Text('Team'), + ), + ), + GridTextColumn( + columnName: 'wins', + label: Center( + child: Text('W'), + ), + ), + GridTextColumn( + columnName: 'losses', + label: Center( + child: Text('L'), + )), + GridTextColumn(columnName: 'pct', label: Center(child: Text('WPCT'))), + GridTextColumn( + columnName: 'gb', + label: Center(child: Text('GB')), + ), + ], + ); + } + + Widget getLocationWidget(String location) { + return Container( + child: Row( + children: [ + Container( + child: Image.asset('images/location.png'), + ), + Text( + ' ' + location, + ) + ], + ), + ); + } + + Widget getTrustWidget(String trust) { + return Container( + child: Row(children: [ + Container( + child: Row( + children: [ + Container( + child: Image.asset('images/Perfect.png'), + ), + Text(trust) + ], + )) + ])); + } + + SfDataGrid _buildDataGridForWeb() { + return SfDataGrid( + source: employeeDataGridSource, + columns: [ + GridTextColumn( + width: 130, + columnName: 'employeeName', + label: Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8.0), + child: Text( + 'Employee Name', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'designation', + width: (model.isWeb || model.isMacOS || model.isLinux) ? 150 : 130, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Designation', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'mail', + width: 180.0, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + 'Mail', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'location', + width: model.isLinux ? 120.0 : 105.0, + label: Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8.0), + child: Text( + 'Location', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'status', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + 'Status', + overflow: TextOverflow.ellipsis, + )), + ), + GridTextColumn( + columnName: 'trustworthiness', + width: 130, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Trustworthiness', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'softwareProficiency', + width: 165, + label: Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8.0), + child: Text( + 'Software Proficiency', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + 'Salary', + overflow: TextOverflow.ellipsis, + )), + ), + GridTextColumn( + columnName: 'address', + width: 200, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Address', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ); + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + employeeDataGridSource = + _EmployeeDataGridSource(brightness: model.themeData.brightness); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: isWebOrDesktop ? _buildDataGridForWeb() : _buildDataGridForMobile(), + ); + } +} + +class _Team { + _Team( + this.team, + this.winPercentage, + this.gamesBehind, + this.wins, + this.losses, + this.image, + ); + final String team; + final double winPercentage; + final double gamesBehind; + final int wins; + final int losses; + final Image image; +} + +class _TeamDataGridSource extends DataGridSource { + _TeamDataGridSource() { + teams = getTeams(teamNames.length); + buildDataGridRows(); + } + + List<_Team> teams = []; + + List dataGridRows = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = teams.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'image', value: dataGridRow.image), + DataGridCell(columnName: 'team', value: dataGridRow.team), + DataGridCell(columnName: 'wins', value: dataGridRow.wins), + DataGridCell(columnName: 'losses', value: dataGridRow.losses), + DataGridCell( + columnName: 'pct', value: dataGridRow.winPercentage), + DataGridCell(columnName: 'gb', value: dataGridRow.gamesBehind), + ]); + }).toList(); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + padding: EdgeInsets.all(8.0), + child: row.getCells()[0].value, + ), + Container( + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[1].value.toString(), + softWrap: true, + ), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + row.getCells()[3].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } + + // Team data's + + final List teamNames = [ + 'Denver', + 'Charllote', + 'Memphis', + 'New York', + 'Detroit', + 'L.A Lakers', + 'Miami', + 'Orlando', + 'L.A Clippers', + 'San Francisco', + 'Dallas', + 'Milwaukke', + 'Oklahoma', + 'Cleveland', + ]; + + final List _teamLogos = [ + Image.asset('images/DenverNuggets.png'), + Image.asset('images/Hornets.png'), + Image.asset('images/Memphis.png'), + Image.asset('images/NewYork.png'), + Image.asset('images/DetroitPistons.png'), + Image.asset('images/LosAngeles.png'), + Image.asset('images/Miami.png'), + Image.asset('images/Orlando.png'), + Image.asset('images/Clippers.png'), + Image.asset('images/GoldenState.png'), + Image.asset('images/Mavericks.png'), + Image.asset('images/Milwakke.png'), + Image.asset('images/Thunder_Logo.png'), + Image.asset('images/Cavaliers.png'), + ]; + + final List gb = [ + 0, + 10, + 15.5, + 15.5, + 40.5, + 0, + 2, + 3, + 14.5, + 19, + 0, + 20, + 24.5, + 28.5, + 31, + 16.6, + 10.3 + ]; + final List wins = [ + 93, + 82, + 76, + 77, + 52, + 84, + 82, + 81, + 70, + 65, + 97, + 77, + 72, + 68, + 66, + 23, + 45 + ]; + final List pct = [ + .616, + .550, + .514, + .513, + .347, + .560, + .547, + .540, + .464, + .433, + .642, + .510, + .480, + .453, + .437, + .567, + .345 + ]; + final List losses = [ + 58, + 67, + 72, + 73, + 98, + 66, + 68, + 69, + 81, + 85, + 54, + 74, + 78, + 82, + 85, + 68, + 78 + ]; + + List<_Team> getTeams(int count) { + final List<_Team> teamData = <_Team>[]; + for (int i = 0; i < count; i++) { + teamData.add(_Team( + teamNames[i], + pct[i], + gb[i], + wins[i], + losses[i], + _teamLogos[i], + )); + } + return teamData; + } +} + +class _Employee { + _Employee( + this.employeeName, + this.designation, + this.mail, + this.location, + this.status, + this.trustworthiness, + this.softwareProficiency, + this.salary, + this.address, + ); + final String location; + final String employeeName; + final String designation; + final String mail; + final String trustworthiness; + final String status; + final int softwareProficiency; + final int salary; + final String address; +} + +class _EmployeeDataGridSource extends DataGridSource { + _EmployeeDataGridSource({required this.brightness}) { + employees = getEmployees(20); + buildDataGridRows(); + } + + final Brightness brightness; final math.Random random = math.Random(); + List dataGridRows = []; + List<_Employee> employees = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell( + columnName: 'employeeName', value: dataGridRow.employeeName), + DataGridCell( + columnName: 'designation', value: dataGridRow.designation), + DataGridCell(columnName: 'mail', value: dataGridRow.mail), + DataGridCell( + columnName: 'location', value: dataGridRow.location), + DataGridCell(columnName: 'status', value: dataGridRow.status), + DataGridCell( + columnName: 'trustworthiness', value: dataGridRow.trustworthiness), + DataGridCell( + columnName: 'softwareProficiency', + value: dataGridRow.softwareProficiency), + DataGridCell(columnName: 'salary', value: dataGridRow.salary), + DataGridCell(columnName: 'address', value: dataGridRow.address), + ]); + }).toList(); + } + + // Overrides + @override + List get rows => dataGridRows; + + Widget buildEmployeeName(dynamic value) { + return Padding( + padding: const EdgeInsets.only(left: 16.0), + child: getWidget( + Icon(Icons.account_circle, size: 30, color: Colors.blue[300]), value), + ); + } + + Widget buildLocation(dynamic value) { + return Padding( + padding: const EdgeInsets.only(left: 16.0), + child: getWidget(const Icon(Icons.location_on, size: 20), value), + ); + } + + Widget buildTrustWorthiness(dynamic value) { + final String trust = value; + if (value == 'Perfect') { + return Padding( + padding: const EdgeInsets.only(left: 16.0), + child: getWidget(images[trust]!, trust), + ); + } else if (value == 'Insufficient') { + return Padding( + padding: const EdgeInsets.only(left: 16.0), + child: getWidget(images[trust]!, trust), + ); + } else { + return Padding( + padding: const EdgeInsets.only(left: 16.0), + child: getWidget(images[trust]!, trust), + ); + } + } + + Widget buildSoftwareProficiency(dynamic value) { + Widget getLinearProgressBar(int progressValue) { + return Container( + width: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 50, + child: LinearProgressIndicator( + value: progressValue / 100, + valueColor: AlwaysStoppedAnimation( + progressValue < 50 ? Colors.red : Colors.green), + backgroundColor: + progressValue < 50 ? Colors.red[100] : Colors.green[100], + )), + Text(' ' + (progressValue.toString() + '%')), + ], + ), + ); + } + + return getLinearProgressBar(value); + } + + Widget getWidget(Widget image, String text) { + return Container( + color: Colors.transparent, + child: Row( + children: [ + Container( + child: image, + ), + const SizedBox(width: 6), + Expanded( + child: Text( + text, + overflow: TextOverflow.ellipsis, + )) + ], + ), + ); + } + + TextStyle getStatusTextStyle(dynamic value) { + if (value == 'Active') { + return TextStyle(color: Colors.green); + } else { + return TextStyle(color: Colors.red[500]); + } + } + + final Map images = { + 'Perfect': Image.asset('images/Perfect.png'), + 'Insufficient': Image.asset('images/Insufficient.png'), + 'Sufficient': Image.asset('images/Sufficient.png'), + }; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + buildEmployeeName(row.getCells()[0].value), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text(row.getCells()[1].value.toString()), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text(row.getCells()[2].value.toString()), + ), + buildLocation(row.getCells()[3].value), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + row.getCells()[4].value.toString(), + style: getStatusTextStyle(row.getCells()[4].value), + )), + buildTrustWorthiness(row.getCells()[5].value), + buildSoftwareProficiency(row.getCells()[6].value), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text(NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[7].value) + .toString()), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text(row.getCells()[8].value.toString()), + ), + ]); + } - final _TeamDataGridSource _teamDataGridSource = _TeamDataGridSource(); - final _EmployeeDataGridSource _employeeDataGridSource = - _EmployeeDataGridSource(); - final List employees = [ + // Employee Data's + + final List employeeNames = [ 'Michael', 'Kathryn', 'Tamer', @@ -61,7 +672,7 @@ class _GettingStartedDataGridState extends SampleViewState { 'Jack', 'Rose' ]; - final List address = [ + final List addresses = [ '59 rue de lAbbaye', 'Luisenstr. 48', 'Rua do Paço 67', @@ -103,7 +714,7 @@ class _GettingStartedDataGridState extends SampleViewState { 'Taucherstraße 10', 'Taucherstraße 10', ]; - final List designation = [ + final List designations = [ 'Designer', 'Manager', 'Developer', @@ -112,45 +723,25 @@ class _GettingStartedDataGridState extends SampleViewState { 'System Analyst', 'CFO' ]; - final List mail = [ - 'arpy.com', - 'sample.com', - 'rpy.com', - 'jourrapide.com' - ]; - final List status = ['Inactive', 'Active']; - final List trusts = ['Sufficient', 'Perfect', 'Insufficient']; - final List locations = [ - 'UK', - 'USA', - 'Sweden', - 'France', - 'Canada', - 'Argentina', - 'Austria', - 'Germany', - 'Mexico' - ]; - final Map images = { - 'Perfect': Image.asset('images/Perfect.png'), - 'Insufficient': Image.asset('images/Insufficient.png'), - 'Sufficient': Image.asset('images/Sufficient.png'), - }; - final List _teamLogos = [ - Image.asset('images/DenverNuggets.png'), - Image.asset('images/Hornets.png'), - Image.asset('images/Memphis.png'), - Image.asset('images/NewYork.png'), - Image.asset('images/DetroitPistons.png'), - Image.asset('images/LosAngeles.png'), - Image.asset('images/Miami.png'), - Image.asset('images/Orlando.png'), - Image.asset('images/Clippers.png'), - Image.asset('images/GoldenState.png'), - Image.asset('images/Mavericks.png'), - Image.asset('images/Milwakke.png'), - Image.asset('images/Thunder_Logo.png'), - ]; + final List mails = [ + 'arpy.com', + 'sample.com', + 'rpy.com', + 'jourrapide.com' + ]; + final List status = ['Inactive', 'Active']; + final List trusts = ['Sufficient', 'Perfect', 'Insufficient']; + final List locations = [ + 'UK', + 'USA', + 'Sweden', + 'France', + 'Canada', + 'Argentina', + 'Austria', + 'Germany', + 'Mexico' + ]; final List genders = [ '1', @@ -180,454 +771,23 @@ class _GettingStartedDataGridState extends SampleViewState { '1', '2' ]; - final List teamName = [ - 'Denver', - 'Hornets', - 'Memphis', - 'New York', - 'Detroit', - 'Los Angeles', - 'Miami', - 'Orlando', - 'Clippers', - 'Golden State', - 'Mavericks', - 'Milwakke', - 'Thunder', - ]; - final List gb = [ - 0, - 10, - 15.5, - 15.5, - 40.5, - 0, - 2, - 3, - 14.5, - 19, - 0, - 20, - 24.5, - 28.5, - 31, - ]; - final List wins = [ - 93, - 82, - 76, - 77, - 52, - 84, - 82, - 81, - 70, - 65, - 97, - 77, - 72, - 68, - 66 - ]; - final List pct = [ - .616, - .550, - .514, - .513, - .347, - .560, - .547, - .540, - .464, - .433, - .642, - .510, - .480, - .453, - .437 - ]; - final List losses = [ - 58, - 67, - 72, - 73, - 98, - 66, - 68, - 69, - 81, - 85, - 54, - 74, - 78, - 82, - 85, - ]; - - List<_Team> generateTeam(int count) { - final List<_Team> teamData = <_Team>[]; - for (int i = 0; i < count - 1; i++) { - teamData.add(_Team( - teamName[i], - pct[i], - gb[i], - wins[i], - losses[i], - images[i], - )); - } - return teamData; - } - - List<_Employee> generateEmployeeData(int count) { - final List<_Employee> employee = <_Employee>[]; - for (int i = 0; i < employees.length - 1; i++) { - employee.add(_Employee( - employees[i], - designation[random.nextInt(designation.length - 1)], - employees[i].toLowerCase() + + List<_Employee> getEmployees(int count) { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < employeeNames.length - 1; i++) { + employeeData.add(_Employee( + employeeNames[i], + designations[random.nextInt(designations.length - 1)], + employeeNames[i].toLowerCase() + '@' + - mail[random.nextInt(mail.length - 1)], + mails[random.nextInt(mails.length - 1)], locations[random.nextInt(locations.length - 1)], status[random.nextInt(status.length)], trusts[random.nextInt(trusts.length - 1)], 20 + random.nextInt(80), 10000 + random.nextInt(70000), - address[random.nextInt(address.length - 1)])); - } - return employee; - } - - SfDataGrid _mobileSample() { - return SfDataGrid( - source: _teamDataGridSource, - columnWidthMode: ColumnWidthMode.fill, - cellBuilder: (BuildContext context, GridColumn column, int rowIndex) => - Container( - child: _teamLogos[rowIndex], - padding: const EdgeInsets.all(8), - ), - rowHeight: 50, - columns: [ - GridWidgetColumn( - mappingName: 'image', - width: 51, - headerText: '', - ), - GridTextColumn( - mappingName: 'team', - columnWidthMode: ColumnWidthMode.cells, - headerText: 'Team', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'wins', - headerText: 'W', - padding: const EdgeInsets.all(8), - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - GridNumericColumn( - mappingName: 'losses', - padding: const EdgeInsets.all(8), - textAlignment: Alignment.center, - headerTextAlignment: Alignment.center, - headerText: 'L'), - GridNumericColumn( - mappingName: 'pct', - headerText: 'WPCT', - padding: const EdgeInsets.all(8), - textAlignment: Alignment.center, - headerTextAlignment: Alignment.center, - columnWidthMode: ColumnWidthMode.auto), - GridNumericColumn( - mappingName: 'gb', - headerText: 'GB', - textAlignment: Alignment.center, - headerTextAlignment: Alignment.center, - padding: const EdgeInsets.all(8)), - ], - ); - } - - Widget getWidget(Widget image, String text) { - return Container( - color: Colors.transparent, - child: Row( - children: [ - Container( - child: image, - ), - const SizedBox(width: 6), - Expanded( - child: Text( - text, - overflow: TextOverflow.ellipsis, - )) - ], - ), - ); - } - - Widget getLocationWidget(String location) { - return Container( - child: Row( - children: [ - Container( - child: Image.asset('images/location.png'), - ), - Text( - ' ' + location, - ) - ], - ), - ); - } - - Widget getLinearProgressBar(int progressValue) { - return Container( - width: 100, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 50, - child: LinearProgressIndicator( - value: progressValue / 100, - valueColor: AlwaysStoppedAnimation( - progressValue < 50 ? Colors.red : Colors.green), - backgroundColor: - progressValue < 50 ? Colors.red[100] : Colors.green[100], - )), - Text(' ' + (progressValue.toString() + '%')), - ], - ), - ); - } - - Widget getTrustWidget(String trust) { - return Container( - child: Row(children: [ - Container( - child: Row( - children: [ - Container( - child: Image.asset('images/Perfect.png'), - ), - Text(trust) - ], - )) - ])); - } - - Widget getCellWidget(BuildContext context, GridColumn column, int rowIndex) { - if (column.mappingName == 'location') { - final String location = _employeeCollection[rowIndex].location; - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: getWidget(const Icon(Icons.location_on, size: 20), location), - ); - } else if (column.mappingName == 'employeeName') { - final String employeeName = _employeeCollection[rowIndex].employeeName; - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: getWidget( - Icon(Icons.account_circle, size: 30, color: Colors.blue[300]), - employeeName), - ); - } else if (column.mappingName == 'trustworthiness') { - final String trust = _employeeCollection[rowIndex].trustworthiness; - if (trust == 'Perfect') { - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: getWidget(images[trust], trust), - ); - } else if (trust == 'Insufficient') { - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: getWidget(images[trust], trust), - ); - } else { - return Padding( - padding: const EdgeInsets.only(left: 16.0), - child: getWidget(images[trust], trust), - ); - } - } else if (column.mappingName == 'softwareProficiency') { - return getLinearProgressBar( - _employeeCollection[rowIndex].softwareProficiency); - } else { - return null; - } - } - - SfDataGrid _webSample() { - return SfDataGrid( - source: _employeeDataGridSource, - columnWidthMode: ColumnWidthMode.auto, - cellBuilder: getCellWidget, - onQueryCellStyle: (QueryCellStyleArgs args) { - if (args.column.mappingName == 'status') { - if (args.cellValue == 'Active') { - return const DataGridCellStyle( - textStyle: TextStyle(color: Colors.green)); - } else { - return DataGridCellStyle( - textStyle: TextStyle(color: Colors.red[500])); - } - } else { - return null; - } - }, - columns: [ - GridWidgetColumn( - mappingName: 'employeeName', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Employee Name'), - GridTextColumn( - mappingName: 'designation', - headerText: 'Designation', - headerTextAlignment: Alignment.centerLeft), - GridTextColumn( - mappingName: 'mail', - headerText: 'Mail', - headerTextAlignment: Alignment.centerLeft), - GridWidgetColumn( - mappingName: 'location', - width: 105, - headerText: 'Location', - headerTextAlignment: Alignment.centerLeft), - GridTextColumn( - mappingName: 'status', - headerText: 'Status', - headerTextAlignment: Alignment.centerLeft), - GridWidgetColumn( - mappingName: 'trustworthiness', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Trustworthiness'), - GridWidgetColumn( - mappingName: 'softwareProficiency', - columnWidthMode: ColumnWidthMode.header, - headerText: 'Software Proficiency'), - GridNumericColumn( - mappingName: 'salary', - headerText: 'Salary', - headerTextAlignment: Alignment.centerRight, - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$')), - GridTextColumn( - mappingName: 'address', - headerText: 'Address', - headerTextAlignment: Alignment.centerLeft), - ], - ); - } - - @override - void initState() { - super.initState(); - _teamData = generateTeam(13); - _employeeCollection = generateEmployeeData(20); - } - - @override - Widget build(BuildContext context) { - return Scaffold(body: model.isWeb ? _webSample() : _mobileSample()); - } -} - -class _Team { - _Team( - this.team, - this.winPercentage, - this.gamesBehind, - this.wins, - this.losses, - this.image, - ); - final String team; - final double winPercentage; - final double gamesBehind; - final int wins; - final int losses; - final Image image; -} - -class _TeamDataGridSource extends DataGridSource<_Team> { - _TeamDataGridSource(); - @override - List<_Team> get dataSource => _teamData; - @override - Object getValue(_Team _team, String columnName) { - switch (columnName) { - case 'team': - return _team.team; - break; - case 'pct': - return _team.winPercentage; - break; - case 'gb': - return _team.gamesBehind; - break; - case 'wins': - return _team.wins; - break; - case 'losses': - return _team.losses; - break; - default: - return 'empty'; - break; - } - } -} - -class _Employee { - _Employee( - this.employeeName, - this.designation, - this.mail, - this.location, - this.status, - this.trustworthiness, - this.softwareProficiency, - this.salary, - this.address, - ); - final String location; - final String employeeName; - final String designation; - final String mail; - final String trustworthiness; - final String status; - final int softwareProficiency; - final int salary; - final String address; -} - -class _EmployeeDataGridSource extends DataGridSource<_Employee> { - _EmployeeDataGridSource(); - @override - List<_Employee> get dataSource => _employeeCollection; - @override - Object getValue(_Employee _employee, String columnName) { - switch (columnName) { - case 'mail': - return _employee.mail; - break; - case 'status': - return _employee.status; - break; - case 'designation': - return _employee.designation; - break; - case 'salary': - return _employee.salary; - break; - case 'address': - return _employee.address; - break; - default: - return 'empty'; - break; + addresses[random.nextInt(addresses.length - 1)])); } + return employeeData; } } diff --git a/lib/samples/datagrid/loadmore/datagrid_infinite_scrolling.dart b/lib/samples/datagrid/loadmore/datagrid_infinite_scrolling.dart index bf3a1b5f..b9e285c6 100644 --- a/lib/samples/datagrid/loadmore/datagrid_infinite_scrolling.dart +++ b/lib/samples/datagrid/loadmore/datagrid_infinite_scrolling.dart @@ -12,8 +12,10 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; /// Local import import '../../../model/sample_view.dart'; +/// Renders Load More Infinite Scrolling Data Grid class LoadMoreInfiniteScrollingDataGrid extends SampleView { - LoadMoreInfiniteScrollingDataGrid({Key key}) : super(key: key); + /// Creates Load More Infinite Scrolling Data Grid + LoadMoreInfiniteScrollingDataGrid({Key? key}) : super(key: key); @override _LoadMoreInfiniteScrollingDataGridState createState() => @@ -21,16 +23,12 @@ class LoadMoreInfiniteScrollingDataGrid extends SampleView { } class _LoadMoreInfiniteScrollingDataGridState extends SampleViewState { - List _employeeData = []; - EmployeeDataSource _employeeDataSource; + /// DataGridSource required for SfDataGrid to obtain the row data. + final _EmployeeDataSource employeeDataSource = _EmployeeDataSource(); - @override - void initState() { - _populateData(); - _employeeDataSource = EmployeeDataSource(employeeData: _employeeData); - super.initState(); - } + late bool isWebOrDesktop; + /// Building the progress indicator when DataGrid scroller reach the bottom Widget _buildProgressIndicator() { final isLight = model.themeData.brightness == Brightness.light; return Container( @@ -56,6 +54,7 @@ class _LoadMoreInfiniteScrollingDataGridState extends SampleViewState { )))); } + /// Callback method for load more builder Widget _buildLoadMoreView(BuildContext context, LoadMoreRows loadMoreRows) { Future loadRows() async { // Call the loadMoreRows function to call the @@ -79,95 +78,101 @@ class _LoadMoreInfiniteScrollingDataGridState extends SampleViewState { @override Widget build(BuildContext context) { return SfDataGrid( - source: _employeeDataSource, + source: employeeDataSource, loadMoreViewBuilder: _buildLoadMoreView, columns: _getColumns()); } - void _populateData() { - _employeeData.clear(); - _employeeData = _generateList(_employeeData, 25); + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); } -} - -List _getColumns() { - return [ - GridNumericColumn( - mappingName: 'id', - columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Order ID'), - GridNumericColumn( - mappingName: 'customerId', - columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Customer ID'), - GridTextColumn(mappingName: 'name', headerText: 'Name'), - GridNumericColumn( - mappingName: 'freight', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight'), - GridTextColumn( - mappingName: 'city', - columnWidthMode: !kIsWeb ? ColumnWidthMode.auto : ColumnWidthMode.fill, - headerText: 'City'), - GridNumericColumn( - mappingName: 'price', - numberFormat: NumberFormat.currency( - locale: 'en_US', symbol: '\$', decimalDigits: 0), - columnWidthMode: ColumnWidthMode.lastColumnFill, - headerText: 'Price') - ]; -} -List _generateList(List employeeData, int count) { - final Random _random = Random(); - int startIndex = employeeData.isNotEmpty ? employeeData.length : 0, - endIndex = startIndex + count; - for (int i = startIndex; i < endIndex; i++) { - employeeData.add(Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); + List _getColumns() { + return [ + GridTextColumn( + columnName: 'id', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'customerId', + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 150 + : double.nan, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'name', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120 : double.nan, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + width: + (isWebOrDesktop && model.isMobileResolution) ? 110 : double.nan, + columnName: 'freight', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'city', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + width: + (isWebOrDesktop && model.isMobileResolution) ? 120 : double.nan, + columnName: 'price', + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ))) + ]; } - return employeeData; } -final List _names = [ - 'Welli', - 'Blonp', - 'Folko', - 'Furip', - 'Folig', - 'Picco', - 'Frans', - 'Warth', - 'Linod', - 'Simop', - 'Merep', - 'Riscu', - 'Seves', - 'Vaffe', - 'Alfki', -]; - -final List _citys = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', -]; - -class Employee { - Employee( +class _Employee { + _Employee( this.id, this.customerId, this.name, this.freight, this.city, this.price); final int id; final int customerId; @@ -177,46 +182,152 @@ class Employee { final double price; } -class EmployeeDataSource extends DataGridSource { - EmployeeDataSource({List employeeData}) { - _employeeData = employeeData; +class _EmployeeDataSource extends DataGridSource { + _EmployeeDataSource() { + _populateData(); + buildDataGridRow(); + } + + List<_Employee> employees = []; + List dataGridRows = []; + + // Building DataGridRows + + void _populateData() { + employees.clear(); + employees = getEmployees(employees, 25); + } + + void buildDataGridRow() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false); } - List _employeeData; + // Overrides @override - List get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(Employee employee, String columnName) { - switch (columnName) { - case 'id': - return employee.id; - break; - case 'name': - return employee.name; - break; - case 'customerId': - return employee.customerId; - break; - case 'freight': - return employee.freight; - break; - case 'price': - return employee.price; - break; - case 'city': - return employee.city; - break; - default: - return 'empty'; - break; - } + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$', decimalDigits: 0) + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); } @override Future handleLoadMoreRows() async { await Future.delayed(Duration(seconds: 5)); - _employeeData = _generateList(dataSource, 15); + employees = getEmployees(employees, 15); + buildDataGridRow(); notifyListeners(); } + + // Employee Data's + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(List<_Employee> employeeData, int count) { + final Random random = Random(); + final int startIndex = employeeData.isNotEmpty ? employeeData.length : 0, + endIndex = startIndex + count; + + for (int i = startIndex; i < endIndex; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); + } + return employeeData; + } } diff --git a/lib/samples/datagrid/loadmore/datagrid_load_more.dart b/lib/samples/datagrid/loadmore/datagrid_load_more.dart index bd602f9d..38b532bc 100644 --- a/lib/samples/datagrid/loadmore/datagrid_load_more.dart +++ b/lib/samples/datagrid/loadmore/datagrid_load_more.dart @@ -12,24 +12,22 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; /// Local import import '../../../model/sample_view.dart'; +/// Renders Load more data grid class LoadMoreDataGrid extends SampleView { - LoadMoreDataGrid({Key key}) : super(key: key); + /// Creates Load more data grid + LoadMoreDataGrid({Key? key}) : super(key: key); @override _LoadMoreDataGridState createState() => _LoadMoreDataGridState(); } class _LoadMoreDataGridState extends SampleViewState { - List _employeeData = []; - EmployeeDataSource _employeeDataSource; + /// DataGridSource required for SfDataGrid to obtain the row data. + final _EmployeeDataSource employeeDataSource = _EmployeeDataSource(); - @override - void initState() { - _populateData(); - _employeeDataSource = EmployeeDataSource(employeeData: _employeeData); - super.initState(); - } + late bool isWebOrDesktop; + /// Building the progress indicator when DataGrid scroller reach the bottom Widget _buildProgressIndicator(bool isLight) { return Container( height: 60.0, @@ -54,6 +52,7 @@ class _LoadMoreDataGridState extends SampleViewState { )))); } + /// Callback method for load more builder Widget _buildLoadMoreView(BuildContext context, LoadMoreRows loadMoreRows) { final isLight = model.themeData.brightness == Brightness.light; bool showIndicator = false; @@ -75,17 +74,12 @@ class _LoadMoreDataGridState extends SampleViewState { ? Color.fromRGBO(0, 0, 0, 0.26) : Color.fromRGBO(255, 255, 255, 0.26)))), child: Container( - width: model.isWeb ? 350.0 : 142.0, + width: isWebOrDesktop ? 350.0 : 142.0, height: 36, decoration: BoxDecoration( color: model.backgroundColor, borderRadius: BorderRadius.circular(4.0)), - child: FlatButton( - child: Text('LOAD MORE', - style: TextStyle( - letterSpacing: model.isWeb ? 1.35 : 0.35, - fontSize: 14, - color: Colors.white)), + child: TextButton( onPressed: () async { // To avoid the "Error: setState() called after dispose():" // while scrolling the datagrid vertically and displaying the @@ -114,103 +108,114 @@ class _LoadMoreDataGridState extends SampleViewState { }); } }, + child: Text('LOAD MORE', + style: TextStyle( + letterSpacing: isWebOrDesktop ? 1.35 : 0.35, + fontSize: 14, + color: Colors.white)), ), )); }); } + List _getColumns() { + return [ + GridTextColumn( + columnName: 'id', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'customerId', + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'name', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'freight', + width: + (isWebOrDesktop && model.isMobileResolution) ? 110.0 : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'city', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ))), + GridTextColumn( + columnName: 'price', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ))) + ]; + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + @override Widget build(BuildContext context) { return SfDataGrid( - source: _employeeDataSource, + source: employeeDataSource, loadMoreViewBuilder: _buildLoadMoreView, columns: _getColumns()); } - - void _populateData() { - _employeeData.clear(); - _employeeData = _generateList(_employeeData, 25); - } } -List _getColumns() { - return [ - GridNumericColumn( - mappingName: 'id', - columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Order ID'), - GridNumericColumn( - mappingName: 'customerId', - columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Customer ID'), - GridTextColumn(mappingName: 'name', headerText: 'Name'), - GridNumericColumn( - mappingName: 'freight', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight'), - GridTextColumn( - mappingName: 'city', - columnWidthMode: !kIsWeb ? ColumnWidthMode.auto : ColumnWidthMode.fill, - headerText: 'City'), - GridNumericColumn( - mappingName: 'price', - numberFormat: NumberFormat.currency( - locale: 'en_US', symbol: '\$', decimalDigits: 0), - columnWidthMode: ColumnWidthMode.lastColumnFill, - headerText: 'Price') - ]; -} - -List _generateList(List employeeData, int count) { - final Random _random = Random(); - int startIndex = employeeData.isNotEmpty ? employeeData.length : 0, - endIndex = startIndex + count; - for (int i = startIndex; i < endIndex; i++) { - employeeData.add(Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); - } - return employeeData; -} - -final List _names = [ - 'Welli', - 'Blonp', - 'Folko', - 'Furip', - 'Folig', - 'Picco', - 'Frans', - 'Warth', - 'Linod', - 'Simop', - 'Merep', - 'Riscu', - 'Seves', - 'Vaffe', - 'Alfki', -]; - -final List _citys = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', -]; - -class Employee { - Employee( +class _Employee { + _Employee( this.id, this.customerId, this.name, this.freight, this.city, this.price); final int id; final int customerId; @@ -220,46 +225,148 @@ class Employee { final double price; } -class EmployeeDataSource extends DataGridSource { - EmployeeDataSource({List employeeData}) { - _employeeData = employeeData; +class _EmployeeDataSource extends DataGridSource { + _EmployeeDataSource() { + _populateData(); + buildDataGridRow(); + } + + List<_Employee> employees = []; + List dataGridRows = []; + + // Building DataGridRows + + void _populateData() { + employees.clear(); + employees = getEmployees(employees, 25); + } + + void buildDataGridRow() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false); } - List _employeeData; + // Overrides @override - List get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(Employee employee, String columnName) { - switch (columnName) { - case 'id': - return employee.id; - break; - case 'name': - return employee.name; - break; - case 'customerId': - return employee.customerId; - break; - case 'freight': - return employee.freight; - break; - case 'price': - return employee.price; - break; - case 'city': - return employee.city; - break; - default: - return 'empty'; - break; - } + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8), + child: Text(row.getCells()[2].value.toString()), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8), + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$', decimalDigits: 0) + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); } @override Future handleLoadMoreRows() async { await Future.delayed(Duration(seconds: 5)); - _employeeData = _generateList(dataSource, 15); + employees = getEmployees(employees, 15); + buildDataGridRow(); notifyListeners(); } + + // Employee Data's + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(List<_Employee> employeeData, int count) { + final Random random = Random(); + final int startIndex = employeeData.isNotEmpty ? employeeData.length : 0, + endIndex = startIndex + count; + for (int i = startIndex; i < endIndex; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); + } + return employeeData; + } } diff --git a/lib/samples/datagrid/paging/datagrid_paging.dart b/lib/samples/datagrid/paging/datagrid_paging.dart index 67134a54..9529bb0f 100644 --- a/lib/samples/datagrid/paging/datagrid_paging.dart +++ b/lib/samples/datagrid/paging/datagrid_paging.dart @@ -4,6 +4,7 @@ import 'dart:math'; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// DataGrid Package import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -17,98 +18,161 @@ import '../../../model/sample_view.dart'; /// Render data pager class PagingDataGrid extends SampleView { /// Create data pager - const PagingDataGrid({Key key}) : super(key: key); + const PagingDataGrid({Key? key}) : super(key: key); @override _PagingDataGridState createState() => _PagingDataGridState(); } -List<_OrderInfo> _dataSource = []; -List<_OrderInfo> _paginatedDataSource = []; - class _PagingDataGridState extends SampleViewState { - static const double _kMobileModeInWeb = 767.0; + // Default pager height static const double dataPagerHeight = 60; - bool _isLandscapeInMobileView; - final _OrderInfoRepository _repository = _OrderInfoRepository(); - final _OrderInfoDataSource _orderInfoDataSource = _OrderInfoDataSource(); + /// Determine to decide whether the device in landscape or in portrait. + bool isLandscapeInMobileView = false; + + late bool isWebOrDesktop; + + /// DataGridSource required for SfDataGrid to obtain the row data. + _OrderInfoDataSource orderInfoDataSource = _OrderInfoDataSource(); @override void initState() { super.initState(); - _dataSource = _repository.getOrderDetails(300); - _paginatedDataSource = _dataSource.getRange(0, 19).toList(growable: false); + isWebOrDesktop = (model.isWeb || model.isDesktop); } @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + isLandscapeInMobileView = !isWebOrDesktop && MediaQuery.of(context).orientation == Orientation.landscape; } - Widget _getDataGrid(BoxConstraints constraint) { + Widget _buildDataGrid() { return SfDataGrid( - source: _orderInfoDataSource, - columnWidthMode: constraint.maxWidth < _kMobileModeInWeb - ? ColumnWidthMode.auto + source: orderInfoDataSource, + columnWidthMode: (isWebOrDesktop && model.isMobileResolution) + ? ColumnWidthMode.none : ColumnWidthMode.fill, columns: [ - GridNumericColumn( - mappingName: 'orderID', - headerText: 'Order ID', - columnWidthMode: _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.none, - headerTextAlignment: Alignment.centerRight), GridTextColumn( - mappingName: 'customerID', headerText: 'Customer Name'), - GridDateTimeColumn( - mappingName: 'orderDate', - headerText: 'Order Date', - dateFormat: DateFormat.yMd()), - GridNumericColumn( - mappingName: 'freight', - headerText: 'Freight', - columnWidthMode: _isLandscapeInMobileView + columnName: 'orderID', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + ), + columnWidthMode: isLandscapeInMobileView ? ColumnWidthMode.fill - : ColumnWidthMode.none, - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center, - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$')), - GridDateTimeColumn( - mappingName: 'shippingDate', - headerText: 'Shipped Date', - dateFormat: DateFormat.yMd()), + : ColumnWidthMode.none), + GridTextColumn( + columnName: 'customerID', + width: 130.0, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + 'Customer Name', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'orderDate', + width: !isWebOrDesktop + ? 110 + : (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + 'Order Date', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'freight', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + ), GridTextColumn( - mappingName: 'shipCountry', headerText: 'Ship Country'), + columnName: 'shippingDate', + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 140.0 + : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + 'Shipped Date', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'shipCountry', + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + 'Ship Country', + overflow: TextOverflow.ellipsis, + ), + )), ]); } - Widget _getDataPager() { + Widget _buildDataPager() { return SfDataPagerTheme( data: SfDataPagerThemeData( brightness: model.themeData.brightness, selectedItemColor: model.backgroundColor, ), child: SfDataPager( - delegate: _orderInfoDataSource, - rowsPerPage: 20, + delegate: orderInfoDataSource, + pageCount: + orderInfoDataSource.orders.length / orderInfoDataSource.rowsPerPage, direction: Axis.horizontal, ), ); } - Widget _getChild() { + Widget _buildLayoutBuilder() { return LayoutBuilder(builder: (context, constraint) { return Column( children: [ SizedBox( height: constraint.maxHeight - dataPagerHeight, width: constraint.maxWidth, - child: _getDataGrid(constraint)), + child: _buildDataGrid()), Container( height: dataPagerHeight, decoration: BoxDecoration( @@ -122,7 +186,7 @@ class _PagingDataGridState extends SampleViewState { bottom: BorderSide.none, left: BorderSide.none, right: BorderSide.none)), - child: Align(alignment: Alignment.center, child: _getDataPager()), + child: Align(alignment: Alignment.center, child: _buildDataPager()), ) ], ); @@ -131,106 +195,109 @@ class _PagingDataGridState extends SampleViewState { @override Widget build(BuildContext context) { - return _getChild(); + return _buildLayoutBuilder(); } } -class _OrderInfoDataSource extends DataGridSource<_OrderInfo> { - @override - List<_OrderInfo> get dataSource => _paginatedDataSource; +class _OrderInfoDataSource extends DataGridSource { + _OrderInfoDataSource() { + orders = getOrders(300); + paginatedOrders = orders.getRange(0, 19).toList(growable: false); + buildPaginateDataGridRows(); + } - @override - Object getValue(_OrderInfo _orderInfo, String columnName) { - switch (columnName) { - case 'orderID': - return _orderInfo.orderID; - break; - case 'employeeID': - return _orderInfo.employeeID; - break; - case 'customerID': - return _orderInfo.customerID; - break; - case 'firstName': - return _orderInfo.firstName; - break; - case 'lastName': - return _orderInfo.lastName; - break; - case 'gender': - return _orderInfo.gender; - break; - case 'shipCity': - return _orderInfo.shipCity; - break; - case 'shipCountry': - return _orderInfo.shipCountry; - break; - case 'freight': - return _orderInfo.freight; - break; - case 'shippingDate': - return _orderInfo.shippingDate; - break; - case 'orderDate': - return _orderInfo.orderData; - break; - case 'isClosed': - return _orderInfo.isClosed; - break; - default: - return ''; - break; - } + final int rowsPerPage = 15; + List<_OrderInfo> orders = []; + List<_OrderInfo> paginatedOrders = []; + List dataGridRows = []; + + // Building PaginateDataGridRows + + void buildPaginateDataGridRows() { + dataGridRows = paginatedOrders.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'orderID', value: dataGridRow.orderID), + DataGridCell(columnName: 'customerID', value: dataGridRow.customerID), + DataGridCell(columnName: 'orderDate', value: dataGridRow.orderData), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell( + columnName: 'shippingDate', value: dataGridRow.shippingDate), + DataGridCell(columnName: 'shipCountry', value: dataGridRow.shipCountry), + ]); + }).toList(growable: false); } + // Overrides + + @override + List get rows => dataGridRows; + @override - int get rowCount => _dataSource.length; + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + DateFormat.yMd().format(row.getCells()[2].value).toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text( + DateFormat.yMd().format(row.getCells()[4].value).toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[5].value.toString(), + overflow: TextOverflow.ellipsis, + )), + ]); + } @override - Future handlePageChange(int oldPageIndex, int newPageIndex, - int startRowIndex, int rowsPerPage) async { - _paginatedDataSource = _dataSource - .getRange(startRowIndex, startRowIndex + rowsPerPage) - .toList(growable: false); - notifyDataSourceListeners(); + Future handlePageChange(int oldPageIndex, int newPageIndex) async { + final int startIndex = newPageIndex * rowsPerPage; + final int endIndex = startIndex + rowsPerPage; + paginatedOrders = + orders.getRange(startIndex, endIndex).toList(growable: false); + buildPaginateDataGridRows(); + notifyListeners(); return true; } -} -/// Order Details -class _OrderInfo { - _OrderInfo( - {this.orderID, - this.employeeID, - this.customerID, - this.firstName, - this.lastName, - this.gender, - this.shipCity, - this.shipCountry, - this.freight, - this.shippingDate, - this.orderData, - this.isClosed}); + // Order Data's - final String orderID; - final String employeeID; - final String customerID; - final String firstName; - final String lastName; - final String gender; - final String shipCity; - final String shipCountry; - final double freight; - final DateTime shippingDate; - final DateTime orderData; - final bool isClosed; -} - -class _OrderInfoRepository { - final List shippedDate = []; final Random random = Random(); + final List shippedDate = []; final Map> shipCity = { 'Argentina': ['Rosario'], 'Austria': ['Graz', 'Salzburg'], @@ -420,16 +487,16 @@ class _OrderInfoRepository { 'USA', ]; - List<_OrderInfo> getOrderDetails(int count) { + List<_OrderInfo> getOrders(int count) { shippedDate ..clear() ..addAll(_getDateBetween(2000, 2014, count)); - List<_OrderInfo> orderDetails = []; + final List<_OrderInfo> orderDetails = []; for (int i = 10001; i <= count + 10000; i++) { - final String ship_Country = + final String _shipCountry = shipCountry[random.nextInt(shipCountry.length)]; - final List ship_CityColl = shipCity[ship_Country]; + final List _shipCityColl = shipCity[_shipCountry]!; final DateTime shippedData = shippedDate[i - 10001]; final DateTime orderedData = DateTime(shippedData.year, shippedData.month, shippedData.day - 2); @@ -440,12 +507,12 @@ class _OrderInfoRepository { firstName: firstNames[random.nextInt(15)], lastName: lastNames[random.nextInt(15)], gender: genders[random.nextInt(5)], - shipCountry: ship_Country, + shipCountry: _shipCountry, orderData: orderedData, shippingDate: shippedData, freight: (random.nextInt(1000) + random.nextDouble()), isClosed: (i + (random.nextInt(10)) > 2) ? true : false, - shipCity: ship_CityColl[random.nextInt(ship_CityColl.length)], + shipCity: _shipCityColl[random.nextInt(_shipCityColl.length)], )); } @@ -455,12 +522,12 @@ class _OrderInfoRepository { int next(int min, int max) => min + random.nextInt(max - min); List _getDateBetween(int startYear, int endYear, int count) { - List date = []; + final List date = []; for (int i = 0; i < count; i++) { - int year = next(startYear, endYear); - int month = random.nextInt(13); - int day = random.nextInt(31); + final int year = next(startYear, endYear); + final int month = random.nextInt(13); + final int day = random.nextInt(31); date.add(DateTime(year, month, day)); } @@ -468,3 +535,33 @@ class _OrderInfoRepository { return date; } } + +/// Order Details +class _OrderInfo { + _OrderInfo( + {required this.orderID, + required this.employeeID, + required this.customerID, + required this.firstName, + required this.lastName, + required this.gender, + required this.shipCity, + required this.shipCountry, + required this.freight, + required this.shippingDate, + required this.orderData, + required this.isClosed}); + + final String orderID; + final String employeeID; + final String customerID; + final String firstName; + final String lastName; + final String gender; + final String shipCity; + final String shipCountry; + final double freight; + final DateTime shippingDate; + final DateTime orderData; + final bool isClosed; +} diff --git a/lib/samples/datagrid/pull_to_refresh/datagrid_pull_to_refresh.dart b/lib/samples/datagrid/pull_to_refresh/datagrid_pull_to_refresh.dart new file mode 100644 index 00000000..69465d96 --- /dev/null +++ b/lib/samples/datagrid/pull_to_refresh/datagrid_pull_to_refresh.dart @@ -0,0 +1,297 @@ +/// Dart import +import 'dart:math'; + +/// Package import +import 'package:intl/intl.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; + +/// DataGrid import +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + +/// Local import +import '../../../model/sample_view.dart'; + +/// Renders pull refresh data grid +class PullToRefreshDataGrid extends SampleView { + /// Creates pull refresh data grid + PullToRefreshDataGrid({Key? key}) : super(key: key); + + @override + _PullToRefreshDataGridState createState() => _PullToRefreshDataGridState(); +} + +class _PullToRefreshDataGridState extends SampleViewState { + /// DataGridSource required for SfDataGrid to obtain the row data. + final _EmployeeDataSource employeeDataSource = _EmployeeDataSource(); + + late bool isWebOrDesktop; + + List _getColumns() { + return [ + GridTextColumn( + columnName: 'id', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'customerId', + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'name', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'freight', + width: + (isWebOrDesktop && model.isMobileResolution) ? 110.0 : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.center, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'price', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + ), + ) + ]; + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + + @override + Widget build(BuildContext context) { + return Theme( + data: ThemeData( + brightness: model.themeData.brightness, + accentColor: model.backgroundColor, + ), + child: SfDataGrid( + source: employeeDataSource, + allowPullToRefresh: true, + columns: _getColumns())); + } +} + +class _Employee { + _Employee( + this.id, this.customerId, this.name, this.freight, this.city, this.price); + final int id; + final int customerId; + final String name; + final String city; + final double freight; + final double price; +} + +class _EmployeeDataSource extends DataGridSource { + _EmployeeDataSource() { + employees = getEmployees(employees, 25); + buildDataGridRows(); + } + + List<_Employee> employees = []; + List dataGridRows = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.center, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency( + locale: 'en_US', symbol: '\$', decimalDigits: 0) + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + )) + ]); + } + + @override + Future handleRefresh() async { + await Future.delayed(Duration(seconds: 5)); + employees = getEmployees(employees, 15); + buildDataGridRows(); + notifyListeners(); + } + + // Employee Data's + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(List<_Employee> employeeData, int count) { + final Random random = Random(); + final int startIndex = employeeData.isNotEmpty ? employeeData.length : 0, + endIndex = startIndex + count; + + for (int i = startIndex; i < endIndex; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); + } + return employeeData; + } +} diff --git a/lib/samples/datagrid/real_time_update/datagrid_real_time_update.dart b/lib/samples/datagrid/real_time_update/datagrid_real_time_update.dart index ef152875..2462a698 100644 --- a/lib/samples/datagrid/real_time_update/datagrid_real_time_update.dart +++ b/lib/samples/datagrid/real_time_update/datagrid_real_time_update.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -14,25 +15,197 @@ import '../../../model/sample_view.dart'; /// Renders real time value change data grid class RealTimeUpdateDataGrid extends SampleView { /// Creates real time value change data grid - const RealTimeUpdateDataGrid({Key key}) : super(key: key); + const RealTimeUpdateDataGrid({Key? key}) : super(key: key); @override _RealTimeUpdateDataGridPageState createState() => _RealTimeUpdateDataGridPageState(); } -List<_Stock> _stockData; - class _RealTimeUpdateDataGridPageState extends SampleViewState { - _RealTimeUpdateDataGridPageState(); + /// Used to refresh the widget for every 200ms respectively. + late Timer timer; + + /// Decide whether to use the sample in mobile or web mode. + bool isLandscapeInMobileView = false; - final math.Random _random = math.Random(); + /// DataGridSource required for SfDataGrid to obtain the row data. + late _RealTimeUpdateDataGridSource realTimeUpdateDataGridSource; - final _RealTimeUpdateDataGridSource _realTimeUpdateDataGridSource = - _RealTimeUpdateDataGridSource(); + late bool isWebOrDesktop; - Timer _timer; - bool _isLandscapeInMobileView; + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + realTimeUpdateDataGridSource = + _RealTimeUpdateDataGridSource(isWebOrDesktop: isWebOrDesktop); + timer = Timer.periodic(const Duration(milliseconds: 200), (Timer args) { + realTimeUpdateDataGridSource.timerTick(args); + }); + } + + SfDataGrid _buildDataGrid() { + return SfDataGrid( + source: realTimeUpdateDataGridSource, + columnWidthMode: isWebOrDesktop || isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + columns: [ + GridTextColumn( + columnName: 'symbol', + width: (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + label: Container( + alignment: Alignment.center, + child: Text('Symbol'), + )), + GridTextColumn( + columnName: 'stock', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, + label: Container( + alignment: Alignment.center, + child: Text('Stock'), + ), + ), + GridTextColumn( + columnName: 'open', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, + label: Container( + alignment: Alignment.center, + child: Text(' Open'), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) ? 150.0 : 130.0, + columnName: 'previousClose', + label: Container( + alignment: Alignment.center, + child: Text('Previous Close'), + ), + ), + GridTextColumn( + columnName: 'lastTrade', + width: + (isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, + label: Container( + alignment: Alignment.center, + child: Text('Last Trade'), + ), + ), + ], + ); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + isLandscapeInMobileView = !isWebOrDesktop && + MediaQuery.of(context).orientation == Orientation.landscape; + } + + @override + Widget build(BuildContext context) { + return Scaffold(body: _buildDataGrid()); + } + + @override + void dispose() { + super.dispose(); + timer.cancel(); + } +} + +class _Stock { + _Stock( + this.symbol, this.stock, this.open, this.previousClose, this.lastTrade); + String symbol; + double stock; + double open; + double previousClose; + int lastTrade; +} + +class _RealTimeUpdateDataGridSource extends DataGridSource { + _RealTimeUpdateDataGridSource({required this.isWebOrDesktop}) { + stocks = getStocks(100); + buildDataGridRows(); + } + + final math.Random random = math.Random(); + + final bool isWebOrDesktop; + + List<_Stock> stocks = []; + + List dataGridRows = []; + + // Runtime Updating the cell values + + void timerTick(Timer args) { + _changeRows(100); + } + + void _changeRows(int count) { + if (stocks.length < count) { + count = stocks.length; + } + + for (int i = 0; i < count; ++i) { + final int recNo = random.nextInt(stocks.length - 1); + + // Reinitialize the DataGridRow for particular row and call the notify to + // view the realtime changes in DataGrid. + void updateDataRow() { + dataGridRows[recNo] = DataGridRow(cells: [ + DataGridCell(columnName: 'symbol', value: stocks[recNo].symbol), + DataGridCell(columnName: 'stock', value: stocks[recNo].stock), + DataGridCell(columnName: 'open', value: stocks[recNo].open), + DataGridCell( + columnName: 'previousClose', value: stocks[recNo].previousClose), + DataGridCell(columnName: 'lastTrade', value: stocks[recNo].lastTrade), + ]); + } + + stocks[recNo].stock = stocksData[(random.nextInt(stocksData.length - 1))]; + updateDataRow(); + updateDataSource(rowColumnIndex: RowColumnIndex(recNo, 1)); + stocks[recNo].open = 50.0 + random.nextInt(40); + updateDataRow(); + updateDataSource(rowColumnIndex: RowColumnIndex(recNo, 2)); + updateDataRow(); + stocks[recNo].previousClose = 50.0 + random.nextInt(30); + updateDataRow(); + updateDataSource(rowColumnIndex: RowColumnIndex(recNo, 3)); + stocks[recNo].lastTrade = 50 + random.nextInt(20); + updateDataRow(); + updateDataSource(rowColumnIndex: RowColumnIndex(recNo, 4)); + } + } + + void buildDataGridRows() { + dataGridRows = stocks.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'symbol', value: dataGridRow.symbol), + DataGridCell(columnName: 'stock', value: dataGridRow.stock), + DataGridCell(columnName: 'open', value: dataGridRow.open), + DataGridCell( + columnName: 'previousClose', value: dataGridRow.previousClose), + DataGridCell(columnName: 'lastTrade', value: dataGridRow.lastTrade), + ]); + }).toList(growable: false); + } + + // Building Widget for each cell + + Widget buildStocks(dynamic value) { + return value >= 0.5 + ? _getWidget(_images[1]!, value) + : _getWidget(_images[0]!, value); + } final Map _images = { 1: Image.asset( @@ -47,7 +220,74 @@ class _RealTimeUpdateDataGridPageState extends SampleViewState { ), }; - final List _stocks = [ + Widget _getWidget(Image image, double stack) { + return Container( + padding: const EdgeInsets.all(4), + color: Colors.transparent, + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: isWebOrDesktop + ? [ + Container(width: 20, child: image), + Container( + width: 50, + child: Text( + ' ' + stack.toString(), + ), + ) + ] + : [ + Container(child: image), + const SizedBox( + width: 6.0, + ), + Flexible( + child: Text( + stack.toString(), + textScaleFactor: 1.0, + ), + ) + ], + ), + ); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.center, + child: Text(row.getCells()[0].value.toString()), + ), + buildStocks(row.getCells()[1].value), + Container( + alignment: Alignment.center, + child: Text(row.getCells()[2].value.toString()), + ), + Container( + alignment: Alignment.center, + child: Text(row.getCells()[3].value.toString()), + ), + Container( + alignment: Alignment.center, + child: Text(row.getCells()[4].value.toString()), + ), + ]); + } + + void updateDataSource({required RowColumnIndex rowColumnIndex}) { + notifyDataSourceListeners(rowColumnIndex: rowColumnIndex); + } + + // Data set for stock data collection + + final List stocksData = [ -0.76, 0.3, 0.42, @@ -67,7 +307,7 @@ class _RealTimeUpdateDataGridPageState extends SampleViewState { -0.94 ]; - final List _symbols = [ + final List symbols = [ 'OJEC', 'PUYU', 'EXTB', @@ -113,191 +353,16 @@ class _RealTimeUpdateDataGridPageState extends SampleViewState { 'HFTB', ]; - List<_Stock> _generateList(int count) { + List<_Stock> getStocks(int count) { final List<_Stock> stockData = <_Stock>[]; - for (int i = 1; i < _symbols.length; i++) { + for (int i = 1; i < symbols.length; i++) { stockData.add(_Stock( - _symbols[i], - _stocks[_random.nextInt(_stocks.length - 1)], - 50.0 + _random.nextInt(40), - 50.0 + _random.nextInt(30), - 50 + _random.nextInt(20))); + symbols[i], + stocksData[random.nextInt(stocksData.length - 1)], + 50.0 + random.nextInt(40), + 50.0 + random.nextInt(30), + 50 + random.nextInt(20))); } return stockData; } - - @override - void initState() { - super.initState(); - _stockData = _generateList(100); - _timer = Timer.periodic(const Duration(milliseconds: 200), (Timer args) { - timerTick(args); - }); - } - - void timerTick(Timer args) { - _changeRows(100); - } - - void _changeRows(int count) { - if (_stockData.length < count) { - count = _stockData.length; - } - - for (int i = 0; i < count; ++i) { - final int recNo = _random.nextInt(_stockData.length - 1); - - _stockData[recNo].stock = _stocks[(_random.nextInt(_stocks.length - 1))]; - _realTimeUpdateDataGridSource.updateDataSource( - rowColumnIndex: RowColumnIndex(recNo, 1)); - - _stockData[recNo].open = 50.0 + _random.nextInt(40); - _realTimeUpdateDataGridSource.updateDataSource( - rowColumnIndex: RowColumnIndex(recNo, 2)); - - _stockData[recNo].previousClose = 50.0 + _random.nextInt(30); - _realTimeUpdateDataGridSource.updateDataSource( - rowColumnIndex: RowColumnIndex(recNo, 3)); - - _stockData[recNo].lastTrade = 50 + _random.nextInt(20); - _realTimeUpdateDataGridSource.updateDataSource( - rowColumnIndex: RowColumnIndex(recNo, 4)); - } - } - - SfDataGrid _dataGridSample() { - return SfDataGrid( - source: _realTimeUpdateDataGridSource, - cellBuilder: (BuildContext context, GridColumn column, int rowIndex) { - if (column.mappingName == 'stock') { - final double stock = _stockData[rowIndex].stock; - return stock >= 0.5 - ? _getWidget(_images[1], stock) - : _getWidget(_images[0], stock); - } else { - return null; - } - }, - columnWidthMode: model.isWeb || _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.header, - columns: [ - GridTextColumn( - mappingName: 'symbol', - headerText: 'Symbol', - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - GridWidgetColumn( - mappingName: 'stock', - headerText: 'Stock', - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - GridNumericColumn( - mappingName: 'open', - headerText: ' Open', - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - GridNumericColumn( - mappingName: 'previousClose', - headerText: 'Previous Close', - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - GridNumericColumn( - mappingName: 'lastTrade', - headerText: 'Last Trade', - headerTextAlignment: Alignment.center, - textAlignment: Alignment.center), - ], - ); - } - - Widget _getWidget(Image image, double stack) { - return Container( - padding: const EdgeInsets.all(4), - color: Colors.transparent, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: model.isWeb - ? [ - Container(width: 20, child: image), - Container( - width: 50, - child: Text( - ' ' + stack.toString(), - ), - ) - ] - : [ - Container(child: image), - const SizedBox( - width: 6.0, - ), - Flexible( - child: Text( - stack.toString(), - textScaleFactor: 1.0, - ), - ) - ], - ), - ); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && - MediaQuery.of(context).orientation == Orientation.landscape; - } - - @override - Widget build(BuildContext context) { - return Scaffold(body: _dataGridSample()); - } - - @override - void dispose() { - super.dispose(); - _timer.cancel(); - } -} - -class _Stock { - _Stock( - this.symbol, this.stock, this.open, this.previousClose, this.lastTrade); - String symbol; - double stock; - double open; - double previousClose; - int lastTrade; -} - -class _RealTimeUpdateDataGridSource extends DataGridSource<_Stock> { - _RealTimeUpdateDataGridSource(); - @override - List<_Stock> get dataSource => _stockData; - @override - Object getValue(_Stock _stock, String columnName) { - switch (columnName) { - case 'symbol': - return _stock.symbol; - break; - case 'open': - return _stock.open; - break; - case 'previousClose': - return _stock.previousClose; - break; - case 'lastTrade': - return _stock.lastTrade; - break; - default: - return 'empty'; - break; - } - } - - void updateDataSource({RowColumnIndex rowColumnIndex}) { - notifyDataSourceListeners(rowColumnIndex: rowColumnIndex); - } } diff --git a/lib/samples/datagrid/row_height/datagrid_row_height.dart b/lib/samples/datagrid/row_height/datagrid_row_height.dart new file mode 100644 index 00000000..11422680 --- /dev/null +++ b/lib/samples/datagrid/row_height/datagrid_row_height.dart @@ -0,0 +1,408 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; + +/// Barcode imports +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:syncfusion_flutter_core/theme.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; + +/// Renders data grid with row height +class RowHeightDataGrid extends SampleView { + /// Creates data grid with row height + const RowHeightDataGrid({Key? key}) : super(key: key); + + @override + _RowHeightDataGridState createState() => _RowHeightDataGridState(); +} + +class _RowHeightDataGridState extends SampleViewState { + /// DataGridSource required for SfDataGrid to obtain the row data. + _RowHeightDataGridSource rowHeightDataGridSource = _RowHeightDataGridSource(); + + late bool isWebOrDesktop; + + Widget _buildDataGrid() { + return SfDataGridTheme( + data: SfDataGridThemeData( + brightness: SfTheme.of(context).brightness, + gridLineStrokeWidth: 1.4, + ), + child: SfDataGrid( + source: rowHeightDataGridSource, + rowHeight: 65.0, + columns: [ + GridTextColumn( + columnName: 'id', + width: isWebOrDesktop ? 135 : 90, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'ID', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'contactName', + width: isWebOrDesktop ? 135 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Contact Name', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'companyName', + width: isWebOrDesktop ? 165 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Company Name', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'address', + width: isWebOrDesktop ? 180 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Address', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'city', + width: isWebOrDesktop ? 150 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'City', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'country', + width: isWebOrDesktop ? 150 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Country', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'designation', + width: isWebOrDesktop ? 150 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Designation', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'postalCode', + width: isWebOrDesktop ? 150 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Postal Code', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + GridTextColumn( + columnName: 'phoneNumber', + width: isWebOrDesktop ? 150 : 140, + label: Container( + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + 'Phone Number', + softWrap: true, + overflow: TextOverflow.clip, + ), + ), + ), + ]), + ); + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + } + + @override + Widget build(BuildContext context) { + return Scaffold(body: _buildDataGrid()); + } +} + +class _Employee { + _Employee( + this.id, + this.contactName, + this.companyName, + this.address, + this.city, + this.country, + this.designation, + this.postalCode, + this.phoneNumber); + final String id; + final String contactName; + final String companyName; + final String address; + final String city; + final String country; + final String designation; + final String postalCode; + final String phoneNumber; +} + +class _RowHeightDataGridSource extends DataGridSource { + _RowHeightDataGridSource() { + employees = getEmployees(); + buildDataGridRow(); + } + + List<_Employee> employees = []; + List dataGridRows = []; + + // Building DataGridRows + + void buildDataGridRow() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'contactName', value: dataGridRow.contactName), + DataGridCell( + columnName: 'companyName', value: dataGridRow.companyName), + DataGridCell(columnName: 'address', value: dataGridRow.address), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'country', value: dataGridRow.country), + DataGridCell( + columnName: 'designation', value: dataGridRow.designation), + DataGridCell( + columnName: 'postalCode', value: dataGridRow.postalCode), + DataGridCell( + columnName: 'phoneNumber', value: dataGridRow.phoneNumber), + ]); + }).toList(); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + return Container( + padding: EdgeInsets.symmetric(vertical: 6.0, horizontal: 16), + alignment: Alignment.centerLeft, + child: Text(dataCell.value.toString()), + ); + }).toList()); + } + + // Employee Data collection set. + + List<_Employee> getEmployees() { + return [ + _Employee('ALFKI', 'Maria Anders', 'Alfreds Futterkiste', 'Obere Str. 57', + 'Berlin', 'Germany', 'Sales Representative', '12209', '030-0074321'), + _Employee( + 'ANATR', + 'Ana Trujillo', + 'Ana Trujillo Emparedados', + 'Avda. de la Constitución 2222', + 'México D.F.', + 'Mexico', + 'Owner', + '05021', + '(5) 555-4729'), + _Employee( + 'ANTON', + 'Antonio Moreno', + 'Antonio Moreno Taquería', + 'Mataderos 2312', + 'México D.F', + 'Mexico', + 'Owner', + '05023', + '(5) 555-3932'), + _Employee('AROUT', 'Thomas Hardy', 'Around the Horn', '120 Hanover Sq.', + 'London', 'UK', 'Sales Representative', 'WA1 1DP', '(71) 555-7788'), + _Employee( + 'BERGS', + 'Christina Berglund', + 'Berglunds snabbköp', + 'Berguvsvägen 8', + 'Luleå', + 'Sweden', + 'Order Administrator', + 'S-958 22', + '0921-12 34 65'), + _Employee( + 'BLAUS', + 'Hanna Moos', + 'Blauer See Delikatessen', + 'Forsterstr. 57', + 'Mannheim', + 'Germany', + 'Sales Representative', + '68306', + '0621-08460'), + _Employee( + 'BLONP', + 'Frédérique Citeaux', + 'Blondel père et fils', + '24, place Kléber', + 'Strasbourg', + 'France', + 'Marketing Manager', + '67000', + '88.60.15.31'), + _Employee( + 'BOLID', + 'Martín Sommer', + 'Bólido Comidas preparadas', + 'C/ Araquil, 67', + 'Madrid', + 'Spain', + 'Marketing Manager' 'Owner', + '28023', + '(91) 555 22 82'), + _Employee( + 'BONAP', + 'Laurence Lebihan', + ''' Bon app' ''', + '12, rue des Bouchers', + 'Marseille', + 'France', + 'Owner', + '13008', + '91.24.45.40'), + _Employee( + 'BOTTM', + 'Elizabeth Lincoln', + 'Bottom-Dollar Markets', + '23 Tsawassen Blvd.', + 'Tsawassen', + 'Canada', + 'Accounting Manager', + 'T2F 8M4', + '(604) 555-4729'), + _Employee( + 'BSBEV', + 'Victoria Ashworth', + '''B's Beverages''', + 'Fauntleroy Circus', + 'London', + 'UK', + 'Sales Representative', + 'EC2 5NT', + '(71) 555-1212'), + _Employee( + 'CACTU', + 'Patricio Simpson', + 'Cactus Comidas para llevar', + 'Cerrito 333', + 'Buenos Aires', + 'Argentina', + 'Sales Agent', + '1010', + '(1) 135-5555'), + _Employee( + 'CENTC', + 'Francisco Chang', + 'Centro comercial Moctezuma', + 'Sierras de Granada 9993', + 'México D.F.', + 'Mexico', + 'Marketing Manager', + '05022', + '0452-076545'), + _Employee('CHOPS', 'Yang Wang', 'Chop-suey Chinese', 'Hauptstr. 29', + 'Bern', 'Switzerland', 'Owner', '3012', '(5) 555-3392'), + _Employee( + 'COMMI', + 'Pedro Afonso', + 'Comércio Mineiro', + 'Av. dos Lusíadas, 23', + 'São Paulo', + 'Brazil', + 'Sales Associate', + '05432-043', + '(11) 555-7647'), + _Employee( + 'CONSH', + 'Elizabeth Brown', + 'Consolidated Holdings', + ''' Berkeley Gardens +12 Brewery ''', + 'London', + 'UK', + 'Sales Representative', + 'WX1 6LT', + '7675-3425'), + _Employee( + 'DRACD', + 'Sven Ottlieb', + 'Drachenblut Delikatessen', + 'Walserweg 21', + 'Aachen', + 'Germany', + 'Order Administrator', + '52066', + '(71) 555-2282'), + _Employee( + 'DUMON', + 'Janine Labrune', + 'Du monde entier', + '67, rue des Cinquante Otages', + 'Nantes', + 'France', + 'Owner', + '44000', + '0241-039123'), + _Employee('EASTC', 'Ann Devon', 'Eastern Connection', '35 King George', + 'London', 'UK', 'Sales Agent', 'WX3 6FW', '40.67.88.88'), + _Employee('ERNSH', 'Roland Mendel', 'Ernst Handel', 'Kirchgasse 6', + 'Graz', 'Austria', 'Sales Manager', '8010', '(71) 555-0297') + ]; + } +} diff --git a/lib/samples/datagrid/selection/datagrid_selection.dart b/lib/samples/datagrid/selection/datagrid_selection.dart index a0c09886..1400bc52 100644 --- a/lib/samples/datagrid/selection/datagrid_selection.dart +++ b/lib/samples/datagrid/selection/datagrid_selection.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter/foundation.dart'; /// Barcode import import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -14,176 +15,56 @@ import '../../../model/sample_view.dart'; /// Renders datagrid with selection option(single/multiple and select/unselect) class SelectionDataGrid extends SampleView { /// Creates datagrid with selection option(single/multiple and select/unselect) - const SelectionDataGrid({Key key}) : super(key: key); + const SelectionDataGrid({Key? key}) : super(key: key); @override _SelectionDataGridPageState createState() => _SelectionDataGridPageState(); } -List<_Employee> _employeeData; - class _SelectionDataGridPageState extends SampleViewState { - _SelectionDataGridPageState(); - bool _isLandscapeInMobileView; - final math.Random _random = math.Random(); - - final _SelectionDataGridSource _selectionDataGridSource = - _SelectionDataGridSource(); - - final List _names = [ - 'Welli', - 'Blonp', - 'Folko', - 'Furip', - 'Folig', - 'Picco', - 'Frans', - 'Warth', - 'Linod', - 'Simop', - 'Merep', - 'Riscu', - 'Seves', - 'Vaffe', - 'Alfki', - ]; + /// Determine to decide whether the device in landscape or in portrait. + bool isLandscapeInMobileView = false; - final List _citys = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', - ]; - - DataGridController getDataGridController() { - final DataGridController _dataGridController = DataGridController(); - _dataGridController.selectedRows.add(_employeeData[2]); - _dataGridController.selectedRows.add(_employeeData[4]); - _dataGridController.selectedRows.add(_employeeData[6]); - - return _dataGridController; - } - - List<_Employee> generateList(int count) { - final List<_Employee> employeeData = <_Employee>[]; - for (int i = 0; i < count; i++) { - employeeData.add(_Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); - } - - return employeeData; - } - - List getColumns() { - List columns; - - columns = model.isWeb - ? [ - GridNumericColumn( - mappingName: 'id', - headerText: 'Order ID', - padding: const EdgeInsets.all(8), - headerTextAlignment: Alignment.centerRight, - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.auto), - GridNumericColumn( - mappingName: 'customerId', - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.header, - headerText: 'Customer ID', - headerTextAlignment: Alignment.centerRight), - GridTextColumn( - mappingName: 'name', - headerText: 'Name', - headerTextAlignment: Alignment.centerLeft), - GridNumericColumn( - mappingName: 'freight', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight', - headerTextAlignment: Alignment.centerRight), - GridTextColumn( - mappingName: 'city', - headerTextAlignment: Alignment.centerLeft, - headerText: 'City', - columnWidthMode: - model.isWeb ? ColumnWidthMode.none : ColumnWidthMode.auto), - GridNumericColumn( - mappingName: 'price', - numberFormat: - NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Price') - ] - : [ - GridNumericColumn( - mappingName: 'id', - headerText: 'Order ID', - padding: const EdgeInsets.all(8), - headerTextAlignment: Alignment.centerRight), - GridNumericColumn( - mappingName: 'customerId', - headerTextAlignment: Alignment.centerRight, - headerText: 'Customer ID'), - GridTextColumn( - mappingName: 'name', - headerTextAlignment: Alignment.centerLeft, - headerText: 'Name'), - GridTextColumn( - mappingName: 'city', - headerText: 'City', - headerTextAlignment: Alignment.centerLeft, - columnWidthMode: ColumnWidthMode.lastColumnFill), - ]; - return columns; - } + /// Determine the selection mode of SfDatGrid. + SelectionMode selectionMode = SelectionMode.multiple; + String _selectionMode = ''; - SfDataGrid _dataGridSample( - [SelectionMode selectionMode, GridNavigationMode navigationMode]) { - return SfDataGrid( - columnWidthMode: model.isWeb || _isLandscapeInMobileView - ? ColumnWidthMode.fill - : ColumnWidthMode.header, - source: _selectionDataGridSource, - selectionMode: selectionMode, - navigationMode: navigationMode, - controller: getDataGridController(), - columns: getColumns(), - ); - } + /// Determine the navigation mode of SfDatGrid. + GridNavigationMode navigationMode = GridNavigationMode.cell; + String _navigationMode = ''; - @override - void initState() { - super.initState(); - _selectionMode = 'Multiple'; - selectionMode = SelectionMode.multiple; - _navigationMode = model.isWeb ? 'Cell' : 'Row'; - navigationMode = - model.isWeb ? GridNavigationMode.cell : GridNavigationMode.row; - _employeeData = generateList(100); - } + /// DataGridSource required for SfDataGrid to obtain the row data. + late _SelectionDataGridSource selectionDataGridSource; - String _selectionMode; - SelectionMode selectionMode = SelectionMode.multiple; + final DataGridController _dataGridController = DataGridController(); - String _navigationMode; - GridNavigationMode navigationMode; + late bool isWebOrDesktop; + /// Selection modes for drop down widget final List _encoding = [ 'None', 'Single', 'Single Deselect', 'Multiple', ]; + + /// Navigation modes for drop down widget + final List _navigation = [ + 'Cell', + 'Row', + ]; + + /// DataGridController to do the programmatical selection. + DataGridController getDataGridController() { + _dataGridController.selectedRows + .add(selectionDataGridSource.dataGridRows[2]); + _dataGridController.selectedRows + .add(selectionDataGridSource.dataGridRows[4]); + _dataGridController.selectedRows + .add(selectionDataGridSource.dataGridRows[6]); + return _dataGridController; + } + void _onSelectionModeChanged(String item) { _selectionMode = item; switch (_selectionMode) { @@ -205,10 +86,6 @@ class _SelectionDataGridPageState extends SampleViewState { }); } - final List _navigation = [ - 'Cell', - 'Row', - ]; void _onNavigationModeChanged(String item) { _navigationMode = item; switch (_navigationMode) { @@ -224,6 +101,172 @@ class _SelectionDataGridPageState extends SampleViewState { }); } + List getColumns() { + List columns; + + columns = isWebOrDesktop + ? [ + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'id', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + columnName: 'customerId', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'name', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + columnName: 'freight', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'city', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnName: 'price', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + )) + ] + : [ + GridTextColumn( + columnName: 'id', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'customerId', + width: 110, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'name', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + columnWidthMode: ColumnWidthMode.lastColumnFill), + ]; + return columns; + } + + SfDataGrid _buildDataGrid( + SelectionMode selectionMode, GridNavigationMode navigationMode) { + return SfDataGrid( + columnWidthMode: isWebOrDesktop || isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + source: selectionDataGridSource, + selectionMode: selectionMode, + navigationMode: navigationMode, + controller: getDataGridController(), + columns: getColumns(), + ); + } + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + _selectionMode = 'Multiple'; + selectionMode = SelectionMode.multiple; + _navigationMode = isWebOrDesktop ? 'Cell' : 'Row'; + navigationMode = + isWebOrDesktop ? GridNavigationMode.cell : GridNavigationMode.row; + selectionDataGridSource = + _SelectionDataGridSource(isWebOrDesktop: isWebOrDesktop); + } + @override Widget buildSettings(BuildContext context) { return StatefulBuilder( @@ -294,7 +337,7 @@ class _SelectionDataGridPageState extends SampleViewState { value: _navigationMode, items: _navigation.map((String value) { return DropdownMenuItem( - value: (value != null) ? value : 'Cell', + value: value, child: Text('$value', textAlign: TextAlign.center, style: TextStyle(color: model.textColor))); @@ -316,13 +359,13 @@ class _SelectionDataGridPageState extends SampleViewState { @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + isLandscapeInMobileView = !isWebOrDesktop && MediaQuery.of(context).orientation == Orientation.landscape; } @override Widget build(BuildContext context) { - return _dataGridSample(selectionMode, navigationMode); + return _buildDataGrid(selectionMode, navigationMode); } } @@ -337,34 +380,175 @@ class _Employee { final double price; } -class _SelectionDataGridSource extends DataGridSource<_Employee> { - _SelectionDataGridSource(); +class _SelectionDataGridSource extends DataGridSource { + _SelectionDataGridSource({required this.isWebOrDesktop}) { + employees = getEmployees(100); + buildDataGridRows(); + } + + final bool isWebOrDesktop; + List dataGridRows = []; + List<_Employee> employees = []; + + // Building DataGridRows + + void buildDataGridRows() { + dataGridRows = isWebOrDesktop + ? employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false) + : employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'city', value: dataGridRow.city), + ]); + }).toList(growable: false); + } + + // Overrides + @override - List<_Employee> get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(_Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'name': - return _employee.name; - break; - case 'customerId': - return _employee.customerId; - break; - case 'freight': - return _employee.freight; - break; - case 'price': - return _employee.price; - break; - case 'city': - return _employee.city; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + if (isWebOrDesktop) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } else { + Widget buildWidget({ + AlignmentGeometry alignment = Alignment.centerLeft, + EdgeInsetsGeometry padding = const EdgeInsets.all(8.0), + TextOverflow textOverflow = TextOverflow.ellipsis, + required Object value, + }) { + return Container( + padding: padding, + alignment: alignment, + child: Text( + value.toString(), + overflow: textOverflow, + ), + ); + } + + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + if (dataCell.columnName == 'id' || + dataCell.columnName == 'customerId') { + return buildWidget( + alignment: Alignment.centerRight, value: dataCell.value); + } else { + return buildWidget(value: dataCell.value); + } + }).toList(growable: false)); } } + + // Employee Data's + + final math.Random random = math.Random(); + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(int count) { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < count; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); + } + return employeeData; + } } diff --git a/lib/samples/datagrid/sorting/datagrid_sorting.dart b/lib/samples/datagrid/sorting/datagrid_sorting.dart index b34e7f3f..ffc50bb5 100644 --- a/lib/samples/datagrid/sorting/datagrid_sorting.dart +++ b/lib/samples/datagrid/sorting/datagrid_sorting.dart @@ -1,60 +1,74 @@ +import 'dart:math'; + import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:flutter_examples/model/sample_view.dart'; -import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; -import 'dart:math'; - -List _employeeData; -Random _random = Random(); +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +/// Renders sorting data grid class SortingDataGrid extends SampleView { - SortingDataGrid({Key key}) : super(key: key); + /// Creates sorting data grid + SortingDataGrid({Key? key}) : super(key: key); @override _SortingDataGridState createState() => _SortingDataGridState(); } class _SortingDataGridState extends SampleViewState { - _SortingDataSource _sortingDataGridSource; - bool _allowSorting = true; - bool _allowMultiSorting = false; - bool _allowTriStateSorting = false; - bool _allowColumnSorting = true; - bool _showSortNumbers = false; - bool _isLandscapeInMobileView; + /// DataGridSource required for SfDataGrid to obtain the row data. + final _SortingDataSource sortingDataGridSource = _SortingDataSource(); + + /// Decide to perform sorting in SfDataGrid. + bool allowSorting = true; + + /// Decide to perform multi column sorting in SfDataGrid. + bool allowMultiSorting = false; + + /// Decide to perform tri column sorting in SfDataGrid. + bool allowTriStateSorting = false; + + /// Decide to perform sorting. + bool allowColumnSorting = true; + + /// Determine the show the sorting number in header. + bool showSortNumbers = false; + + /// Determine to decide whether the device in landscape or in portrait. + bool isLandscapeInMobileView = false; + + late bool isWebOrDesktop; @override void initState() { super.initState(); - _employeeData = generateList(); - _sortingDataGridSource = _SortingDataSource(); - _sortingDataGridSource.sortedColumns.add(SortColumnDetails( + isWebOrDesktop = (model.isWeb || model.isDesktop); + sortingDataGridSource.sortedColumns.add(SortColumnDetails( name: 'id', sortDirection: DataGridSortDirection.descending)); } @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + isLandscapeInMobileView = !isWebOrDesktop && MediaQuery.of(context).orientation == Orientation.landscape; } @override Widget build(BuildContext context) { return SfDataGrid( - source: _sortingDataGridSource, + source: sortingDataGridSource, columns: getColumns(), gridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both, - columnWidthMode: kIsWeb || _isLandscapeInMobileView + columnWidthMode: isWebOrDesktop || isLandscapeInMobileView ? ColumnWidthMode.fill - : ColumnWidthMode.header, - allowSorting: _allowSorting, - allowMultiColumnSorting: _allowMultiSorting, - allowTriStateSorting: _allowTriStateSorting, - showSortNumbers: _showSortNumbers, + : ColumnWidthMode.none, + allowSorting: allowSorting, + allowMultiColumnSorting: allowMultiSorting, + allowTriStateSorting: allowTriStateSorting, + showSortNumbers: showSortNumbers, ); } @@ -71,10 +85,10 @@ class _SortingDataGridState extends SampleViewState { trailing: Transform.scale( scale: 0.8, child: CupertinoSwitch( - value: _allowSorting, + value: allowSorting, onChanged: (bool value) { setState(() { - _allowSorting = value; + allowSorting = value; stateSetter(() {}); }); }, @@ -86,10 +100,10 @@ class _SortingDataGridState extends SampleViewState { trailing: Transform.scale( scale: 0.8, child: CupertinoSwitch( - value: _allowMultiSorting, + value: allowMultiSorting, onChanged: (bool value) { setState(() { - _allowMultiSorting = value; + allowMultiSorting = value; stateSetter(() {}); }); }, @@ -100,10 +114,10 @@ class _SortingDataGridState extends SampleViewState { trailing: Transform.scale( scale: 0.8, child: CupertinoSwitch( - value: _allowTriStateSorting, + value: allowTriStateSorting, onChanged: (bool value) { setState(() { - _allowTriStateSorting = value; + allowTriStateSorting = value; stateSetter(() {}); }); }, @@ -112,10 +126,10 @@ class _SortingDataGridState extends SampleViewState { trailing: Transform.scale( scale: 0.8, child: CupertinoSwitch( - value: _allowColumnSorting, + value: allowColumnSorting, onChanged: (bool value) { setState(() { - _allowColumnSorting = value; + allowColumnSorting = value; stateSetter(() {}); }); }, @@ -129,10 +143,10 @@ class _SortingDataGridState extends SampleViewState { trailing: Transform.scale( scale: 0.8, child: CupertinoSwitch( - value: _showSortNumbers, + value: showSortNumbers, onChanged: (bool value) { setState(() { - _showSortNumbers = value; + showSortNumbers = value; stateSetter(() {}); }); }, @@ -144,85 +158,110 @@ class _SortingDataGridState extends SampleViewState { List getColumns() { return [ - GridNumericColumn( - mappingName: 'id', + GridTextColumn( + columnName: 'id', columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Order ID'), - GridNumericColumn( - mappingName: 'customerId', + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + width: !isWebOrDesktop + ? 100 + : (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'customerId', columnWidthMode: - !kIsWeb ? ColumnWidthMode.header : ColumnWidthMode.fill, - headerText: 'Customer ID'), + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + )), GridTextColumn( - mappingName: 'name', - headerText: 'Name', - allowSorting: _allowColumnSorting), - GridNumericColumn( - mappingName: 'freight', - numberFormat: NumberFormat.currency(locale: 'en_US', symbol: '\$'), - headerText: 'Freight'), + columnName: 'name', + width: !isWebOrDesktop + ? 80 + : (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + allowSorting: allowColumnSorting), GridTextColumn( - mappingName: 'city', - columnWidthMode: - !kIsWeb ? ColumnWidthMode.auto : ColumnWidthMode.fill, - headerText: 'City'), - GridNumericColumn( - mappingName: 'price', - numberFormat: NumberFormat.currency( - locale: 'en_US', symbol: '\$', decimalDigits: 0), - columnWidthMode: ColumnWidthMode.lastColumnFill, - headerText: 'Price') + columnName: 'freight', + width: !isWebOrDesktop + ? 120 + : (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + width: !isWebOrDesktop + ? 90 + : (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + columnWidthMode: + !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'price', + width: + (isWebOrDesktop && model.isMobileResolution) ? 120.0 : double.nan, + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + ), + ) ]; } } -List generateList() { - final List employeeData = []; - for (int i = 0; i < 30; i++) { - employeeData.add(Employee( - 1000 + i, - 1700 + i, - _names[i < _names.length ? i : _random.nextInt(_names.length - 1)], - _random.nextInt(1000) + _random.nextDouble(), - _citys[_random.nextInt(_citys.length - 1)], - 1500.0 + _random.nextInt(100), - )); - } - return employeeData; -} - -final List _names = [ - 'Welli', - 'Blonp', - 'Folko', - 'Furip', - 'Folig', - 'Picco', - 'Frans', - 'Warth', - 'Linod', - 'Simop', - 'Merep', - 'Riscu', - 'Seves', - 'Vaffe', - 'Alfki', -]; - -final List _citys = [ - 'Bruxelles', - 'Rosario', - 'Recife', - 'Graz', - 'Montreal', - 'Tsawassen', - 'Campinas', - 'Resende', -]; - -class Employee { - Employee( +class _Employee { + _Employee( this.id, this.customerId, this.name, this.freight, this.city, this.price); final int id; final int customerId; @@ -232,34 +271,130 @@ class Employee { final double price; } -class _SortingDataSource extends DataGridSource { - _SortingDataSource(); +class _SortingDataSource extends DataGridSource { + _SortingDataSource() { + employees = getEmployees(); + buildDataGridRows(); + } + + List<_Employee> employees = []; + + List dataGridRows = []; + + void buildDataGridRows() { + dataGridRows = employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell(columnName: 'price', value: dataGridRow.price), + ]); + }).toList(growable: false); + } + @override - List get dataSource => _employeeData; + List get rows => dataGridRows; + @override - Object getValue(Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'name': - return _employee.name; - break; - case 'customerId': - return _employee.customerId; - break; - case 'freight': - return _employee.freight; - break; - case 'price': - return _employee.price; - break; - case 'city': - return _employee.city; - break; - default: - return 'empty'; - break; + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(8.0), + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + )), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8.0), + child: Text( + NumberFormat.currency( + locale: 'en_US', symbol: '\$', decimalDigits: 0) + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + )), + ]); + } + + Random random = Random(); + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees() { + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < 30; i++) { + employeeData.add(_Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + )); } + return employeeData; } } diff --git a/lib/samples/datagrid/swiping/datagrid_swiping.dart b/lib/samples/datagrid/swiping/datagrid_swiping.dart new file mode 100644 index 00000000..e5cd67e9 --- /dev/null +++ b/lib/samples/datagrid/swiping/datagrid_swiping.dart @@ -0,0 +1,657 @@ +/// Dart import +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_examples/model/sample_view.dart'; +import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:collection/collection.dart'; + +/// Renders column type data grid +class SwipingDataGrid extends SampleView { + /// Creates column type data grid + const SwipingDataGrid({Key? key}) : super(key: key); + + @override + _SwipingDataGridState createState() => _SwipingDataGridState(); +} + +class _SwipingDataGridState extends SampleViewState { + /// Determine to decide whether the device in landscape or in portrait. + bool isLandscapeInMobileView = false; + + /// DataGridSource required for SfDataGrid to obtain the row data. + late _EmployeeDataSource employeeDataSource; + + /// Editing controller for forms to perform update the values. + TextEditingController? orderIdController, + customerIdController, + cityController, + nameController, + freightController, + priceController; + + /// Used to validate the forms + final GlobalKey _formKey = GlobalKey(); + + late bool isWebOrDesktop; + + @override + void initState() { + super.initState(); + isWebOrDesktop = (model.isWeb || model.isDesktop); + employeeDataSource = _EmployeeDataSource(isWebOrDesktop: isWebOrDesktop); + orderIdController = TextEditingController(); + customerIdController = TextEditingController(); + cityController = TextEditingController(); + nameController = TextEditingController(); + freightController = TextEditingController(); + priceController = TextEditingController(); + } + + /// Building the each field with label and TextFormField + Widget _buildRow( + {required TextEditingController controller, required String columnName}) { + final keyboardType = ['City', 'Name'].contains(columnName) + ? TextInputType.text + : TextInputType.number; + final inputFormatter = ['City', 'Name'].contains(columnName) + ? FilteringTextInputFormatter.allow(RegExp('[a-zA-Z]')) + : FilteringTextInputFormatter.allow(RegExp('[0-9]')); + + return Row( + children: [ + Container( + width: isWebOrDesktop ? 150 : 130, + padding: EdgeInsets.symmetric(vertical: 15), + child: Text(columnName)), + Container( + width: isWebOrDesktop ? 150 : 130, + child: TextFormField( + validator: (value) { + if (value!.isEmpty) { + return 'Field must not be empty'; + } + return null; + }, + controller: controller, + keyboardType: keyboardType, + inputFormatters: [inputFormatter], + ), + ) + ], + ); + } + + /// Building the forms to edit the data + Widget _buildAlertDialogContent() { + return isWebOrDesktop + ? Column( + children: [ + _buildRow(controller: orderIdController!, columnName: 'Order ID'), + _buildRow( + controller: customerIdController!, columnName: 'Customer ID'), + _buildRow(controller: nameController!, columnName: 'Name'), + _buildRow(controller: freightController!, columnName: 'Freight'), + _buildRow(controller: cityController!, columnName: 'City'), + _buildRow(controller: priceController!, columnName: 'Price'), + ], + ) + : Column( + children: [ + _buildRow(controller: orderIdController!, columnName: 'Order ID'), + _buildRow( + controller: customerIdController!, columnName: 'Customer ID'), + _buildRow(controller: nameController!, columnName: 'Name'), + _buildRow(controller: cityController!, columnName: 'City'), + ], + ); + } + + /// Updating the DataGridRows after changing the value and notify the DataGrid + /// to refresh the view + void _processCellUpdate(DataGridRow row, BuildContext buildContext) { + final rowIndex = employeeDataSource.dataGridRows.indexOf(row); + + if (_formKey.currentState!.validate()) { + employeeDataSource.employees[rowIndex] = _Employee( + int.tryParse(orderIdController!.text)!, + int?.tryParse(customerIdController!.text)!, + nameController!.text, + freightController!.text == '' + ? 0.0 + : double.tryParse(freightController!.text)!, + cityController!.text, + priceController!.text == '' + ? 0.0 + : double.tryParse(priceController!.text)!, + ); + employeeDataSource.updateDataGridRow(); + employeeDataSource.updateDataSource(); + Navigator.pop(buildContext); + } + } + + // Updating the data to the TextEditingController + void _updateTextFieldContext(DataGridRow row) { + final orderId = row + .getCells() + .firstWhereOrNull((element) => element.columnName == 'id') + ?.value + .toString(); + orderIdController!.text = orderId ?? ''; + + final customerId = row + .getCells() + .firstWhereOrNull((element) => element.columnName == 'customerId') + ?.value + .toString(); + + customerIdController!.text = customerId ?? ''; + + final name = row + .getCells() + .firstWhereOrNull((element) => element.columnName == 'name') + ?.value + .toString(); + + nameController!.text = name ?? ''; + + final freight = row + .getCells() + .firstWhereOrNull((element) => element.columnName == 'freight') + ?.value; + + freightController!.text = + freight == null ? '' : freight.roundToDouble().toString(); + + final city = row + .getCells() + .firstWhereOrNull( + (element) => element.columnName == 'city', + ) + ?.value + .toString(); + + cityController!.text = city ?? ''; + + final price = row + .getCells() + .firstWhereOrNull( + (element) => element.columnName == 'price', + ) + ?.value + .toString(); + + priceController!.text = price ?? ''; + } + + /// Building the option button on the bottom of the alert popup + List _buildActionButtons(DataGridRow row, BuildContext buildContext) { + return [ + TextButton( + onPressed: () => _processCellUpdate(row, buildContext), + child: Text( + 'SAVE', + style: TextStyle(color: model.backgroundColor), + ), + ), + TextButton( + onPressed: () => Navigator.pop(buildContext), + child: Text( + 'CANCEL', + style: TextStyle(color: model.backgroundColor), + ), + ), + ]; + } + + /// Editing the DataGridRow + void _handleEditWidgetTap(DataGridRow row) { + _updateTextFieldContext(row); + showDialog( + context: context, + builder: (context) => AlertDialog( + scrollable: true, + titleTextStyle: TextStyle( + color: model.textColor, fontWeight: FontWeight.bold, fontSize: 16), + title: Text('Edit Details'), + actions: _buildActionButtons(row, context), + content: Scrollbar( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Form( + key: _formKey, + child: _buildAlertDialogContent(), + ), + ), + ), + ), + ); + } + + /// Deleting the DataGridRow + void _handleDeleteWidgetTap(DataGridRow row) { + final index = employeeDataSource.dataGridRows.indexOf(row); + employeeDataSource.dataGridRows.remove(row); + employeeDataSource.employees.remove(employeeDataSource.employees[index]); + employeeDataSource.updateDataSource(); + showDialog( + context: context, + builder: (context) => AlertDialog( + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + 'OK', + style: TextStyle(color: model.backgroundColor), + ), + ), + ], + content: Text('Row deleted successfully'), + ), + ); + } + + /// Callback for left swiping, and it will flipped for RTL case + Widget _buildStartSwipeWidget(BuildContext context, DataGridRow row) { + return GestureDetector( + onTap: () => _handleEditWidgetTap(row), + child: Container( + color: Colors.blueAccent, + padding: const EdgeInsets.only(left: 16.0, right: 16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.edit, color: Colors.white, size: 20), + SizedBox(width: 16.0), + Text( + 'EDIT', + style: TextStyle(color: Colors.white, fontSize: 15), + ) + ], + ), + ), + ); + } + + /// Callback for right swiping, and it will flipped for RTL case + Widget _buildEndSwipeWidget(BuildContext context, DataGridRow row) { + return GestureDetector( + onTap: () => _handleDeleteWidgetTap(row), + child: Container( + color: Colors.redAccent, + padding: const EdgeInsets.only(left: 16.0, right: 16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.delete, color: Colors.white, size: 20), + SizedBox(width: 16.0), + Text( + 'DELETE', + style: TextStyle(color: Colors.white, fontSize: 15), + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Container( + child: SfDataGrid( + allowSwiping: true, + swipeMaxOffset: 121.0, + columns: getColumns(), + source: employeeDataSource, + columnWidthMode: ColumnWidthMode.fill, + endSwipeActionsBuilder: _buildEndSwipeWidget, + startSwipeActionsBuilder: _buildStartSwipeWidget, + ), + ); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + isLandscapeInMobileView = !isWebOrDesktop && + MediaQuery.of(context).orientation == Orientation.landscape; + } + + List getColumns() { + List columns; + columns = isWebOrDesktop + ? [ + GridTextColumn( + columnName: 'id', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Order ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'customerId', + width: (isWebOrDesktop && model.isMobileResolution) + ? 150.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + )), + GridTextColumn( + columnName: 'name', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(8), + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'freight', + width: (isWebOrDesktop && model.isMobileResolution) + ? 110.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Freight', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'price', + width: (isWebOrDesktop && model.isMobileResolution) + ? 120.0 + : double.nan, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Price', + overflow: TextOverflow.ellipsis, + ), + ), + ) + ] + : [ + GridTextColumn( + columnName: 'id', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'customerId', + columnWidthMode: isLandscapeInMobileView + ? ColumnWidthMode.fill + : ColumnWidthMode.none, + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + 'Customer ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'name', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridTextColumn( + columnName: 'city', + label: Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + 'City', + overflow: TextOverflow.ellipsis, + ), + ), + ), + ]; + return columns; + } +} + +class _Employee { + _Employee( + this.id, this.customerId, this.name, this.freight, this.city, this.price); + final int id; + final int customerId; + final String name; + final String city; + final double freight; + final double price; +} + +class _EmployeeDataSource extends DataGridSource { + _EmployeeDataSource({required this.isWebOrDesktop}) { + employees = getEmployees(100); + updateDataGridRow(); + } + + final bool isWebOrDesktop; + List dataGridRows = []; + List<_Employee> employees = []; + + // Building and Updating DataGridRows + + void updateDataGridRow() { + dataGridRows = isWebOrDesktop + ? employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell( + columnName: 'freight', value: dataGridRow.freight), + DataGridCell(columnName: 'city', value: dataGridRow.city), + DataGridCell( + columnName: 'price', value: dataGridRow.price), + ]); + }).toList() + : employees.map((dataGridRow) { + return DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell( + columnName: 'customerId', value: dataGridRow.customerId), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell(columnName: 'city', value: dataGridRow.city), + ]); + }).toList(); + } + + // Overrides + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + if (isWebOrDesktop) { + return DataGridRowAdapter(cells: [ + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[0].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + row.getCells()[1].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.all(8), + child: Text( + row.getCells()[2].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[3].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerLeft, + child: Text( + row.getCells()[4].value.toString(), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: const EdgeInsets.all(8), + alignment: Alignment.centerRight, + child: Text( + NumberFormat.currency(locale: 'en_US', symbol: '\$') + .format(row.getCells()[5].value) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ), + ]); + } else { + Widget buildWidget({ + AlignmentGeometry alignment = Alignment.centerLeft, + EdgeInsetsGeometry padding = const EdgeInsets.all(8.0), + TextOverflow textOverflow = TextOverflow.ellipsis, + required Object value, + }) { + return Container( + padding: padding, + alignment: alignment, + child: Text( + value.toString(), + overflow: textOverflow, + ), + ); + } + + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + if (dataCell.columnName == 'id' || + dataCell.columnName == 'customerId') { + return buildWidget( + alignment: Alignment.centerRight, value: dataCell.value); + } else { + return buildWidget(value: dataCell.value); + } + }).toList(growable: false)); + } + } + + void updateDataSource() { + notifyListeners(); + } + + final List names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List cities = [ + 'Bruxelles', + 'Rosario', + 'Recife', + 'Graz', + 'Montreal', + 'Tsawassen', + 'Campinas', + 'Resende', + ]; + + List<_Employee> getEmployees(int count) { + final Random random = Random(); + final List<_Employee> employeeData = <_Employee>[]; + for (int i = 0; i < count; i++) { + employeeData.add( + _Employee( + 1000 + i, + 1700 + i, + names[i < names.length ? i : random.nextInt(names.length - 1)], + random.nextInt(1000) + random.nextDouble(), + cities[random.nextInt(cities.length - 1)], + 1500.0 + random.nextInt(100), + ), + ); + } + return employeeData; + } +} diff --git a/lib/samples/date_picker/blackout_date_picker.dart b/lib/samples/date_picker/blackout_date_picker.dart index afc1a2aa..1ac978a1 100644 --- a/lib/samples/date_picker/blackout_date_picker.dart +++ b/lib/samples/date_picker/blackout_date_picker.dart @@ -22,8 +22,8 @@ class BlackoutDatePicker extends SampleView { class _BlackoutDatePickerState extends SampleViewState { _BlackoutDatePickerState(); - List _blackoutDates; - Orientation _deviceOrientation; + late List _blackoutDates; + late Orientation _deviceOrientation; @override void initState() { @@ -55,10 +55,10 @@ class _BlackoutDatePickerState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget cardView = Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 60, 30, 10) : const EdgeInsets.all(30), child: Container( @@ -73,11 +73,11 @@ class _BlackoutDatePickerState extends SampleViewState { backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), + : const Color(0x00171a21), body: Column(children: [ Expanded( - flex: model.isWeb ? 9 : 8, - child: model.isWeb + flex: model.isWebFullView ? 9 : 8, + child: model.isWebFullView ? Center( child: Container(width: 400, height: 600, child: cardView)) @@ -88,7 +88,7 @@ class _BlackoutDatePickerState extends SampleViewState { ) ])), Expanded( - flex: model.isWeb + flex: model.isWebFullView ? 1 : model.isMobileResolution && _deviceOrientation == Orientation.landscape @@ -106,7 +106,7 @@ class _BlackoutDatePickerState extends SampleViewState { color: Colors.red, decoration: TextDecoration.lineThrough)), monthViewSettings: DateRangePickerMonthViewSettings( showTrailingAndLeadingDates: true, blackoutDates: _blackoutDates), - showNavigationArrow: model.isWeb, + showNavigationArrow: model.isWebFullView, ); } } diff --git a/lib/samples/date_picker/customized_date_picker.dart b/lib/samples/date_picker/customized_date_picker.dart index 0a20ba29..2644cc28 100644 --- a/lib/samples/date_picker/customized_date_picker.dart +++ b/lib/samples/date_picker/customized_date_picker.dart @@ -22,8 +22,8 @@ class CustomizedDatePicker extends SampleView { class _CustomizedDatePickerState extends SampleViewState { _CustomizedDatePickerState(); - List _specialDates; - Orientation _deviceOrientation; + late List _specialDates; + late Orientation _deviceOrientation; @override void initState() { @@ -57,10 +57,10 @@ class _CustomizedDatePickerState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final Widget _datePicker = Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 60, 30, 0) : const EdgeInsets.all(30), child: Container( @@ -72,11 +72,11 @@ class _CustomizedDatePickerState extends SampleViewState { backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), + : const Color(0x00171a21), body: Column(children: [ Expanded( - flex: model.isWeb ? 9 : 8, - child: model.isWeb + flex: model.isWebFullView ? 9 : 8, + child: model.isWebFullView ? Center( child: Container(width: 400, height: 600, child: _datePicker)) @@ -84,7 +84,7 @@ class _CustomizedDatePickerState extends SampleViewState { Container(height: 450, child: _datePicker) ])), Expanded( - flex: model.isWeb + flex: model.isWebFullView ? 1 : model.isMobileResolution && _deviceOrientation == Orientation.landscape @@ -97,7 +97,7 @@ class _CustomizedDatePickerState extends SampleViewState { /// Returns the date range picker based on the properties passed SfDateRangePicker _getCustomizedDatePicker( - [List specialDates, ThemeData theme]) { + List specialDates, ThemeData theme) { final bool isDark = theme != null && theme.brightness != null && theme.brightness == Brightness.dark; @@ -187,16 +187,16 @@ class _MonthCellDecoration extends Decoration { const _MonthCellDecoration( {this.borderColor, this.backgroundColor, - this.showIndicator, + required this.showIndicator, this.indicatorColor}); - final Color borderColor; - final Color backgroundColor; + final Color? borderColor; + final Color? backgroundColor; final bool showIndicator; - final Color indicatorColor; + final Color? indicatorColor; @override - BoxPainter createBoxPainter([VoidCallback onChanged]) { + BoxPainter createBoxPainter([VoidCallback? onChanged]) { return _MonthCellDecorationPainter( borderColor: borderColor, backgroundColor: backgroundColor, @@ -210,34 +210,34 @@ class _MonthCellDecorationPainter extends BoxPainter { _MonthCellDecorationPainter( {this.borderColor, this.backgroundColor, - this.showIndicator, + required this.showIndicator, this.indicatorColor}); - final Color borderColor; - final Color backgroundColor; + final Color? borderColor; + final Color? backgroundColor; final bool showIndicator; - final Color indicatorColor; + final Color? indicatorColor; @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { - final Rect bounds = offset & configuration.size; + final Rect bounds = offset & configuration.size!; _drawDecoration(canvas, bounds); } void _drawDecoration(Canvas canvas, Rect bounds) { - final Paint paint = Paint()..color = backgroundColor; + final Paint paint = Paint()..color = backgroundColor!; canvas.drawRRect( RRect.fromRectAndRadius(bounds, const Radius.circular(5)), paint); paint.style = PaintingStyle.stroke; paint.strokeWidth = 1; if (borderColor != null) { - paint.color = borderColor; + paint.color = borderColor!; canvas.drawRRect( RRect.fromRectAndRadius(bounds, const Radius.circular(5)), paint); } if (showIndicator) { - paint.color = indicatorColor; + paint.color = indicatorColor!; paint.style = PaintingStyle.fill; canvas.drawCircle(Offset(bounds.right - 6, bounds.top + 6), 2.5, paint); } diff --git a/lib/samples/date_picker/date_picker_getting_started.dart b/lib/samples/date_picker/date_picker_getting_started.dart index 91c1703f..3e2141ab 100644 --- a/lib/samples/date_picker/date_picker_getting_started.dart +++ b/lib/samples/date_picker/date_picker_getting_started.dart @@ -24,16 +24,18 @@ class GettingStartedDatePicker extends SampleView { class _GettingStartedDatePickerState extends SampleViewState { _GettingStartedDatePickerState(); - DateRangePickerController _controller; - DateRangePickerSelectionMode _selectionMode; - bool _showTrailingAndLeadingDates; - bool _enablePastDates; - bool _enableSwipingSelection; - bool _enableViewNavigation; - bool _isWeb; - Orientation _deviceOrientation; + final DateRangePickerController _controller = DateRangePickerController(); + DateRangePickerSelectionMode _selectionMode = + DateRangePickerSelectionMode.range; + bool _showTrailingAndLeadingDates = true; + bool _enablePastDates = true; + bool _enableSwipingSelection = true; + bool _enableViewNavigation = true; + bool _showActionButtons = true; + bool _isWeb = false; + late Orientation _deviceOrientation; - String _selectionModeString; + String _selectionModeString = 'Range'; final List _selectionModeList = [ 'Single', 'Multiple', @@ -41,7 +43,7 @@ class _GettingStartedDatePickerState extends SampleViewState { 'Multi Range', ].toList(); - String _viewModeString; + String _viewModeString = 'Month'; final List _viewModeList = [ 'Month', 'Year', @@ -51,14 +53,6 @@ class _GettingStartedDatePickerState extends SampleViewState { @override void initState() { - _controller = DateRangePickerController(); - _selectionMode = DateRangePickerSelectionMode.range; - _showTrailingAndLeadingDates = true; - _enablePastDates = true; - _enableSwipingSelection = true; - _enableViewNavigation = true; - _selectionModeString = 'Range'; - _viewModeString = 'Month'; _controller.view = DateRangePickerView.month; _controller.displayDate = DateTime.now(); _controller.selectedDate = DateTime.now(); @@ -80,7 +74,6 @@ class _GettingStartedDatePickerState extends SampleViewState { PickerDateRange(DateTime.now().add(const Duration(days: 22)), DateTime.now().add(const Duration(days: 27))) ]; - _isWeb = false; super.initState(); } @@ -109,13 +102,13 @@ class _GettingStartedDatePickerState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final bool _enableMultiView = _isWeb && (_selectionMode == DateRangePickerSelectionMode.range || _selectionMode == DateRangePickerSelectionMode.multiRange); final Widget cardView = Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 60, 30, 10) : const EdgeInsets.all(30), child: Container( @@ -131,19 +124,21 @@ class _GettingStartedDatePickerState extends SampleViewState { _enablePastDates, _enableSwipingSelection, _enableViewNavigation, + _showActionButtons, DateTime.now().subtract(const Duration(days: 200)), DateTime.now().add(const Duration(days: 200)), - _enableMultiView)), + _enableMultiView, + context)), )); return Scaffold( backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), + : const Color(0x00171a21), body: Column(children: [ Expanded( - flex: model.isWeb ? 9 : 8, - child: model.isWeb + flex: model.isWebFullView ? 9 : 8, + child: model.isWebFullView ? Center( child: Container( width: !_enableMultiView ? 400 : 700, @@ -156,7 +151,7 @@ class _GettingStartedDatePickerState extends SampleViewState { ) ])), Expanded( - flex: model.isWeb + flex: model.isWebFullView ? 1 : model.isMobileResolution && _deviceOrientation == Orientation.landscape @@ -216,6 +211,8 @@ class _GettingStartedDatePickerState extends SampleViewState { _enableSwipingSelection = value; } else if (property == 'EnableViewNavigation') { _enableViewNavigation = value; + } else if (property == 'ShowActionButtons') { + _showActionButtons = value; } setState(() { /// update the bool value changes @@ -223,10 +220,10 @@ class _GettingStartedDatePickerState extends SampleViewState { } @override - Widget buildSettings([BuildContext context]) { + Widget buildSettings(BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { - List propertyOptions = []; + final List propertyOptions = []; propertyOptions.add(Container( height: 50, child: Row( @@ -312,9 +309,45 @@ class _GettingStartedDatePickerState extends SampleViewState { child: Theme( data: model.themeData.copyWith( canvasColor: model.bottomSheetBackgroundColor), - child: _DateRangePickerOption( - _onDisplayDateChanged, _controller.displayDate, model, - displayDate: _controller.displayDate)), + child: _DateRangePickerOption(_onDisplayDateChanged, + _controller.displayDate!, model, + displayDate: _controller.displayDate!)), + )) + ], + ), + )); + propertyOptions.add(Container( + height: 50, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 6, + child: Text('Show action buttons', + style: TextStyle(fontSize: 16.0, color: model.textColor))), + Expanded( + flex: 4, + child: Container( + padding: const EdgeInsets.all(0), + child: Theme( + data: Theme.of(context).copyWith( + canvasColor: model.bottomSheetBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showActionButtons, + onChanged: (dynamic value) { + setState(() { + onBoolValueChange('ShowActionButtons', value); + stateSetter(() {}); + }); + }, + activeColor: model.backgroundColor, + ))), + ), )) ], ), @@ -464,7 +497,7 @@ class _GettingStartedDatePickerState extends SampleViewState { )); return Padding( padding: const EdgeInsets.fromLTRB(15, 10, 0, 5), - child: model.isWeb + child: model.isWebFullView ? Column( children: propertyOptions, ) @@ -488,7 +521,7 @@ class _GettingStartedDatePickerState extends SampleViewState { /// property for the date range picker, in the property window. class _DateRangePickerOption extends StatefulWidget { const _DateRangePickerOption(this.selectionChanged, this.date, this.model, - {this.displayDate}); + {required this.displayDate}); final DateRangePickerSelectionChangedCallback selectionChanged; final DateTime date; @@ -502,7 +535,7 @@ class _DateRangePickerOption extends StatefulWidget { } class _DateRangePickerOptionState extends State<_DateRangePickerOption> { - DateTime _date; + late DateTime _date; @override void initState() { @@ -528,57 +561,78 @@ class _DateRangePickerOptionState extends State<_DateRangePickerOption> { return Container( color: Colors.transparent, child: GestureDetector( - child: Text(DateFormat('dd-MM-yyyy').format(_date), - style: TextStyle( - fontSize: 15, - color: theme.textTheme.subtitle2.color, - fontWeight: FontWeight.w600)), - onTap: () async { - final DateTime result = await showDialog( - context: context, - builder: (BuildContext context) { - return Theme( - data: theme, - child: DateRangePicker( - _date, - null, - minDate: DateTime.now() - .subtract(const Duration(days: 200)), - maxDate: - DateTime.now().add(const Duration(days: 200)), - displayDate: _date, - model: widget.model, - )); - }); + onTap: () async { + final DateTime? result = await showDialog( + context: context, + builder: (BuildContext context) { + return Theme( + data: theme, + child: DateRangePicker( + _date, + null, + minDate: + DateTime.now().subtract(const Duration(days: 200)), + maxDate: DateTime.now().add(const Duration(days: 200)), + displayDate: _date, + model: widget.model, + )); + }); - if (result != null) { - _onSelectionChanged(result); - } - })); + if (result != null) { + _onSelectionChanged(result); + } + }, + child: Text(DateFormat('MM-dd-yyyy').format(_date), + style: TextStyle( + fontSize: 15, + color: theme.textTheme.subtitle2?.color, + fontWeight: FontWeight.w600)), + )); } } /// Returns the date range picker based on the properties passed SfDateRangePicker _getGettingStartedDatePicker( - [DateRangePickerController controller, + DateRangePickerController controller, DateRangePickerSelectionMode mode, bool showLeading, bool enablePastDates, bool enableSwipingSelection, bool enableViewNavigation, + bool showActionButtons, DateTime minDate, DateTime maxDate, - bool enableMultiView]) { + bool enableMultiView, + BuildContext context) { return SfDateRangePicker( enablePastDates: enablePastDates, minDate: minDate, maxDate: maxDate, enableMultiView: enableMultiView, allowViewNavigation: enableViewNavigation, + showActionButtons: showActionButtons, selectionMode: mode, controller: controller, + headerStyle: DateRangePickerHeaderStyle( + textAlign: enableMultiView ? TextAlign.center : TextAlign.left), + onCancel: () { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text( + 'Selection Cancelled', + ), + duration: Duration(milliseconds: 200), + )); + }, + onSubmit: (Object value) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text( + 'Selection Confirmed', + ), + duration: Duration(milliseconds: 200), + )); + }, monthViewSettings: DateRangePickerMonthViewSettings( enableSwipeSelection: enableSwipingSelection, - showTrailingAndLeadingDates: showLeading ?? false), + showTrailingAndLeadingDates: showLeading), ); } diff --git a/lib/samples/date_picker/hijri_calendar.dart b/lib/samples/date_picker/hijri_calendar.dart index 9d7262c0..ab6b5047 100644 --- a/lib/samples/date_picker/hijri_calendar.dart +++ b/lib/samples/date_picker/hijri_calendar.dart @@ -25,15 +25,17 @@ class HijriDatePicker extends SampleView { class _HijriDatePickerState extends SampleViewState { _HijriDatePickerState(); - HijriDatePickerController _controller; - DateRangePickerSelectionMode _selectionMode; - bool _enablePastDates; - bool _enableSwipingSelection; - bool _enableViewNavigation; - bool _isWeb; - Orientation _deviceOrientation; + final HijriDatePickerController _controller = HijriDatePickerController(); + DateRangePickerSelectionMode _selectionMode = + DateRangePickerSelectionMode.range; + bool _enablePastDates = true; + bool _enableSwipingSelection = true; + bool _enableViewNavigation = true; + bool _showActionButtons = true; + bool _isWeb = false; + late Orientation _deviceOrientation; - String _selectionModeString; + String _selectionModeString = 'Range'; final List _selectionModeList = [ 'Single', 'Multiple', @@ -41,7 +43,7 @@ class _HijriDatePickerState extends SampleViewState { 'Multi Range', ].toList(); - String _viewModeString; + String _viewModeString = 'Month'; final List _viewModeList = [ 'Month', 'Year', @@ -50,13 +52,6 @@ class _HijriDatePickerState extends SampleViewState { @override void initState() { - _controller = HijriDatePickerController(); - _selectionMode = DateRangePickerSelectionMode.range; - _enablePastDates = true; - _enableSwipingSelection = true; - _enableViewNavigation = true; - _selectionModeString = 'Range'; - _viewModeString = 'Month'; _controller.view = HijriDatePickerView.month; _controller.displayDate = HijriDateTime.now(); _controller.selectedDate = HijriDateTime.now(); @@ -78,7 +73,6 @@ class _HijriDatePickerState extends SampleViewState { HijriDateRange(HijriDateTime.now().add(const Duration(days: 22)), HijriDateTime.now().add(const Duration(days: 27))) ]; - _isWeb = false; super.initState(); } @@ -107,13 +101,13 @@ class _HijriDatePickerState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { final bool enableMultiView = _isWeb && (_selectionMode == DateRangePickerSelectionMode.range || _selectionMode == DateRangePickerSelectionMode.multiRange); final Widget cardView = Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 60, 30, 10) : const EdgeInsets.all(30), child: Container( @@ -128,19 +122,21 @@ class _HijriDatePickerState extends SampleViewState { _enablePastDates, _enableSwipingSelection, _enableViewNavigation, + _showActionButtons, HijriDateTime.now().subtract(const Duration(days: 200)), HijriDateTime.now().add(const Duration(days: 200)), - enableMultiView)), + enableMultiView, + context)), )); return Scaffold( backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), + : const Color(0x00171a21), body: Column(children: [ Expanded( - flex: model.isWeb ? 9 : 8, - child: model.isWeb + flex: model.isWebFullView ? 9 : 8, + child: model.isWebFullView ? Center( child: Container( width: !enableMultiView ? 400 : 700, @@ -153,7 +149,7 @@ class _HijriDatePickerState extends SampleViewState { ) ])), Expanded( - flex: model.isWeb + flex: model.isWebFullView ? 1 : model.isMobileResolution && _deviceOrientation == Orientation.landscape @@ -209,6 +205,8 @@ class _HijriDatePickerState extends SampleViewState { _enableSwipingSelection = value; } else if (property == 'EnableViewNavigation') { _enableViewNavigation = value; + } else if (property == 'ShowActionButtons') { + _showActionButtons = value; } setState(() { @@ -217,10 +215,10 @@ class _HijriDatePickerState extends SampleViewState { } @override - Widget buildSettings([BuildContext context]) { + Widget buildSettings(BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { - List propertyOptions = []; + final List propertyOptions = []; propertyOptions.add(Container( height: 50, child: Row( @@ -308,14 +306,50 @@ class _HijriDatePickerState extends SampleViewState { canvasColor: model.bottomSheetBackgroundColor), child: _DateRangePickerOption( _onDisplayDateChanged, - _controller.displayDate, + _controller.displayDate!, model, - displayDate: _controller.displayDate, + displayDate: _controller.displayDate!, )), )) ], ), )); + propertyOptions.add(Container( + height: 50, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 6, + child: Text('Show action buttons', + style: TextStyle(fontSize: 16.0, color: model.textColor))), + Expanded( + flex: 4, + child: Container( + padding: const EdgeInsets.all(0), + child: Theme( + data: Theme.of(context).copyWith( + canvasColor: model.bottomSheetBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showActionButtons, + onChanged: (bool value) { + setState(() { + onBoolValueChange('ShowActionButtons', value); + stateSetter(() {}); + }); + }, + activeColor: model.backgroundColor, + ))), + ), + )) + ], + ), + )); propertyOptions.add(Container( height: 50, child: Row( @@ -427,7 +461,7 @@ class _HijriDatePickerState extends SampleViewState { return Padding( padding: const EdgeInsets.fromLTRB(15, 10, 0, 5), - child: model.isWeb + child: model.isWebFullView ? Column( children: propertyOptions, ) @@ -450,7 +484,7 @@ class _HijriDatePickerState extends SampleViewState { /// property for the date range picker, in the property window. class _DateRangePickerOption extends StatefulWidget { const _DateRangePickerOption(this.selectionChanged, this.date, this.model, - {this.displayDate}); + {required this.displayDate}); final DateRangePickerSelectionChangedCallback selectionChanged; final HijriDateTime date; @@ -464,7 +498,7 @@ class _DateRangePickerOption extends StatefulWidget { } class _DateRangePickerOptionState extends State<_DateRangePickerOption> { - HijriDateTime _date; + late HijriDateTime _date; @override void initState() { @@ -490,18 +524,8 @@ class _DateRangePickerOptionState extends State<_DateRangePickerOption> { return Container( color: Colors.transparent, child: GestureDetector( - child: Text( - _date.day.toString() + - '-' + - _date.month.toString() + - '-' + - _date.year.toString(), - style: TextStyle( - fontSize: 15, - color: _theme.textTheme.subtitle2.color, - fontWeight: FontWeight.w600)), onTap: () async { - final HijriDateTime result = await showDialog( + final HijriDateTime? result = await showDialog( context: context, builder: (BuildContext context) { return Theme( @@ -521,28 +545,59 @@ class _DateRangePickerOptionState extends State<_DateRangePickerOption> { if (result != null) { _onSelectionChanged(result); } - })); + }, + child: Text( + _date.day.toString() + + '-' + + _date.month.toString() + + '-' + + _date.year.toString(), + style: TextStyle( + fontSize: 15, + color: _theme.textTheme.subtitle2?.color, + fontWeight: FontWeight.w600)))); } } /// Returns the date range picker based on the properties passed SfHijriDateRangePicker _getGettingStartedDatePicker( - [HijriDatePickerController controller, + HijriDatePickerController controller, DateRangePickerSelectionMode mode, bool enablePastDates, bool _enableSwipingSelection, bool _enableViewNavigation, + bool showActionButtons, HijriDateTime minDate, HijriDateTime maxDate, - bool enableMultiView]) { + bool enableMultiView, + BuildContext context) { return SfHijriDateRangePicker( enablePastDates: enablePastDates, minDate: minDate, maxDate: maxDate, enableMultiView: enableMultiView, allowViewNavigation: _enableViewNavigation, + showActionButtons: showActionButtons, selectionMode: mode, controller: controller, + headerStyle: DateRangePickerHeaderStyle( + textAlign: enableMultiView ? TextAlign.center : TextAlign.left), + onCancel: () { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text( + 'Selection Cancelled', + ), + duration: Duration(milliseconds: 200), + )); + }, + onSubmit: (Object value) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text( + 'Selection Confirmed', + ), + duration: Duration(milliseconds: 200), + )); + }, monthViewSettings: HijriDatePickerMonthViewSettings( enableSwipeSelection: _enableSwipingSelection), ); diff --git a/lib/samples/date_picker/popup_picker.dart b/lib/samples/date_picker/popup_picker.dart index 2268d5a6..498eb423 100644 --- a/lib/samples/date_picker/popup_picker.dart +++ b/lib/samples/date_picker/popup_picker.dart @@ -26,17 +26,9 @@ class _PopUpDatePickerState extends SampleViewState with SingleTickerProviderStateMixin { _PopUpDatePickerState(); - DateTime _startDate; - DateTime _endDate; - int _value; - - @override - void initState() { - _startDate = DateTime.now(); - _endDate = DateTime.now().add(const Duration(days: 1)); - _value = 1; - super.initState(); - } + DateTime _startDate = DateTime.now(); + DateTime _endDate = DateTime.now().add(const Duration(days: 1)); + int _value = 1; /// Update the selected date for the date range picker based on the date selected, /// when the trip mode set one way. @@ -55,9 +47,8 @@ class _PopUpDatePickerState extends SampleViewState /// Update the selected range based on the range selected in the pop up editor, /// when the trip mode set as round trip. void _onSelectedRangeChanged(_picker.PickerDateRange dateRange) { - final DateTime startDateValue = dateRange.startDate; - DateTime endDateValue = dateRange.endDate; - endDateValue ??= startDateValue; + final DateTime startDateValue = dateRange.startDate!; + final DateTime endDateValue = dateRange.endDate ?? startDateValue; setState(() { if (startDateValue.isAfter(endDateValue)) { _startDate = endDateValue; @@ -72,13 +63,13 @@ class _PopUpDatePickerState extends SampleViewState Widget _getBooking() { return Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 20, 30, 5) : const EdgeInsets.all(30), child: Container( color: model.cardThemeColor, child: ListView( - padding: model.isWeb + padding: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 10, 10, 5) : const EdgeInsets.fromLTRB(30, 20, 10, 10), children: [ @@ -231,7 +222,7 @@ class _PopUpDatePickerState extends SampleViewState padding: EdgeInsets.all(5), onPressed: () async { if (_value == 0) { - final DateTime date = + final DateTime? date = await showDialog( context: context, builder: (BuildContext context) { @@ -245,7 +236,7 @@ class _PopUpDatePickerState extends SampleViewState _onSelectedDateChanged(date); } } else { - final _picker.PickerDateRange range = + final _picker.PickerDateRange? range = await showDialog( context: context, builder: (BuildContext context) { @@ -413,7 +404,8 @@ class _PopUpDatePickerState extends SampleViewState splashColor: Colors.grey.withOpacity(0.12), hoverColor: Colors.grey.withOpacity(0.04), onPressed: () { - Scaffold.of(context).showSnackBar(const SnackBar( + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar( content: Text( 'Searching...', ), @@ -435,13 +427,13 @@ class _PopUpDatePickerState extends SampleViewState } @override - Widget build([BuildContext context]) { + Widget build(BuildContext context) { return Scaffold( backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), - body: model.isWeb + : const Color(0x00171a21), + body: model.isWebFullView ? Center( child: Container(width: 400, height: 380, child: _getBooking())) : Container( @@ -462,7 +454,7 @@ _picker.SfDateRangePicker getPopUpDatePicker() { class DateRangePicker extends StatefulWidget { /// Creates Date range picker const DateRangePicker(this.date, this.range, - {this.minDate, this.maxDate, this.displayDate, this.model}); + {this.minDate, this.maxDate, this.displayDate, required this.model}); /// Holds date value final dynamic date; @@ -492,8 +484,8 @@ class _DateRangePickerState extends State { dynamic _date; dynamic _controller; dynamic _range; - bool _isWeb, _isHijri; - SfLocalizations _localizations; + late bool _isWeb, _isHijri; + late SfLocalizations _localizations; @override void initState() { @@ -534,36 +526,6 @@ class _DateRangePickerState extends State { @override Widget build(BuildContext context) { - final Widget footerWidget = ButtonBarTheme( - data: ButtonBarTheme.of(context), - child: ButtonBar( - children: [ - FlatButton( - splashColor: widget.model.backgroundColor - .withOpacity(widget.model.backgroundColor.opacity * 0.2), - child: Text( - 'Cancel', - style: TextStyle(color: widget.model.backgroundColor), - ), - onPressed: () => Navigator.pop(context, null), - ), - FlatButton( - splashColor: widget.model.backgroundColor - .withOpacity(widget.model.backgroundColor.opacity * 0.2), - child: Text( - 'OK', - style: TextStyle(color: widget.model.backgroundColor), - ), - onPressed: () { - (_range != null) - ? Navigator.pop(context, _range) - : Navigator.pop(context, _date); - }, - ), - ], - ), - ); - final Widget selectedDateWidget = Container( color: Colors.transparent, padding: const EdgeInsets.symmetric(vertical: 16.0), @@ -658,6 +620,8 @@ class _DateRangePickerState extends State { selectionMode: _range == null ? _picker.DateRangePickerSelectionMode.single : _picker.DateRangePickerSelectionMode.range, + showActionButtons: true, + onCancel: () => Navigator.pop(context, null), minDate: widget.minDate, maxDate: widget.maxDate, todayHighlightColor: Colors.transparent, @@ -665,6 +629,13 @@ class _DateRangePickerState extends State { textAlign: TextAlign.center, textStyle: TextStyle(color: widget.model.backgroundColor, fontSize: 15)), + onSubmit: (Object value) { + if (_range == null) { + Navigator.pop(context, _date); + } else { + Navigator.pop(context, _range); + } + }, onSelectionChanged: (_picker.DateRangePickerSelectionChangedArgs details) { setState(() { @@ -681,6 +652,8 @@ class _DateRangePickerState extends State { controller: _controller, initialDisplayDate: widget.displayDate, showNavigationArrow: true, + showActionButtons: true, + onCancel: () => Navigator.pop(context, null), enableMultiView: _range != null && _isWeb, selectionMode: _range == null ? _picker.DateRangePickerSelectionMode.single @@ -692,6 +665,13 @@ class _DateRangePickerState extends State { textAlign: TextAlign.center, textStyle: TextStyle(color: widget.model.backgroundColor, fontSize: 15)), + onSubmit: (Object value) { + if (_range == null) { + Navigator.pop(context, _date); + } else { + Navigator.pop(context, _range); + } + }, onSelectionChanged: (_picker.DateRangePickerSelectionChangedArgs details) { setState(() { @@ -726,7 +706,6 @@ class _DateRangePickerState extends State { padding: const EdgeInsets.symmetric( vertical: 0, horizontal: 5), child: pickerWidget)), - footerWidget, ], ), ))); diff --git a/lib/samples/date_picker/vertical_calendar.dart b/lib/samples/date_picker/vertical_calendar.dart index af12b505..ae20768c 100644 --- a/lib/samples/date_picker/vertical_calendar.dart +++ b/lib/samples/date_picker/vertical_calendar.dart @@ -19,10 +19,14 @@ class VerticalCalendar extends SampleView { class _VerticalCalendarPickerState extends SampleViewState { _VerticalCalendarPickerState(); - @override - void initState() { - super.initState(); - } + DateRangePickerNavigationMode _navigationMode = + DateRangePickerNavigationMode.scroll; + String _navigationModeString = 'Scroll'; + final List _navigationModeList = [ + 'None', + 'Snap', + 'Scroll', + ].toList(); @override void didChangeDependencies() { @@ -30,7 +34,59 @@ class _VerticalCalendarPickerState extends SampleViewState { } @override - Widget build([BuildContext context]) { + Widget buildSettings(BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + final List propertyOptions = []; + propertyOptions.add(Container( + height: 50, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 6, + child: Text('Navigation mode', + style: TextStyle(fontSize: 16.0, color: model.textColor))), + Expanded( + flex: 4, + child: Container( + padding: const EdgeInsets.all(0), + alignment: Alignment.bottomLeft, + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _navigationModeString, + items: _navigationModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Scroll', + child: Text('$value', + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (dynamic value) { + onNavigationModeChange(value); + stateSetter(() {}); + }), + ), + ) + ], + ), + )); + return Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 0, 5), + child: model.isWebFullView + ? Column( + children: propertyOptions, + ) + : ListView( + children: propertyOptions, + ), + ); + }); + } + + @override + Widget build(BuildContext context) { final Widget calendar = Container( height: 550, padding: const EdgeInsets.fromLTRB(5, 0, 5, 5), @@ -42,19 +98,19 @@ class _VerticalCalendarPickerState extends SampleViewState { ); final Widget _cardView = Card( elevation: 10, - margin: model.isWeb + margin: model.isWebFullView ? const EdgeInsets.fromLTRB(30, 20, 30, 10) : const EdgeInsets.fromLTRB(30, 30, 30, 10), - child: model.isWeb ? ListView(children: [calendar]) : calendar); + child: model.isWebFullView ? ListView(children: [calendar]) : calendar); return Scaffold( backgroundColor: model.themeData == null || model.themeData.brightness == Brightness.light ? null - : const Color(0x171A21), + : const Color(0x00171a21), body: Column(children: [ Expanded( flex: 9, - child: model.isWeb + child: model.isWebFullView ? Center( child: @@ -71,13 +127,33 @@ class _VerticalCalendarPickerState extends SampleViewState { ])); } + void onNavigationModeChange(String value) { + _navigationModeString = value; + if (value == 'None') { + _navigationMode = DateRangePickerNavigationMode.none; + } else if (value == 'Snap') { + _navigationMode = DateRangePickerNavigationMode.snap; + } else if (value == 'Scroll') { + _navigationMode = DateRangePickerNavigationMode.scroll; + } + + setState(() { + /// Update the date range picker navigation mode changes. + }); + } + /// Returns the date range picker widget based on the properties passed. SfDateRangePicker _getVerticalCalendar() { return SfDateRangePicker( enableMultiView: true, + headerStyle: + DateRangePickerHeaderStyle(backgroundColor: model.cardThemeColor), navigationDirection: DateRangePickerNavigationDirection.vertical, selectionMode: DateRangePickerSelectionMode.multiRange, - showNavigationArrow: model.isWeb, + monthViewSettings: + DateRangePickerMonthViewSettings(enableSwipeSelection: false), + showNavigationArrow: model.isWebFullView, + navigationMode: _navigationMode, ); } } diff --git a/lib/samples/gauge/animation/radial_bounce.dart b/lib/samples/gauge/animation/radial_bounce.dart index 96505535..7c49dbff 100644 --- a/lib/samples/gauge/animation/radial_bounce.dart +++ b/lib/samples/gauge/animation/radial_bounce.dart @@ -21,15 +21,15 @@ class _RadialBounceOutExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialBounceOutExample(); + return _buildRadialBounceOutExample(); } /// Returns the pointer bounce out animation gauge - SfRadialGauge _getRadialBounceOutExample() { + SfRadialGauge _buildRadialBounceOutExample() { return SfRadialGauge( axes: [ RadialAxis( - radiusFactor: model.isWeb ? 0.85 : 0.98, + radiusFactor: model.isWebFullView ? 0.85 : 0.98, startAngle: 90, endAngle: 330, minimum: -8, diff --git a/lib/samples/gauge/animation/radial_ease_animation.dart b/lib/samples/gauge/animation/radial_ease_animation.dart index 542371f7..d99f0b73 100644 --- a/lib/samples/gauge/animation/radial_ease_animation.dart +++ b/lib/samples/gauge/animation/radial_ease_animation.dart @@ -21,11 +21,11 @@ class _RadialEaseExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialEaseExample(); + return _buildRadialEaseExample(); } /// Return the gauge pointer ease animation gauge - SfRadialGauge _getRadialEaseExample() { + SfRadialGauge _buildRadialEaseExample() { return SfRadialGauge( axes: [ RadialAxis( @@ -33,7 +33,7 @@ class _RadialEaseExampleState extends SampleViewState { endAngle: 360, showLabels: false, showTicks: false, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, axisLineStyle: AxisLineStyle( thicknessUnit: GaugeSizeUnit.factor, thickness: isCardView ? 0.07 : 0.1)), @@ -44,7 +44,7 @@ class _RadialEaseExampleState extends SampleViewState { labelFormat: '{value}M', onLabelCreated: _handleLabelCreated, showAxisLine: false, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, minimum: 0, maximum: 15, axisLabelStyle: GaugeTextStyle( @@ -78,32 +78,28 @@ class _RadialEaseExampleState extends SampleViewState { enableAnimation: true, sizeUnit: GaugeSizeUnit.factor, animationType: AnimationType.ease, - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFFFB397), Color(0xFFF46AA0)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFFFB397), Color(0xFFF46AA0)], + stops: [0.25, 0.75]), ), - model.isWeb - ? MarkerPointer( - value: 11.5, - markerType: MarkerType.circle, - enableAnimation: true, - animationType: AnimationType.ease, - color: Colors.blue, - markerHeight: isCardView ? 30 : 40, - markerOffset: 4, - markerWidth: isCardView ? 30 : 40) - : MarkerPointer( - value: 11.5, - markerType: MarkerType.image, - enableAnimation: true, - animationType: AnimationType.ease, - imageUrl: 'images/ball_progressbar.png', - markerHeight: isCardView ? 30 : 40, - markerOffset: 4, - markerWidth: isCardView ? 30 : 40) + MarkerPointer( + value: 11.5, + markerType: MarkerType.image, + enableAnimation: true, + animationType: AnimationType.ease, + imageUrl: 'images/ball_progressbar.png', + markerHeight: isCardView + ? 30 + : model.isWebFullView + ? 45 + : 40, + markerOffset: 4, + markerWidth: isCardView + ? 30 + : model.isWebFullView + ? 45 + : 40, + ) ]) ], ); diff --git a/lib/samples/gauge/animation/radial_ease_incric.dart b/lib/samples/gauge/animation/radial_ease_incric.dart index 6f3bdd49..ffb3a81e 100644 --- a/lib/samples/gauge/animation/radial_ease_incric.dart +++ b/lib/samples/gauge/animation/radial_ease_incric.dart @@ -22,15 +22,15 @@ class _RadialEaseInCircExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialEaseInCircExample(); + return _buildRadialEaseInCircExample(); } /// Returns the pointer ease in circle animation gauge - SfRadialGauge _getRadialEaseInCircExample() { + SfRadialGauge _buildRadialEaseInCircExample() { return SfRadialGauge( axes: [ RadialAxis( - radiusFactor: model.isWeb ? 0.85 : 0.95, + radiusFactor: model.isWebFullView ? 0.85 : 0.95, showAxisLine: false, ticksPosition: ElementsPosition.outside, labelsPosition: ElementsPosition.outside, @@ -53,12 +53,9 @@ class _RadialEaseInCircExampleState extends SampleViewState { pointerOffset: 10, value: 45, animationDuration: 1000, - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFF3B3FF3), Color(0xFF46D0ED)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFF3B3FF3), Color(0xFF46D0ED)], + stops: [0.25, 0.75]), animationType: AnimationType.easeInCirc, enableAnimation: true, color: const Color(0xFFF8B195)) diff --git a/lib/samples/gauge/animation/radial_ease_out.dart b/lib/samples/gauge/animation/radial_ease_out.dart index 36214725..fdd9938f 100644 --- a/lib/samples/gauge/animation/radial_ease_out.dart +++ b/lib/samples/gauge/animation/radial_ease_out.dart @@ -19,13 +19,15 @@ class RadialEaseOutAnimation extends SampleView { class _RadialEaseOutAnimationState extends SampleViewState { _RadialEaseOutAnimationState(); + final Color _darkNeedleColor = const Color(0xFFDCDCDC); + @override Widget build(BuildContext context) { - return _getRadialEaseOutAnimation(); + return _buildRadialEaseOutAnimation(); } /// Returns the pointer ease out animation gauge - SfRadialGauge _getRadialEaseOutAnimation() { + SfRadialGauge _buildRadialEaseOutAnimation() { return SfRadialGauge( axes: [ RadialAxis( @@ -45,18 +47,22 @@ class _RadialEaseOutAnimationState extends SampleViewState { width: 40, color: const Color(0xFF00A8B5), value: 40, - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFD046CA), Color(0xFF6094EA)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFD046CA), Color(0xFF6094EA)], + stops: [0.25, 0.75]), ), NeedlePointer( knobStyle: KnobStyle( - knobRadius: 5, sizeUnit: GaugeSizeUnit.logicalPixel), + color: model.themeData.brightness == Brightness.light + ? null + : _darkNeedleColor, + knobRadius: 5, + sizeUnit: GaugeSizeUnit.logicalPixel), needleEndWidth: 2, needleStartWidth: 2, + needleColor: model.themeData.brightness == Brightness.light + ? null + : _darkNeedleColor, lengthUnit: GaugeSizeUnit.factor, needleLength: 0.98, value: 40, diff --git a/lib/samples/gauge/animation/radial_elastic_out.dart b/lib/samples/gauge/animation/radial_elastic_out.dart index faa840ef..416a8fea 100644 --- a/lib/samples/gauge/animation/radial_elastic_out.dart +++ b/lib/samples/gauge/animation/radial_elastic_out.dart @@ -23,10 +23,10 @@ class _RadialElasticOutAnimationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialElasticOutAnimation(); + return _buildRadialElasticOutAnimation(); } - SfRadialGauge _getRadialElasticOutAnimation() { + SfRadialGauge _buildRadialElasticOutAnimation() { return SfRadialGauge( axes: [ RadialAxis( @@ -42,12 +42,9 @@ class _RadialElasticOutAnimationState extends SampleViewState { minorTicksPerInterval: 4, pointers: [ RangePointer( - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFD481FF), Color(0xFF06F0E0)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFD481FF), Color(0xFF06F0E0)], + stops: [0.25, 0.75]), value: 70, width: 5, animationDuration: 2000, @@ -57,7 +54,8 @@ class _RadialElasticOutAnimationState extends SampleViewState { NeedlePointer( value: 70, needleStartWidth: 0, - needleColor: model.isWeb ? null : const Color(0xFFD481FF), + needleColor: + model.isWebFullView ? null : const Color(0xFFD481FF), lengthUnit: GaugeSizeUnit.factor, needleLength: 1, enableAnimation: true, diff --git a/lib/samples/gauge/animation/radial_linear_animation.dart b/lib/samples/gauge/animation/radial_linear_animation.dart index 00601ab6..918b5f46 100644 --- a/lib/samples/gauge/animation/radial_linear_animation.dart +++ b/lib/samples/gauge/animation/radial_linear_animation.dart @@ -21,11 +21,11 @@ class _RadialLinearAnimationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialLinearAnimation(context); + return _buildRadialLinearAnimation(context); } /// Returns the pointer linear animation gauge - Widget _getRadialLinearAnimation(BuildContext context) { + Widget _buildRadialLinearAnimation(BuildContext context) { return SfRadialGauge( axes: [ RadialAxis( @@ -57,7 +57,9 @@ class _RadialLinearAnimationState extends SampleViewState { animationType: AnimationType.linear, lengthUnit: GaugeSizeUnit.factor, needleLength: 0.8, - needleColor: _linearNeedleColor) + needleColor: model.themeData.brightness == Brightness.light + ? _linearNeedleColor + : _linearNeedleDarkColor), ], axisLineStyle: AxisLineStyle(thickness: 3), tickOffset: 2, @@ -69,5 +71,6 @@ class _RadialLinearAnimationState extends SampleViewState { } final Color _linearNeedleColor = const Color(0xFF355C7D); + final Color _linearNeedleDarkColor = const Color(0xFFDCDCDC); final Color _linearMarkerColor = const Color(0xFFF67280); } diff --git a/lib/samples/gauge/animation/radial_slow_middle.dart b/lib/samples/gauge/animation/radial_slow_middle.dart index 696ac68c..1a8b32f0 100644 --- a/lib/samples/gauge/animation/radial_slow_middle.dart +++ b/lib/samples/gauge/animation/radial_slow_middle.dart @@ -22,15 +22,15 @@ class _RadialSlowMiddleAnimationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialSlowMiddleAnimation(); + return _buildRadialSlowMiddleAnimation(); } /// Returns the pointer slow middle animation gauge - SfRadialGauge _getRadialSlowMiddleAnimation() { + SfRadialGauge _buildRadialSlowMiddleAnimation() { return SfRadialGauge( axes: [ RadialAxis( - radiusFactor: model.isWeb ? 0.85 : 0.95, + radiusFactor: model.isWebFullView ? 0.85 : 0.95, startAngle: 270, endAngle: 270, showAxisLine: false, diff --git a/lib/samples/gauge/annotation/direct_compass.dart b/lib/samples/gauge/annotation/direct_compass.dart index 9b74ac58..a86b2d6e 100644 --- a/lib/samples/gauge/annotation/direct_compass.dart +++ b/lib/samples/gauge/annotation/direct_compass.dart @@ -21,11 +21,11 @@ class _RadialCompassState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialCompass(); + return _buildRadialCompass(); } /// Returns the direction compass gauge using annotation support - SfRadialGauge _getRadialCompass() { + SfRadialGauge _buildRadialCompass() { return SfRadialGauge( axes: [ RadialAxis( diff --git a/lib/samples/gauge/annotation/temparature_tracker.dart b/lib/samples/gauge/annotation/temparature_tracker.dart index ddcf6c90..24f5c66d 100644 --- a/lib/samples/gauge/annotation/temparature_tracker.dart +++ b/lib/samples/gauge/annotation/temparature_tracker.dart @@ -21,16 +21,16 @@ class _RadialImageAnnotationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialImageAnnotation(); + return _buildRadialImageAnnotation(); } /// Returns the image annotation gauge - SfRadialGauge _getRadialImageAnnotation() { + SfRadialGauge _buildRadialImageAnnotation() { return SfRadialGauge( axes: [ RadialAxis( interval: 10, - radiusFactor: model.isWeb ? 0.8 : 0.95, + radiusFactor: model.isWebFullView ? 0.8 : 0.95, startAngle: 0, endAngle: 360, showTicks: false, @@ -42,11 +42,9 @@ class _RadialImageAnnotationState extends SampleViewState { width: 20, color: const Color(0xFFFFCD60), enableAnimation: true, - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFFCE38A), Color(0xFFF38181)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFFCE38A), Color(0xFFF38181)], + stops: [0.25, 0.75]), cornerStyle: CornerStyle.bothCurve) ], annotations: [ diff --git a/lib/samples/gauge/annotation/text_annotation.dart b/lib/samples/gauge/annotation/text_annotation.dart index 448e7b67..6efa54da 100644 --- a/lib/samples/gauge/annotation/text_annotation.dart +++ b/lib/samples/gauge/annotation/text_annotation.dart @@ -21,11 +21,11 @@ class _RadialTextAnnotationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialTextAnnotation(); + return _buildRadialTextAnnotation(); } /// Returns the text annotation gauge - SfRadialGauge _getRadialTextAnnotation() { + SfRadialGauge _buildRadialTextAnnotation() { return SfRadialGauge( axes: [ RadialAxis( @@ -33,18 +33,18 @@ class _RadialTextAnnotationState extends SampleViewState { showLabels: false, startAngle: 180, endAngle: 180, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, axisLineStyle: AxisLineStyle( // Dash array not supported in web thickness: 30, - dashArray: model.isWeb ? null : [8, 10]), + dashArray: [8, 10]), ), RadialAxis( showTicks: false, showLabels: false, startAngle: 180, endAngle: 50, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, annotations: [ GaugeAnnotation( angle: 270, @@ -61,14 +61,11 @@ class _RadialTextAnnotationState extends SampleViewState { ], axisLineStyle: AxisLineStyle( color: const Color(0xFF00A8B5), - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFF06974A), Color(0xFFF2E41F)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFF06974A), Color(0xFFF2E41F)], + stops: [0.25, 0.75]), thickness: 30, - dashArray: model.isWeb ? null : [8, 10])) + dashArray: [8, 10])) ], ); } diff --git a/lib/samples/gauge/axis_feature/custom_labels.dart b/lib/samples/gauge/axis_feature/custom_labels.dart index 788949b8..cff78f6b 100644 --- a/lib/samples/gauge/axis_feature/custom_labels.dart +++ b/lib/samples/gauge/axis_feature/custom_labels.dart @@ -21,11 +21,11 @@ class _GaugeCustomLabelsState extends SampleViewState { @override Widget build(BuildContext context) { - return _getGaugeCustomLabels(context); + return _buildGaugeCustomLabels(context); } /// Returns the custom label axis gauge - SfRadialGauge _getGaugeCustomLabels(BuildContext context) { + SfRadialGauge _buildGaugeCustomLabels(BuildContext context) { final Orientation _orientation = MediaQuery.of(context).orientation; final Brightness _brightness = Theme.of(context).brightness; @@ -34,7 +34,7 @@ class _GaugeCustomLabelsState extends SampleViewState { RadialAxis( startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, minimum: 0, maximum: 80, axisLineStyle: AxisLineStyle( @@ -52,7 +52,7 @@ class _GaugeCustomLabelsState extends SampleViewState { value: 70, lengthUnit: GaugeSizeUnit.factor, needleLength: 0.55, - needleEndWidth: model.isWeb + needleEndWidth: model.isWebFullView ? 18 : isCardView ? 10 @@ -72,7 +72,7 @@ class _GaugeCustomLabelsState extends SampleViewState { ]), needleColor: const Color(0xFFF67280), knobStyle: KnobStyle( - knobRadius: model.isWeb ? 0.098 : 0.09, + knobRadius: model.isWebFullView ? 0.098 : 0.09, sizeUnit: GaugeSizeUnit.factor, color: Colors.white)), NeedlePointer( @@ -92,8 +92,8 @@ class _GaugeCustomLabelsState extends SampleViewState { lengthUnit: GaugeSizeUnit.factor, needleColor: _brightness == Brightness.dark ? const Color(0xFF888888) - : const Color(0xFFFCACACA), - needleEndWidth: model.isWeb + : const Color(0x0ffcacca), + needleEndWidth: model.isWebFullView ? 18 : isCardView ? 10 @@ -101,7 +101,7 @@ class _GaugeCustomLabelsState extends SampleViewState { ? 18 : 10, knobStyle: KnobStyle( - knobRadius: model.isWeb ? 0.098 : 0.09, + knobRadius: model.isWebFullView ? 0.098 : 0.09, sizeUnit: GaugeSizeUnit.factor, color: Colors.white)) ], diff --git a/lib/samples/gauge/axis_feature/custom_scale.dart b/lib/samples/gauge/axis_feature/custom_scale.dart index 49281ca9..b946a475 100644 --- a/lib/samples/gauge/axis_feature/custom_scale.dart +++ b/lib/samples/gauge/axis_feature/custom_scale.dart @@ -21,21 +21,21 @@ class _RadialNonLinearLabelState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialNonLinearLabel(); + return _buildRadialNonLinearLabel(); } /// Returns the non-linear axis label gauge - SfRadialGauge _getRadialNonLinearLabel() { + SfRadialGauge _buildRadialNonLinearLabel() { return SfRadialGauge( enableLoadingAnimation: true, - key: model.isWeb ? UniqueKey() : null, + key: model.isWebFullView ? UniqueKey() : null, animationDuration: 2500, axes: [ RadialAxis( labelOffset: 15, axisLineStyle: AxisLineStyle( thicknessUnit: GaugeSizeUnit.factor, thickness: 0.15), - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, minimum: 0, showTicks: false, maximum: 150, @@ -46,7 +46,7 @@ class _RadialNonLinearLabelState extends SampleViewState { NeedlePointer( enableAnimation: true, gradient: const LinearGradient(colors: [ - Color.fromRGBO(203, 126, 223, 0.1), + Color.fromRGBO(203, 126, 223, 0), Color(0xFFCB7EDF) ], stops: [ 0.25, @@ -69,12 +69,9 @@ class _RadialNonLinearLabelState extends SampleViewState { color: _pointerColor, animationDuration: 1300, animationType: AnimationType.easeOutBack, - // Sweep gradient not supported in web. - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFF9E40DC), Color(0xFFE63B86)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFF9E40DC), Color(0xFFE63B86)], + stops: [0.25, 0.75]), enableAnimation: true) ]) ], @@ -100,7 +97,7 @@ class _CustomAxisRenderer extends RadialAxisRenderer { for (num i = 0; i < 9; i++) { final double _value = _calculateLabelValue(i); final CircularAxisLabel label = CircularAxisLabel( - this.axis.axisLabelStyle, _value.toInt().toString(), i, false); + axis.axisLabelStyle, _value.toInt().toString(), i, false); label.value = _value; _visibleLabels.add(label); } diff --git a/lib/samples/gauge/axis_feature/default_gauge_view.dart b/lib/samples/gauge/axis_feature/default_gauge_view.dart index 7253741f..fab28ca9 100644 --- a/lib/samples/gauge/axis_feature/default_gauge_view.dart +++ b/lib/samples/gauge/axis_feature/default_gauge_view.dart @@ -21,11 +21,11 @@ class _RadialGaugeDefaultState extends SampleViewState { @override Widget build(BuildContext context) { - return _getDefaultRadialGauge(); + return _buildDefaultRadialGauge(); } /// Returns the default axis gauge - SfRadialGauge _getDefaultRadialGauge() { + SfRadialGauge _buildDefaultRadialGauge() { return SfRadialGauge( enableLoadingAnimation: true, axes: [ @@ -40,7 +40,7 @@ class _RadialGaugeDefaultState extends SampleViewState { fontSize: isCardView ? 12 : 14, ), labelOffset: 25, - radiusFactor: model.isWeb ? 0.8 : 0.95, + radiusFactor: model.isWebFullView ? 0.8 : 0.95, pointers: [ NeedlePointer( needleLength: 0.7, diff --git a/lib/samples/gauge/axis_feature/multiple_axis.dart b/lib/samples/gauge/axis_feature/multiple_axis.dart index 2b08852e..5e976dc5 100644 --- a/lib/samples/gauge/axis_feature/multiple_axis.dart +++ b/lib/samples/gauge/axis_feature/multiple_axis.dart @@ -21,11 +21,11 @@ class _MultipleAxisExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialGauge(context); + return _buildRadialGauge(context); } /// Returns the default axis gauge - SfRadialGauge _getRadialGauge(BuildContext context) { + SfRadialGauge _buildRadialGauge(BuildContext context) { return SfRadialGauge(axes: [ RadialAxis( minimum: 32, diff --git a/lib/samples/gauge/axis_feature/radial_label_customization.dart b/lib/samples/gauge/axis_feature/radial_label_customization.dart index ba703f42..6fb4f110 100644 --- a/lib/samples/gauge/axis_feature/radial_label_customization.dart +++ b/lib/samples/gauge/axis_feature/radial_label_customization.dart @@ -22,11 +22,11 @@ class _RadialLabelCustomizationState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialLabelCustomization(); + return _buildRadialLabelCustomization(); } /// Returns the customized axis label gauge - SfRadialGauge _getRadialLabelCustomization() { + SfRadialGauge _buildRadialLabelCustomization() { return SfRadialGauge( axes: [ RadialAxis( diff --git a/lib/samples/gauge/axis_feature/range_colors.dart b/lib/samples/gauge/axis_feature/range_colors.dart index da0bb88c..0af71fa1 100644 --- a/lib/samples/gauge/axis_feature/range_colors.dart +++ b/lib/samples/gauge/axis_feature/range_colors.dart @@ -21,11 +21,11 @@ class _RangeColorForLabelsState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRangeColorForLabels(); + return _buildRangeColorForLabels(); } /// Returns the range color for axis labels gauge - SfRadialGauge _getRangeColorForLabels() { + SfRadialGauge _buildRangeColorForLabels() { return SfRadialGauge( axes: [ RadialAxis( @@ -54,24 +54,24 @@ class _RangeColorForLabelsState extends SampleViewState { color: const Color(0xFFF8B195), sizeUnit: GaugeSizeUnit.factor, rangeOffset: 0.06, - startWidth: model.isWeb ? 0.2 : 0.05, - endWidth: model.isWeb ? 0.2 : 0.25), + startWidth: model.isWebFullView ? 0.2 : 0.05, + endWidth: model.isWebFullView ? 0.2 : 0.25), GaugeRange( startValue: 35, endValue: 70, rangeOffset: 0.06, sizeUnit: GaugeSizeUnit.factor, color: const Color(0xFFC06C84), - startWidth: model.isWeb ? 0.2 : 0.05, - endWidth: model.isWeb ? 0.2 : 0.25), + startWidth: model.isWebFullView ? 0.2 : 0.05, + endWidth: model.isWebFullView ? 0.2 : 0.25), GaugeRange( startValue: 70, endValue: 100, rangeOffset: 0.06, sizeUnit: GaugeSizeUnit.factor, color: const Color(0xFF355C7D), - startWidth: model.isWeb ? 0.2 : 0.05, - endWidth: model.isWeb ? 0.2 : 0.25), + startWidth: model.isWebFullView ? 0.2 : 0.05, + endWidth: model.isWebFullView ? 0.2 : 0.25), ]) ], ); diff --git a/lib/samples/gauge/axis_feature/tick_customization.dart b/lib/samples/gauge/axis_feature/tick_customization.dart index b5c8a0e9..19f18041 100644 --- a/lib/samples/gauge/axis_feature/tick_customization.dart +++ b/lib/samples/gauge/axis_feature/tick_customization.dart @@ -30,7 +30,7 @@ class _RadialTickCustomizationState extends SampleViewState { return SfRadialGauge( axes: [ RadialAxis( - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, showAxisLine: false, onLabelCreated: _handleLabelCreated, startAngle: 270, @@ -42,7 +42,7 @@ class _RadialTickCustomizationState extends SampleViewState { length: 0.15, lengthUnit: GaugeSizeUnit.factor, thickness: 1, - dashArray: model.isWeb ? null : [2, 1]), + dashArray: model.isWebFullView ? null : [2, 1]), minorTicksPerInterval: 4, interval: 10, minorTickStyle: MinorTickStyle( @@ -51,10 +51,10 @@ class _RadialTickCustomizationState extends SampleViewState { lengthUnit: GaugeSizeUnit.factor, /// Dash array not supported in web. - dashArray: model.isWeb ? null : [2, 1]), + dashArray: model.isWebFullView ? null : [2, 1]), pointers: [ NeedlePointer( - enableAnimation: model.isWeb ? false : true, + enableAnimation: model.isWebFullView ? false : true, animationType: AnimationType.ease, animationDuration: 1300, value: 75, diff --git a/lib/samples/gauge/export/export.dart b/lib/samples/gauge/export/export.dart index 1bb5054c..efdc0b97 100644 --- a/lib/samples/gauge/export/export.dart +++ b/lib/samples/gauge/export/export.dart @@ -35,7 +35,7 @@ class _ExportState extends SampleViewState { return Scaffold( key: scaffoldKey, body: Column(children: [ - Expanded(child: _getTemperatureMonitorExample()), + Expanded(child: _buildTemperatureMonitorExample()), Container( padding: EdgeInsets.only(bottom: 10), child: Row( @@ -52,14 +52,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, duration: Duration(milliseconds: 100), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), content: - Text("Gauge has been exported as PNG image"), + Text('Gauge has been exported as PNG image'), )); _renderImage(); }, @@ -77,14 +77,14 @@ class _ExportState extends SampleViewState { alignment: Alignment.center, child: IconButton( onPressed: () { - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, duration: Duration(milliseconds: 2000), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), content: Text( - "Gauge is being exported as PDF document."), + 'Gauge is being exported as PDF document.'), )); _renderPdf(); }, @@ -95,12 +95,12 @@ class _ExportState extends SampleViewState { ])); } - SfRadialGauge _getTemperatureMonitorExample() { - bool isPortrait = + SfRadialGauge _buildTemperatureMonitorExample() { + final bool isPortrait = MediaQuery.of(context).orientation == Orientation.portrait; return SfRadialGauge( key: _key, - backgroundColor: model.currentThemeData.brightness == Brightness.light + backgroundColor: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Color.fromRGBO(33, 33, 33, 1), enableLoadingAnimation: true, @@ -110,9 +110,6 @@ class _ExportState extends SampleViewState { : '\nHigh and low temperatures of London - Sep ‘20', textStyle: TextStyle( fontSize: 20.0, - // color: model.currentThemeData.brightness == Brightness.light - // ? Colors.black - // : Colors.white, fontFamily: 'Segoe UI', fontStyle: FontStyle.normal, ), @@ -124,7 +121,7 @@ class _ExportState extends SampleViewState { minimum: 0, maximum: 30, interval: 5, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, labelOffset: 8, annotations: [ GaugeAnnotation( @@ -171,12 +168,9 @@ class _ExportState extends SampleViewState { ], axisLineStyle: AxisLineStyle( cornerStyle: CornerStyle.bothCurve, - //Sweep gradient not supported in web - gradient: model.isWeb - ? null - : SweepGradient( - colors: [Colors.grey[400], Colors.orange], - stops: [0.25, 0.75]), + gradient: SweepGradient( + colors: [Colors.grey.shade200, Colors.orange], + stops: [0.25, 0.75]), thickness: isPortrait ? 30 : 10, )) ], @@ -190,8 +184,8 @@ class _ExportState extends SampleViewState { await getApplicationDocumentsDirectory(); final String path = documentDirectory.path; final String imageName = 'radialgauge.png'; - imageCache.clear(); - File file = new File('$path/$imageName'); + imageCache!.clear(); + final File file = File('$path/$imageName'); file.writeAsBytesSync(bytes); await Navigator.of(context).push( @@ -226,13 +220,13 @@ class _ExportState extends SampleViewState { final Size pageSize = page.getClientSize(); page.graphics.drawImage( bitmap, Rect.fromLTWH(0, 0, pageSize.width, pageSize.height)); - scaffoldKey.currentState.hideCurrentSnackBar(); - scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5))), duration: Duration(milliseconds: 200), - content: Text("Gauge has been exported as PDF document."), + content: Text('Gauge has been exported as PDF document.'), )); final List bytes = document.save(); document.dispose(); @@ -240,8 +234,9 @@ class _ExportState extends SampleViewState { } Future> _readImageData() async { - dart_ui.Image data = await _key.currentState.toImage(pixelRatio: 3.0); + final dart_ui.Image data = + await _key.currentState!.toImage(pixelRatio: 3.0); final bytes = await data.toByteData(format: dart_ui.ImageByteFormat.png); - return bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); + return bytes!.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes); } } diff --git a/lib/samples/gauge/pointer_interaction/radial_range_slider.dart b/lib/samples/gauge/pointer_interaction/radial_range_slider.dart index b04c5f3e..0f00ab00 100644 --- a/lib/samples/gauge/pointer_interaction/radial_range_slider.dart +++ b/lib/samples/gauge/pointer_interaction/radial_range_slider.dart @@ -6,6 +6,7 @@ import 'package:syncfusion_flutter_gauges/gauges.dart'; /// Local imports import '../../../model/sample_view.dart'; +import '../../../widgets/custom_button.dart'; /// Renders the gauge radial range range slider class RadialRangeSliderExample extends SampleView { @@ -23,115 +24,159 @@ class _RadialRangeSliderExampleState extends SampleViewState { @override Widget build(BuildContext context) { if (MediaQuery.of(context).orientation == Orientation.portrait) { - _markerSize = 20; + _markerSize = 25; _annotationFontSize = 25; _thickness = 0.06; _borderWidth = 5; } else { - _markerSize = 18; + _markerSize = 23; _annotationFontSize = 15; _thickness = 0.1; _borderWidth = 4; } - return isCardView - ? _getRadialRangeSlider(isCardView) - : Scaffold( - backgroundColor: - model.isWeb ? Colors.transparent : model.cardThemeColor, - body: Padding( - padding: model.isWeb - ? const EdgeInsets.fromLTRB(5, 20, 5, 20) - : const EdgeInsets.fromLTRB(5, 0, 5, 50), - child: SfRadialGauge(axes: [ - RadialAxis( - axisLineStyle: AxisLineStyle( - thickness: _thickness, - thicknessUnit: GaugeSizeUnit.factor), - radiusFactor: model.isWeb ? 0.8 : 0.95, - minorTicksPerInterval: 4, - showFirstLabel: false, - minimum: 0, - maximum: 12, - interval: 1, - startAngle: 270, - endAngle: 270, - pointers: [ - MarkerPointer( - value: _firstMarkerValue, - onValueChanged: _handleFirstPointerValueChanged, - onValueChanging: _handleFirstPointerValueChanging, - enableDragging: true, - borderColor: const Color(0xFFFFCD60), - borderWidth: _borderWidth, - color: Colors.white, - markerHeight: _markerSize, - markerWidth: _markerSize, - markerType: MarkerType.circle, - ), - MarkerPointer( - value: _secondMarkerValue, - onValueChanged: _handleSecondPointerValueChanged, - onValueChanging: _handleSecondPointerValueChanging, - color: Colors.white, - enableDragging: true, - borderColor: const Color(0xFFFFCD60), - markerHeight: _markerSize, - borderWidth: _borderWidth, - markerWidth: _markerSize, - markerType: MarkerType.circle, - ), - ], - ranges: [ - GaugeRange( - endValue: _secondMarkerValue, - sizeUnit: GaugeSizeUnit.factor, - startValue: _firstMarkerValue, - startWidth: _thickness, - endWidth: _thickness) - ], - annotations: [ - GaugeAnnotation( - widget: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '$_annotationValue', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: const Color(0xFF00A8B5)), - ), - Text( - ' hr', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: const Color(0xFF00A8B5)), - ), - Text( - ' $_minutesValue', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: const Color(0xFF00A8B5)), - ), - Text( - 'm', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: const Color(0xFF00A8B5)), - ) - ], - ), - positionFactor: 0.1, - angle: 0) - ]) - ]))); + return Scaffold( + backgroundColor: + model.isWebFullView ? Colors.transparent : model.cardThemeColor, + body: Padding( + padding: model.isWebFullView + ? const EdgeInsets.fromLTRB(5, 20, 5, 20) + : const EdgeInsets.fromLTRB(5, 0, 5, 50), + child: SfRadialGauge(axes: [ + RadialAxis( + axisLineStyle: AxisLineStyle( + thickness: model.isWebFullView ? 0.06 : _thickness, + thicknessUnit: GaugeSizeUnit.factor), + radiusFactor: isCardView + ? 0.95 + : model.isWebFullView + ? 0.8 + : 0.85, + minorTicksPerInterval: 4, + showFirstLabel: false, + minimum: 0, + maximum: 12, + interval: 1, + startAngle: 270, + endAngle: 270, + pointers: [ + MarkerPointer( + value: _firstMarkerValue, + onValueChanged: _handleFirstPointerValueChanged, + onValueChanging: _handleFirstPointerValueChanging, + enableDragging: _enableDragging, + borderColor: const Color(0xFFFFCD60), + borderWidth: isCardView ? 3 : _borderWidth, + color: model.currentThemeData!.brightness == + Brightness.light + ? Colors.white + : Colors.black.withOpacity(0.8), + markerHeight: isCardView ? 15 : _markerSize, + markerWidth: isCardView ? 15 : _markerSize, + markerType: MarkerType.circle, + overlayColor: Color.fromRGBO(255, 205, 96, 0.3), + overlayRadius: isCardView ? 15 : _overlayRadius), + MarkerPointer( + value: _secondMarkerValue, + onValueChanged: _handleSecondPointerValueChanged, + onValueChanging: _handleSecondPointerValueChanging, + color: model.currentThemeData!.brightness == + Brightness.light + ? Colors.white + : Colors.black.withOpacity(0.8), + enableDragging: _enableDragging, + borderColor: const Color(0xFFFFCD60), + markerHeight: isCardView ? 15 : _markerSize, + borderWidth: isCardView ? 3 : _borderWidth, + markerWidth: isCardView ? 15 : _markerSize, + markerType: MarkerType.circle, + overlayColor: Color.fromRGBO(255, 205, 96, 0.3), + overlayRadius: isCardView ? 15 : _overlayRadius), + ], + ranges: [ + GaugeRange( + endValue: _secondMarkerValue, + sizeUnit: GaugeSizeUnit.factor, + startValue: _firstMarkerValue, + startWidth: model.isWebFullView ? 0.06 : _thickness, + endWidth: model.isWebFullView ? 0.06 : _thickness) + ], + annotations: [ + GaugeAnnotation( + widget: Container( + child: Center( + child: Text( + '${_annotationValue}hr ${_minutesValue}m', + style: TextStyle( + fontSize: isCardView ? 18 : _annotationFontSize, + fontFamily: 'Times', + fontWeight: FontWeight.bold, + color: const Color(0xFF00A8B5)), + ))), + positionFactor: 0.05, + angle: 0) + ]) + ]))); + } + + @override + Widget buildSettings(BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + return ListView( + shrinkWrap: true, + children: [ + Container( + child: Row( + children: [ + Text('Enable dragging', style: TextStyle(color: model.textColor)), + Container( + width: 75, + child: CheckboxListTile( + activeColor: model.backgroundColor, + value: _enableDragging, + onChanged: (bool? value) { + setState(() { + _enableDragging = value!; + stateSetter(() {}); + }); + })) + ], + )), + Container( + child: Visibility( + visible: _enableDragging, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text('Overlay radius', + style: TextStyle(color: model.textColor)), + Container( + padding: !model.isWebFullView + ? EdgeInsets.fromLTRB(25, 0, 0, 0) + : EdgeInsets.fromLTRB(50, 0, 0, 0), + child: CustomDirectionalButtons( + maxValue: 35, + minValue: 15, + initialValue: _overlayRadius, + onChanged: (double val) { + setState(() { + _overlayRadius = val; + }); + }, + step: 5, + loop: false, + iconColor: model.textColor, + style: + TextStyle(fontSize: 16.0, color: model.textColor), + ), + ), + ], + )), + ), + ], + ); + }); } /// Dragged pointer new value is updated to range. @@ -150,16 +195,7 @@ class _RadialRangeSliderExampleState extends SampleViewState { void _handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 1) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 1) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -168,16 +204,7 @@ class _RadialRangeSliderExampleState extends SampleViewState { void _handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 1) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 1) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -205,69 +232,14 @@ class _RadialRangeSliderExampleState extends SampleViewState { _actualValue.length == 1 ? '0' + _actualValue : _actualValue; } - /// Returns the radial range slider gauge - Widget _getRadialRangeSlider(bool isTileView) { - return SfRadialGauge(axes: [ - RadialAxis( - axisLineStyle: AxisLineStyle( - thickness: 0.06, thicknessUnit: GaugeSizeUnit.factor), - minorTicksPerInterval: 4, - showFirstLabel: false, - minimum: 0, - maximum: 12, - interval: 1, - startAngle: 270, - endAngle: 270, - pointers: [ - MarkerPointer( - value: 2, - borderColor: const Color(0xFFFFCD60), - borderWidth: 3, - color: Colors.white, - markerHeight: 15, - markerWidth: 15, - markerType: MarkerType.circle, - ), - MarkerPointer( - value: 8, - color: Colors.white, - borderColor: const Color(0xFFFFCD60), - markerHeight: 15, - borderWidth: 3, - markerWidth: 15, - markerType: MarkerType.circle, - ), - ], - ranges: [ - GaugeRange( - endValue: 8, - sizeUnit: GaugeSizeUnit.factor, - startValue: 2, - startWidth: 0.06, - endWidth: 0.06) - ], - annotations: [ - GaugeAnnotation( - widget: const Text( - '6 hr 40 m', - style: TextStyle( - fontSize: 18, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: Color(0xFF00A8B5)), - ), - positionFactor: 0.05, - angle: 0) - ]) - ]); - } - double _borderWidth = 5; double _firstMarkerValue = 2; double _secondMarkerValue = 8; double _markerSize = 25; double _annotationFontSize = 25; double _thickness = 0.06; - String _annotationValue = '6'; + String _annotationValue = '06'; String _minutesValue = '40'; + double _overlayRadius = 30; + bool _enableDragging = true; } diff --git a/lib/samples/gauge/pointer_interaction/radial_slider.dart b/lib/samples/gauge/pointer_interaction/radial_slider.dart index a7eeac8d..8abd7790 100644 --- a/lib/samples/gauge/pointer_interaction/radial_slider.dart +++ b/lib/samples/gauge/pointer_interaction/radial_slider.dart @@ -25,25 +25,25 @@ class _RadialSliderExampleState extends SampleViewState { if (MediaQuery.of(context).orientation == Orientation.portrait) { _firstMarkerSize = 10; _annotationFontSize = 25; - if (model.isWeb) { + if (model.isWebFullView) { _width = _width * 0.35; } } else { - _firstMarkerSize = model.isWeb ? 10 : 5; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 10 : 5; + _annotationFontSize = model.isWebFullView ? 25 : 15; _width = _width * 0.35; } return Scaffold( backgroundColor: - model.isWeb ? Colors.transparent : model.cardThemeColor, + model.isWebFullView ? Colors.transparent : model.cardThemeColor, /// Added separate view for sample browser tile view and expanded view. /// In tile view, slider widget is removed. body: isCardView - ? getRadialSliderExample(true) + ? _buildRadialSliderExample(true) : Padding( - padding: model.isWeb + padding: model.isWebFullView ? const EdgeInsets.fromLTRB(5, 20, 5, 20) : const EdgeInsets.fromLTRB(5, 0, 5, 0), child: Column( @@ -81,15 +81,7 @@ class _RadialSliderExampleState extends SampleViewState { mainAxisSize: MainAxisSize.min, children: [ Text( - '$_annotationValue', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - color: const Color(0xFF00A8B5)), - ), - Text( - ' %', + '$_annotationValue%', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', @@ -104,7 +96,7 @@ class _RadialSliderExampleState extends SampleViewState { ]), ), Expanded( - flex: model.isWeb ? 2 : 3, + flex: model.isWebFullView ? 2 : 3, child: Container( width: _width, child: Slider( @@ -140,8 +132,28 @@ class _RadialSliderExampleState extends SampleViewState { } } + /// Dragged pointer new value is updated to pointer and + /// annotation current value. + void handleCardPointerValueChanged(double value) { + if (value.toInt() > 6) { + setState(() { + _cardCurrentValue = value.roundToDouble(); + final int _value = _cardCurrentValue.toInt(); + _cardAnnotationValue = '$_value'; + _cardMarkerValue = _cardCurrentValue - 2; + }); + } + } + + /// Pointer dragging is canceled when dragging pointer value is less than 6. + void handleCardPointerValueChanging(ValueChangingArgs args) { + if (args.value.toInt() <= 6) { + args.cancel = true; + } + } + /// Returns the radial slider gauge - Widget getRadialSliderExample(bool isTileView) { + Widget _buildRadialSliderExample(bool isTileView) { return SfRadialGauge(axes: [ RadialAxis( axisLineStyle: AxisLineStyle( @@ -150,9 +162,16 @@ class _RadialSliderExampleState extends SampleViewState { showLabels: false, radiusFactor: 1, pointers: [ - RangePointer(value: 60, width: 0.2, sizeUnit: GaugeSizeUnit.factor), + RangePointer( + width: 0.2, + value: _cardCurrentValue, + onValueChanged: handleCardPointerValueChanged, + onValueChangeEnd: handleCardPointerValueChanged, + onValueChanging: handleCardPointerValueChanging, + enableDragging: true, + sizeUnit: GaugeSizeUnit.factor), MarkerPointer( - value: 58, + value: _cardMarkerValue, color: Colors.white, markerHeight: 5, markerWidth: 5, @@ -163,9 +182,9 @@ class _RadialSliderExampleState extends SampleViewState { GaugeAnnotation( widget: Row( mainAxisSize: MainAxisSize.min, - children: const [ + children: [ Text( - '60', + _cardAnnotationValue, style: TextStyle( fontSize: 20, fontFamily: 'Times', @@ -173,7 +192,7 @@ class _RadialSliderExampleState extends SampleViewState { color: Color(0xFF00A8B5)), ), Text( - ' %', + '%', style: TextStyle( fontSize: 20, fontFamily: 'Times', @@ -193,4 +212,7 @@ class _RadialSliderExampleState extends SampleViewState { double _firstMarkerSize = 10; double _annotationFontSize = 25; String _annotationValue = '60'; + String _cardAnnotationValue = '60'; + double _cardCurrentValue = 60; + double _cardMarkerValue = 58; } diff --git a/lib/samples/gauge/pointers/marker_pointer.dart b/lib/samples/gauge/pointers/marker_pointer.dart index c8faae89..4dc5b409 100644 --- a/lib/samples/gauge/pointers/marker_pointer.dart +++ b/lib/samples/gauge/pointers/marker_pointer.dart @@ -6,6 +6,7 @@ import 'package:syncfusion_flutter_gauges/gauges.dart'; /// Local imports import '../../../model/sample_view.dart'; +import '../../../widgets/custom_button.dart'; /// Renders the gauge marker pointer sample class MarkerPointerExample extends SampleView { @@ -19,13 +20,113 @@ class MarkerPointerExample extends SampleView { class _MarkerPointerExampleState extends SampleViewState { _MarkerPointerExampleState(); + final List _markerTypes = [ + 'Circle', + 'Diamond', + 'Inverted triangle', + 'Rectangle', + 'Triangle', + ]; + + String _selectedMarkerType = 'Inverted triangle'; + MarkerType _markerType = MarkerType.invertedTriangle; + double _elevation = 4; + + @override + void initState() { + _selectedMarkerType = 'Inverted triangle'; + _markerType = MarkerType.invertedTriangle; + super.initState(); + } + @override Widget build(BuildContext context) { - return _getMarkerPointerExample(); + return _buildMarkerPointerExample(); + } + + @override + Widget buildSettings(BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + return ListView(shrinkWrap: true, children: [ + Container( + child: Row( + children: [ + Text('Marker type ', + style: TextStyle( + color: model.textColor, + fontSize: 16, + )), + Container( + padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), + child: DropdownButton( + underline: Container(color: Color(0xFFBDBDBD), height: 1), + value: _selectedMarkerType, + items: _markerTypes.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Inverted triangle', + child: Text('$value', + style: TextStyle(color: model.textColor))); + }).toList(), + onChanged: (String? value) { + _onMarkerTypeChange(value.toString()); + stateSetter(() {}); + }), + ), + ], + )), + Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text('Elevation', + style: TextStyle(fontSize: 16.0, color: model.textColor)), + Container( + padding: !model.isWebFullView + ? EdgeInsets.fromLTRB(40, 0, 0, 0) + : EdgeInsets.fromLTRB(50, 0, 0, 0), + child: CustomDirectionalButtons( + maxValue: 15, + minValue: 0, + initialValue: _elevation, + onChanged: (double val) { + setState(() { + _elevation = val; + }); + }, + step: 1, + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), + ), + ], + )), + ]); + }); + } + + /// Method for updating the marker type + void _onMarkerTypeChange(String item) { + setState(() { + _selectedMarkerType = item; + if (_selectedMarkerType == 'Circle') { + _markerType = MarkerType.circle; + } else if (_selectedMarkerType == 'Diamond') { + _markerType = MarkerType.diamond; + } else if (_selectedMarkerType == 'Inverted triangle') { + _markerType = MarkerType.invertedTriangle; + } else if (_selectedMarkerType == 'Rectangle') { + _markerType = MarkerType.rectangle; + } else if (_selectedMarkerType == 'Triangle') { + _markerType = MarkerType.triangle; + } + }); } /// Returns the marker pointer gauge - SfRadialGauge _getMarkerPointerExample() { + SfRadialGauge _buildMarkerPointerExample() { return SfRadialGauge( axes: [ RadialAxis( @@ -39,10 +140,11 @@ class _MarkerPointerExampleState extends SampleViewState { pointers: [ MarkerPointer( value: 70, - markerWidth: 20, - markerHeight: 20, + elevation: _elevation, + markerWidth: 25, + markerHeight: 25, color: const Color(0xFFF67280), - markerType: MarkerType.invertedTriangle, + markerType: _markerType, markerOffset: -7) ], annotations: [ @@ -76,11 +178,9 @@ class _MarkerPointerExampleState extends SampleViewState { startValue: 0, endValue: 100, sizeUnit: GaugeSizeUnit.factor, - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFAB64F5), Color(0xFF62DBF6)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFAB64F5), Color(0xFF62DBF6)], + stops: [0.25, 0.75]), startWidth: 0.4, endWidth: 0.4, color: const Color(0xFF00A8B5), diff --git a/lib/samples/gauge/pointers/multiple_needle.dart b/lib/samples/gauge/pointers/multiple_needle.dart index b90e90ad..e743c8d4 100644 --- a/lib/samples/gauge/pointers/multiple_needle.dart +++ b/lib/samples/gauge/pointers/multiple_needle.dart @@ -21,16 +21,16 @@ class _MultipleNeedleExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getMultipleNeedleExample(); + return _buildMultipleNeedleExample(); } /// Returns the multiple needle pointers gauge - SfRadialGauge _getMultipleNeedleExample() { + SfRadialGauge _buildMultipleNeedleExample() { return SfRadialGauge( axes: [ RadialAxis( showAxisLine: false, - radiusFactor: model.isWeb ? 0.43 : 0.5, + radiusFactor: model.isWebFullView ? 0.43 : 0.5, startAngle: 270, endAngle: 270, minimum: 0, @@ -54,7 +54,7 @@ class _MultipleNeedleExampleState extends SampleViewState { endAngle: 270, minimum: 0, maximum: 12, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, showFirstLabel: false, interval: 1, labelOffset: 10, diff --git a/lib/samples/gauge/pointers/range_pointer.dart b/lib/samples/gauge/pointers/range_pointer.dart index 2ce3d0db..7f85dca7 100644 --- a/lib/samples/gauge/pointers/range_pointer.dart +++ b/lib/samples/gauge/pointers/range_pointer.dart @@ -21,11 +21,11 @@ class _RangePointerExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRangePointerExampleGauge(); + return _buildRangePointerExampleGauge(); } /// Returns the range pointer gauge - SfRadialGauge _getRangePointerExampleGauge() { + SfRadialGauge _buildRangePointerExampleGauge() { return SfRadialGauge( axes: [ RadialAxis( @@ -75,12 +75,9 @@ class _RangePointerExampleState extends SampleViewState { animationDuration: 1200, animationType: AnimationType.ease, sizeUnit: GaugeSizeUnit.factor, - // Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFF6A6EF6), Color(0xFFDB82F5)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFF6A6EF6), Color(0xFFDB82F5)], + stops: [0.25, 0.75]), color: const Color(0xFF00A8B5), width: 0.15), ]), diff --git a/lib/samples/gauge/pointers/text_pointer.dart b/lib/samples/gauge/pointers/text_pointer.dart index 15ecd7a2..1e4c13f1 100644 --- a/lib/samples/gauge/pointers/text_pointer.dart +++ b/lib/samples/gauge/pointers/text_pointer.dart @@ -21,11 +21,11 @@ class _RadialTextPointerState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRadialTextPointer(); + return _buildRadialTextPointer(); } /// Returns the text pointer gauge - SfRadialGauge _getRadialTextPointer() { + SfRadialGauge _buildRadialTextPointer() { return SfRadialGauge( axes: [ RadialAxis( diff --git a/lib/samples/gauge/pointers/widget_pointer.dart b/lib/samples/gauge/pointers/widget_pointer.dart new file mode 100644 index 00000000..1750fbeb --- /dev/null +++ b/lib/samples/gauge/pointers/widget_pointer.dart @@ -0,0 +1,177 @@ +///Dart imports +import 'dart:async'; + +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; + +/// Renders the gauge axis default sample. +class WidgetPointerExample extends SampleView { + /// Renders default radial gauge widget + const WidgetPointerExample(Key key) : super(key: key); + + @override + _WidgetPointerExampleState createState() => _WidgetPointerExampleState(); +} + +class _WidgetPointerExampleState extends SampleViewState { + _WidgetPointerExampleState(); + + late Timer _timer; + int _value = 0; + + @override + Widget build(BuildContext context) { + return _buildWidgetPointerExample(context); + } + + @override + void initState() { + super.initState(); + _startTimer(); + } + + void _startTimer() { + if (mounted) { + _timer = Timer.periodic(const Duration(milliseconds: 20), (Timer _timer) { + _incrementPointerValue(); + }); + } + } + + void _incrementPointerValue() { + setState(() { + if (_value == 60) { + _timer.cancel(); + } else { + _value++; + } + }); + } + + /// Returns the default axis gauge + SfRadialGauge _buildWidgetPointerExample(BuildContext context) { + return SfRadialGauge( + axes: [ + RadialAxis( + startAngle: 130, + endAngle: 50, + showTicks: true, + interval: 10, + labelOffset: 0.1, + tickOffset: 0.125, + minorTicksPerInterval: 0, + labelsPosition: ElementsPosition.outside, + offsetUnit: GaugeSizeUnit.factor, + showAxisLine: false, + radiusFactor: model.isWebFullView ? 0.8 : 0.8, + showLabels: true, + minimum: 0, + maximum: 120, + pointers: [ + WidgetPointer( + offset: isCardView ? -2.5 : -5, + child: Container( + decoration: BoxDecoration( + color: model.themeData.brightness == Brightness.light + ? Colors.white + : Color.fromRGBO(33, 33, 33, 1), + borderRadius: BorderRadius.circular(40), + boxShadow: [ + BoxShadow( + color: model.themeData.brightness == Brightness.light + ? Colors.grey + : Colors.white.withOpacity(0.2), + offset: Offset.zero, + blurRadius: 4.0, + ), + ], + border: Border.all( + color: model.themeData.brightness == Brightness.light + ? Colors.black.withOpacity(0.1) + : Colors.white.withOpacity(0.1), + style: BorderStyle.solid, + width: 1.0, + )), + height: isCardView + ? 37 + : MediaQuery.of(context).orientation == + Orientation.landscape + ? 45 + : 50, + width: isCardView + ? 35 + : MediaQuery.of(context).orientation == + Orientation.landscape + ? 45 + : 50, + child: Center( + child: Row( + children: [ + Padding(padding: EdgeInsets.fromLTRB(5, 0, 0, 0)), + Container( + width: isCardView + ? 14.00 + : MediaQuery.of(context).orientation == + Orientation.landscape + ? 20 + : 20, + height: isCardView + ? 19.00 + : MediaQuery.of(context).orientation == + Orientation.landscape + ? 30 + : 30, + decoration: BoxDecoration( + image: DecorationImage( + image: ExactAssetImage(model + .themeData.brightness == + Brightness.light + ? 'images/temperature_indicator_light.png' + : 'images/temperature_indicator_dark.png'), + fit: BoxFit.fill, + ), + )), + Center( + child: Text( + '$_value', + style: TextStyle( + color: Color.fromRGBO(126, 126, 126, 1), + fontWeight: FontWeight.bold, + fontSize: isCardView ? 10 : 12, + ), + ), + ) + ], + ), + ), + ), + value: _value.toDouble()) + ], + ranges: [ + GaugeRange( + startValue: 0, + endValue: 40, + color: const Color.fromRGBO(74, 177, 70, 1), + ), + GaugeRange( + startValue: 40, + endValue: 80, + color: const Color.fromRGBO(251, 190, 32, 1), + ), + GaugeRange( + startValue: 80, + endValue: 120, + color: const Color.fromRGBO(237, 34, 35, 1), + ) + ], + ) + ], + ); + } +} diff --git a/lib/samples/gauge/ranges/multiple_ranges.dart b/lib/samples/gauge/ranges/multiple_ranges.dart index e35ca7ed..ba96d35c 100644 --- a/lib/samples/gauge/ranges/multiple_ranges.dart +++ b/lib/samples/gauge/ranges/multiple_ranges.dart @@ -21,11 +21,11 @@ class _MultipleRangesExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getMultipleRangesExampleGauge(context); + return _buildMultipleRangesExampleGauge(context); } /// Returns the multiple range gauge - SfRadialGauge _getMultipleRangesExampleGauge(BuildContext context) { + SfRadialGauge _buildMultipleRangesExampleGauge(BuildContext context) { return SfRadialGauge( axes: [ RadialAxis( diff --git a/lib/samples/gauge/ranges/range_datalabels.dart b/lib/samples/gauge/ranges/range_datalabels.dart index ecdd4adf..b2f0b09b 100644 --- a/lib/samples/gauge/ranges/range_datalabels.dart +++ b/lib/samples/gauge/ranges/range_datalabels.dart @@ -21,11 +21,11 @@ class _RangeDataLabelExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return _getRangeDataLabelExample(); + return _buildRangeDataLabelExample(); } /// Returns the range data label gauge - SfRadialGauge _getRangeDataLabelExample() { + SfRadialGauge _buildRangeDataLabelExample() { return SfRadialGauge( axes: [ RadialAxis( @@ -34,7 +34,7 @@ class _RangeDataLabelExampleState extends SampleViewState { showTicks: false, minimum: 0, maximum: 99, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, ranges: [ GaugeRange( startValue: 0, diff --git a/lib/samples/gauge/ranges/range_thickness.dart b/lib/samples/gauge/ranges/range_thickness.dart index be568a95..4f792e19 100644 --- a/lib/samples/gauge/ranges/range_thickness.dart +++ b/lib/samples/gauge/ranges/range_thickness.dart @@ -21,11 +21,11 @@ class _RangeThicknessExampleState extends SampleViewState { @override Widget build(BuildContext context) { - return getRangeThicknessExampleGauge(); + return _buildRangeThicknessExampleGauge(); } /// Returns the range thickness gauge - SfRadialGauge getRangeThicknessExampleGauge() { + SfRadialGauge _buildRangeThicknessExampleGauge() { return SfRadialGauge( axes: [ RadialAxis( @@ -70,14 +70,10 @@ class _RangeThicknessExampleState extends SampleViewState { GaugeRange( startValue: 30, endValue: 100, - startWidth: model.isWeb ? 0.2 : 0.05, - - /// Sweep gradient not supported in web - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFF289AB1), Color(0xFF43E695)], - stops: [0.25, 0.75]), + startWidth: model.isWebFullView ? 0.2 : 0.05, + gradient: const SweepGradient( + colors: [Color(0xFF289AB1), Color(0xFF43E695)], + stops: [0.25, 0.75]), color: const Color(0xFF289AB1), rangeOffset: 0.08, endWidth: 0.2, diff --git a/lib/samples/gauge/showcase/clock_sample.dart b/lib/samples/gauge/showcase/clock_sample.dart index a09c7a81..a1d8fdce 100644 --- a/lib/samples/gauge/showcase/clock_sample.dart +++ b/lib/samples/gauge/showcase/clock_sample.dart @@ -22,7 +22,7 @@ class ClockExample extends SampleView { class _ClockExampleState extends SampleViewState { _ClockExampleState(); - Timer timer; + late Timer timer; @override void initState() { @@ -53,13 +53,13 @@ class _ClockExampleState extends SampleViewState { child: Container( height: _containerSize, width: _containerSize, - child: _getClockExample(), + child: _buildClockExample(), ), ); } /// Returns the gauge clock - SfRadialGauge _getClockExample() { + SfRadialGauge _buildClockExample() { return SfRadialGauge( axes: [ /// Renders inner axis and positioned it using CenterX and @@ -115,7 +115,7 @@ class _ClockExampleState extends SampleViewState { interval: 2, centerX: isCardView ? 0.38 - : model.isWeb + : model.isWebFullView ? 0.38 : 0.335, minorTicksPerInterval: 5, @@ -148,7 +148,7 @@ class _ClockExampleState extends SampleViewState { maximum: 12, showFirstLabel: false, interval: 1, - radiusFactor: model.isWeb ? 0.8 : 0.95, + radiusFactor: model.isWebFullView ? 0.8 : 0.95, labelOffset: 0.1, offsetUnit: GaugeSizeUnit.factor, minorTicksPerInterval: 4, diff --git a/lib/samples/gauge/showcase/distance_tracker.dart b/lib/samples/gauge/showcase/distance_tracker.dart index b3162a3a..c643dd9f 100644 --- a/lib/samples/gauge/showcase/distance_tracker.dart +++ b/lib/samples/gauge/showcase/distance_tracker.dart @@ -27,15 +27,15 @@ class _DistanceTrackerExampleState extends SampleViewState { _markerValue = (MediaQuery.of(context).orientation == Orientation.portrait) ? 138 - : model.isWeb + : model.isWebFullView ? 138 : 136; }); - return _getDistanceTrackerExample(); + return _buildDistanceTrackerExample(); } /// Returns the gauge distance tracker - SfRadialGauge _getDistanceTrackerExample() { + SfRadialGauge _buildDistanceTrackerExample() { return SfRadialGauge( enableLoadingAnimation: true, axes: [ @@ -93,11 +93,9 @@ class _DistanceTrackerExampleState extends SampleViewState { pointerOffset: -6, cornerStyle: CornerStyle.bothCurve, color: const Color(0xFFF67280), - gradient: model.isWeb - ? null - : const SweepGradient( - colors: [Color(0xFFFF7676), Color(0xFFF54EA2)], - stops: [0.25, 0.75]), + gradient: const SweepGradient( + colors: [Color(0xFFFF7676), Color(0xFFF54EA2)], + stops: [0.25, 0.75]), ), MarkerPointer( value: isCardView ? 136 : _markerValue, diff --git a/lib/samples/gauge/showcase/gauge_compass.dart b/lib/samples/gauge/showcase/gauge_compass.dart index 006f3636..a967f7c7 100644 --- a/lib/samples/gauge/showcase/gauge_compass.dart +++ b/lib/samples/gauge/showcase/gauge_compass.dart @@ -30,12 +30,12 @@ class _GaugeCompassExampleState extends SampleViewState { _markerWidth = 15; _labelFontSize = 11; } else { - _annotationTextSize = model.isWeb ? 22 : 16; - _markerOffset = model.isWeb ? 0.71 : 0.69; - _positionFactor = model.isWeb ? 0.025 : 0.05; - _markerHeight = model.isWeb ? 10 : 5; - _markerWidth = model.isWeb ? 15 : 10; - _labelFontSize = model.isWeb ? 11 : 10; + _annotationTextSize = model.isWebFullView ? 22 : 16; + _markerOffset = model.isWebFullView ? 0.71 : 0.69; + _positionFactor = model.isWebFullView ? 0.025 : 0.05; + _markerHeight = model.isWebFullView ? 10 : 5; + _markerWidth = model.isWebFullView ? 15 : 10; + _labelFontSize = model.isWebFullView ? 11 : 10; } final Widget _widget = SfRadialGauge( axes: [ @@ -93,7 +93,7 @@ class _GaugeCompassExampleState extends SampleViewState { ]) ], ); - if (model.isWeb) { + if (model.isWebFullView) { return Padding( padding: const EdgeInsets.all(35), child: _widget, diff --git a/lib/samples/gauge/showcase/temperature_monitor.dart b/lib/samples/gauge/showcase/temperature_monitor.dart index 85ca5479..dd3da6b9 100644 --- a/lib/samples/gauge/showcase/temperature_monitor.dart +++ b/lib/samples/gauge/showcase/temperature_monitor.dart @@ -28,11 +28,11 @@ class _GaugeTemperatureMonitorExampleState extends SampleViewState { _interval = MediaQuery.of(context).orientation == Orientation.portrait ? 10 : 20; }); - return _getTemperatureMonitorExample(); + return _buildTemperatureMonitorExample(); } /// Returns the gauge temperature monitor - SfRadialGauge _getTemperatureMonitorExample() { + SfRadialGauge _buildTemperatureMonitorExample() { return SfRadialGauge( animationDuration: 3500, enableLoadingAnimation: true, @@ -45,7 +45,7 @@ class _GaugeTemperatureMonitorExampleState extends SampleViewState { interval: isCardView ? 20 : _interval, minorTicksPerInterval: 9, showAxisLine: false, - radiusFactor: model.isWeb ? 0.8 : 0.9, + radiusFactor: model.isWebFullView ? 0.8 : 0.9, labelOffset: 8, ranges: [ GaugeRange( diff --git a/lib/samples/linear_gauge/api/api_customization.dart b/lib/samples/linear_gauge/api/api_customization.dart new file mode 100644 index 00000000..763341d6 --- /dev/null +++ b/lib/samples/linear_gauge/api/api_customization.dart @@ -0,0 +1,445 @@ +// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter_examples/samples/linear_gauge/utils.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../../../widgets/custom_button.dart'; +import '../utils.dart'; + +/// Renders the linear gauge api customization sample. +class ApiCustomization extends SampleView { + /// Creates the linear gauge api customization sample. + const ApiCustomization(Key key) : super(key: key); + + @override + _ApiCustomizationState createState() => _ApiCustomizationState(); +} + +/// State class of api customization sample. +class _ApiCustomizationState extends SampleViewState { + LinearElementPosition _shapePosition = LinearElementPosition.outside; + LinearElementPosition _barPosition = LinearElementPosition.outside; + LinearElementPosition _rangePosition = LinearElementPosition.outside; + final _scrollController = ScrollController(); + + String _shapePointerPosition = 'Outside'; + String _barPointerPosition = 'Outside'; + String _rangePointerPosition = 'Outside'; + bool _isMirror = false; + bool _isInverse = false; + bool _isHorizontalOrientation = false; + double _barOffset = 5; + + final List _pointerPositions = ['Outside', 'Cross', 'Inside']; + + void shapePosition(String item) { + _shapePointerPosition = item; + if (_shapePointerPosition == 'Inside') { + _shapePosition = LinearElementPosition.inside; + } + if (_shapePointerPosition == 'Outside') { + _shapePosition = LinearElementPosition.outside; + } + if (_shapePointerPosition == 'Cross') { + _shapePosition = LinearElementPosition.cross; + } + } + + void barPosition(String item) { + _barPointerPosition = item; + if (_barPointerPosition == 'Inside') { + _barPosition = LinearElementPosition.inside; + } + if (_barPointerPosition == 'Outside') { + _barPosition = LinearElementPosition.outside; + } + if (_barPointerPosition == 'Cross') { + _barPosition = LinearElementPosition.cross; + } + } + + void rangePosition(String item) { + _rangePointerPosition = item; + if (_rangePointerPosition == 'Inside') { + _rangePosition = LinearElementPosition.inside; + } + if (_rangePointerPosition == 'Outside') { + _rangePosition = LinearElementPosition.outside; + } + if (_rangePointerPosition == 'Cross') { + _rangePosition = LinearElementPosition.cross; + } + } + + Widget _buildLinearGauge(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: model.isWebFullView + ? MediaQuery.of(context).size.height / 2 + : MediaQuery.of(context).size.height / + (MediaQuery.of(context).orientation == Orientation.portrait + ? 2 + : 3), + child: SfLinearGauge( + maximum: 50, + isMirrored: _isMirror, + isAxisInversed: _isInverse, + interval: 10, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [ + LinearBarPointer( + value: 30, + position: _barPosition, + offset: _barOffset, + edgeStyle: LinearEdgeStyle.endCurve, + ), + ], + markerPointers: [ + LinearShapePointer( + value: 40, + position: _shapePosition, + ), + ], + ranges: [ + LinearGaugeRange( + startValue: 0, + endValue: 20, + color: Colors.red, + position: _rangePosition, + ), + LinearGaugeRange( + startValue: 20, + endValue: 35, + color: Colors.orange, + position: _rangePosition, + ), + LinearGaugeRange( + startValue: 35, + endValue: 50, + color: Colors.green, + position: _rangePosition, + ) + ], + ), + ), + SizedBox(height: 5), + Visibility( + maintainSize: true, + maintainAnimation: true, + maintainState: true, + visible: _barPosition == LinearElementPosition.cross ? true : false, + child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Icon(Icons.lightbulb_outline, color: Colors.orange, size: 24.0), + SizedBox(width: 5), + Flexible( + child: Text( + 'Offset positioning is not possible for cross aligned elements.', + style: TextStyle(fontSize: 12), + ), + ) + ])), + ], + ); + } + + Widget _buildPropertiesPanel(BuildContext context) { + return Scrollbar( + controller: _scrollController, + isAlwaysShown: model.isMobile + ? true + : MediaQuery.of(context).size.width >= 550 + ? false + : true, + child: SingleChildScrollView( + controller: _scrollController, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + 'Properties : ', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), + ), + SizedBox(height: 5), + GestureDetector( + onTap: () { + setState(() { + _isInverse = !_isInverse; + }); + }, + child: Container( + height: 40, + color: Colors.transparent, + child: Row( + children: [ + Container( + width: 30, + child: Checkbox( + value: _isInverse, + splashRadius: 15, + activeColor: model.backgroundColor, + onChanged: (bool? value) { + setState(() { + if (value != null) { + _isInverse = value; + } + }); + }), + ), + Text('Inverse Axis', style: TextStyle(fontSize: 14)) + ], + ), + ), + ), + GestureDetector( + onTap: () { + setState(() { + _isMirror = !_isMirror; + }); + }, + child: Container( + height: 40, + color: Colors.transparent, + child: Row( + children: [ + Container( + width: 30, + child: Checkbox( + splashRadius: 15, + value: _isMirror, + activeColor: model.backgroundColor, + onChanged: (bool? value) { + setState(() { + if (value != null) { + _isMirror = value; + } + }); + }), + ), + Text('Mirror', style: TextStyle(fontSize: 14)) + ], + ), + )), + GestureDetector( + onTap: () { + setState(() { + _isHorizontalOrientation = !_isHorizontalOrientation; + }); + }, + child: Container( + height: 40, + color: Colors.transparent, + child: Row( + children: [ + Container( + width: 30, + child: Checkbox( + value: _isHorizontalOrientation, + splashRadius: 15, + activeColor: model.backgroundColor, + onChanged: (bool? value) { + setState(() { + if (value != null) { + _isHorizontalOrientation = value; + } + }); + }), + ), + Text('Horizontal Orientation', + style: TextStyle(fontSize: 14)) + ], + ), + )), + Row( + children: [ + Container( + width: 150, + margin: EdgeInsets.only(left: 5), + child: Text('Shape Pointer Position', + style: TextStyle(fontSize: 14)), + ), + Text(':'), + Padding( + padding: const EdgeInsets.only(left: 10), + child: ButtonTheme( + alignedDropdown: true, + child: DropdownButton( + value: _shapePointerPosition, + items: _pointerPositions.map((String value) { + return DropdownMenuItem( + value: + (value != null) ? value : 'Outside', + child: Text('$value', + style: TextStyle(fontSize: 14))); + }).toList(), + onChanged: (String? value) { + setState(() { + if (value != null) { + shapePosition(value.toString()); + } + }); + })), + ) + ], + ), + Row( + children: [ + Container( + width: 150, + margin: EdgeInsets.only(left: 5), + child: Text('Bar Pointer Position', + style: TextStyle(fontSize: 14)), + ), + Text(':'), + Padding( + padding: const EdgeInsets.only(left: 10), + child: ButtonTheme( + alignedDropdown: true, + child: DropdownButton( + value: _barPointerPosition, + items: _pointerPositions.map((String value) { + return DropdownMenuItem( + value: + (value != null) ? value : 'Outside', + child: Text('$value', + style: TextStyle(fontSize: 14))); + }).toList(), + onChanged: (String? value) { + setState(() { + if (value != null) { + barPosition(value.toString()); + } + }); + })), + ) + ], + ), + Row( + children: [ + Container( + width: 150, + margin: EdgeInsets.only(left: 5), + child: Text( + 'Range Position', + style: TextStyle(fontSize: 14), + )), + Text(':'), + Padding( + padding: const EdgeInsets.only(left: 10), + child: ButtonTheme( + alignedDropdown: true, + child: DropdownButton( + value: _rangePointerPosition, + items: _pointerPositions.map((String value) { + return DropdownMenuItem( + value: + (value != null) ? value : 'Outside', + child: Text('$value', + style: TextStyle(fontSize: 14))); + }).toList(), + onChanged: (dynamic value) { + setState(() { + rangePosition(value.toString()); + }); + })), + ) + ], + ), + Visibility( + visible: _barPosition == LinearElementPosition.cross + ? false + : true, + child: Row( + children: [ + Container( + width: 150, + margin: EdgeInsets.only(left: 5), + child: Text( + 'Bar Offset', + style: TextStyle(fontSize: 14), + )), + Text(':'), + Container( + transform: Matrix4.translationValues(-8, 0, 0), + child: CustomDirectionalButtons( + maxValue: 20, + minValue: 0, + initialValue: _barOffset, + onChanged: (double value) { + setState(() { + _barOffset = value; + }); + }, + step: 1, + loop: false, + iconColor: model.textColor, + style: TextStyle( + fontSize: 16.0, color: model.textColor), + ), + ) + ], + ), + ), + ]))); + } + + @override + Widget build(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + return (isWebOrDesktop && MediaQuery.of(context).size.width >= 550) + ? Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Spacer(), + Wrap(children: [ + Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width / 3, + child: _buildLinearGauge(context)), + ]), + Spacer(), + Container( + height: MediaQuery.of(context).size.height, + width: 1, + color: _brightness == Brightness.dark + ? Color(0xff3D3D3D) + : Color(0xffe2e2e2)), + Container( + color: _brightness == Brightness.dark + ? Color(0xff2a2a2a) + : model.webBackgroundColor, + height: MediaQuery.of(context).size.height, + padding: EdgeInsets.all(10), + child: _buildPropertiesPanel(context)), + ], + ) + : Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SingleChildScrollView( + child: Column(children: [ + _buildLinearGauge(context), + SizedBox(height: 10), + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height / 4, + padding: EdgeInsets.fromLTRB(10, 10, 0, 10), + color: _brightness == Brightness.dark + ? Color(0xff2a2a2a) + : model.webBackgroundColor, + child: _buildPropertiesPanel(context), + ), + ]), + ), + ), + ); + } +} diff --git a/lib/samples/linear_gauge/axis/axis_track.dart b/lib/samples/linear_gauge/axis/axis_track.dart new file mode 100644 index 00000000..66f9feba --- /dev/null +++ b/lib/samples/linear_gauge/axis/axis_track.dart @@ -0,0 +1,247 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge axis track sample. +class AxisTrack extends SampleView { + /// Creates linear gauge with default and customized axis track styles. + const AxisTrack(Key key) : super(key: key); + + @override + _AxisTrackState createState() => _AxisTrackState(); +} + +/// State class of linear gauge axis track. +class _AxisTrackState extends SampleViewState { + _AxisTrackState(); + double _pointerValue = 70; + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildAxisTrack(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge axis track. + Widget _buildAxisTrack(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + children: [ + _buildHorizontalGauges( + 'Default axis', _buildDefaultAxis(context)), + _buildHorizontalGauges( + 'Edge style', _buildEdgeStyleAxis(context)), + _buildHorizontalGauges( + 'Inversed axis', _buildInversedAxis(context)), + _buildHorizontalGauges( + 'Range color for axis', _buildRangeColorAxis(context)), + _buildHorizontalGauges( + 'Axis extent', _buildAxisExtent(context)), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges( + 'Default axis', _buildDefaultAxis(context)), + _buildVerticalGauges( + 'Edge style', + _buildEdgeStyleAxis(context), + ), + _buildVerticalGauges( + 'Axis extent', _buildAxisExtent(context)), + _buildVerticalGauges( + 'Range color for axis', _buildRangeColorAxis(context)), + _buildVerticalGauges( + 'Inversed axis', _buildInversedAxis(context)), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + ), + ); + } + + /// Returns the default axis. + Widget _buildDefaultAxis(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the edge style axis. + Widget _buildEdgeStyleAxis(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + axisTrackExtent: 8, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 24, edgeStyle: LinearEdgeStyle.bothCurve))); + } + + /// Returns the inversed axis. + Widget _buildInversedAxis(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + isAxisInversed: true, + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [ + LinearBarPointer(value: _pointerValue) + ], + markerPointers: [ + LinearShapePointer( + value: _pointerValue, + onValueChanged: (value) => { + setState(() => {_pointerValue = value}) + }), + ])); + } + + /// Returns the range color axis. + Widget _buildRangeColorAxis(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + minorTicksPerInterval: 4, + useRangeColorForAxis: true, + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 1, + ), + ranges: [ + LinearGaugeRange( + startValue: 0, + endValue: 33, + position: LinearElementPosition.outside, + color: _brightness == Brightness.light + ? Color(0xffF45656) + : Color(0xffFF7B7B), + ), + LinearGaugeRange( + startValue: 33, + endValue: 66, + position: LinearElementPosition.outside, + color: Color(0xffFFC93E), + ), + LinearGaugeRange( + startValue: 66, + endValue: 100, + position: LinearElementPosition.outside, + color: Color(0xff0DC9AB), + ), + ], + )); + } + + /// Returns the axis extent. + Widget _buildAxisExtent(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + axisTrackExtent: 20, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + labelOffset: 10, + minorTicksPerInterval: 0, + animateAxis: true, + )); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/axis/label_customization.dart b/lib/samples/linear_gauge/axis/label_customization.dart new file mode 100644 index 00000000..c4ae3e6a --- /dev/null +++ b/lib/samples/linear_gauge/axis/label_customization.dart @@ -0,0 +1,309 @@ +import 'package:flutter/foundation.dart'; + +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge labels customization sample. +class GaugeLabelCustomization extends SampleView { + /// Creates Linear Gauge with default and customized label styles + const GaugeLabelCustomization(Key key) : super(key: key); + + @override + _GaugeLabelCustomizationState createState() => + _GaugeLabelCustomizationState(); +} + +/// State class of linear gauge label customization. +class _GaugeLabelCustomizationState extends SampleViewState { + _GaugeLabelCustomizationState(); + + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: isWebOrDesktop + ? MediaQuery.of(context).size.width >= 1000 + ? _isHorizontalOrientation + ? MediaQuery.of(context).size.width / 3 + : MediaQuery.of(context).size.width + : 440 + : MediaQuery.of(context).size.width, + child: _buildLabelCustomization(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge label customization. + Widget _buildLabelCustomization(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges('Custom labels', _buildCustomLabels()), + _buildHorizontalGauges( + 'Label offset', _buildLabelsWithOffset()), + _buildHorizontalGauges( + 'Text labels', _buildTextLabels(context)), + _buildHorizontalGauges('Label style customization', + _buildLabelStyleCustomization(context)) + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges('Custom labels', _buildCustomLabels()), + _buildVerticalGauges( + 'Text labels', _buildTextLabels(context)), + _buildVerticalGauges( + 'Label offset', _buildLabelsWithOffset()), + _buildVerticalGauges('Label style customization', + _buildLabelStyleCustomization(context)) + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + ), + ); + } + + /// Returns the custom labels sample. + Widget _buildCustomLabels() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + onGenerateLabels: () { + return [ + LinearAxisLabel(text: '\$5', value: 0), + LinearAxisLabel(text: '\$10', value: 10), + LinearAxisLabel(text: '\$15', value: 20), + LinearAxisLabel(text: '\$20', value: 30), + ]; + }, + minimum: 0, + maximum: 30, + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical)); + } + + /// Returns the text labels sample. + Widget _buildTextLabels(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + final double _deliveryStatus = 20; + final double _orderState = 0; + final double _packedState = 10; + final double _shippedState = 20; + final double _deliveredState = 30; + final Color _activeColor = + _deliveryStatus > _orderState ? Color(0xff0DC9AB) : Color(0xffD1D9DD); + final Color _inactiveColor = + _brightness == Brightness.dark ? Color(0xff62686A) : Color(0xFFD1D9DD); + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + minimum: 0, + maximum: 30, + labelOffset: 24, + isAxisInversed: _isHorizontalOrientation ? false : true, + showTicks: false, + onGenerateLabels: () { + return [ + LinearAxisLabel(text: 'Ordered', value: 0), + LinearAxisLabel(text: 'Packed', value: 10), + LinearAxisLabel(text: 'Shipped', value: 20), + LinearAxisLabel(text: 'Delivered', value: 30), + ]; + }, + axisTrackStyle: LinearAxisTrackStyle( + color: _inactiveColor, + ), + barPointers: [ + LinearBarPointer( + value: _deliveryStatus, + color: _activeColor, + enableAnimation: false, + position: LinearElementPosition.cross, + ), + ], + markerPointers: [ + LinearWidgetPointer( + value: _orderState, + enableAnimation: false, + position: LinearElementPosition.cross, + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: model.cardColor, + border: Border.all(width: 4, color: _activeColor), + borderRadius: BorderRadius.all(Radius.circular(12))), + child: Center( + child: + Icon(Icons.check_rounded, size: 14, color: _activeColor), + ), + ), + ), + LinearWidgetPointer( + enableAnimation: false, + value: _packedState, + position: LinearElementPosition.cross, + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: model.cardColor, + border: Border.all(width: 4, color: _activeColor), + borderRadius: BorderRadius.all(Radius.circular(12))), + child: Center( + child: + Icon(Icons.check_rounded, size: 14, color: _activeColor), + ), + ), + ), + LinearWidgetPointer( + value: _shippedState, + enableAnimation: false, + position: LinearElementPosition.cross, + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: model.cardColor, + border: Border.all(width: 4, color: _activeColor), + borderRadius: BorderRadius.all(Radius.circular(12))), + child: Center( + child: + Icon(Icons.check_rounded, size: 14, color: _activeColor), + ), + ), + ), + LinearShapePointer( + value: _deliveredState, + enableAnimation: false, + color: _inactiveColor, + width: 24, + height: 24, + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle, + ), + ], + )); + } + + /// Returns the labels with offset sample. + Widget _buildLabelsWithOffset() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + labelOffset: 16, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the label style customization sample. + Widget _buildLabelStyleCustomization(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + axisLabelStyle: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 10, + color: _brightness == Brightness.dark + ? Color(0xff8580FF) + : Color(0xff6F20F0)), + ), + ); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/axis/tick_customization.dart b/lib/samples/linear_gauge/axis/tick_customization.dart new file mode 100644 index 00000000..1563050f --- /dev/null +++ b/lib/samples/linear_gauge/axis/tick_customization.dart @@ -0,0 +1,187 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge ticks customization sample. +class TickCustomization extends SampleView { + /// Creates linear gauge with default and customized tick styles. + const TickCustomization(Key key) : super(key: key); + + @override + _TickCustomizationState createState() => _TickCustomizationState(); +} + +/// State class of linear gauge tick customization. +class _TickCustomizationState extends SampleViewState { + _TickCustomizationState(); + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildLinearTickCustomization(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge tick customization. + Widget _buildLinearTickCustomization(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges('Outside ticks', _buildOutsideTicks()), + _buildHorizontalGauges('Cross ticks', _buildCrossTicks()), + _buildHorizontalGauges('Inside ticks', _buildInsideTicks()), + _buildHorizontalGauges( + 'Ticks with offset', _buildTicksWithOffset()), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges('Outside ticks', _buildOutsideTicks()), + _buildVerticalGauges('Cross ticks', _buildCrossTicks()), + _buildVerticalGauges('Inside ticks', _buildInsideTicks()), + _buildVerticalGauges( + 'Ticks with offset', _buildTicksWithOffset()), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + ), + ); + } + + /// Returns the outside ticks sample. + Widget _buildOutsideTicks() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + labelPosition: LinearLabelPosition.outside, + tickPosition: LinearElementPosition.outside, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the cross ticks sample. + Widget _buildCrossTicks() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + tickPosition: LinearElementPosition.cross, + labelPosition: LinearLabelPosition.outside, + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the inside ticks sample. + Widget _buildInsideTicks() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the ticks with offset sample. + Widget _buildTicksWithOffset() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + tickOffset: 20, + labelOffset: 20, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + )); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/pointers/bar_pointer.dart b/lib/samples/linear_gauge/pointers/bar_pointer.dart new file mode 100644 index 00000000..d6522d15 --- /dev/null +++ b/lib/samples/linear_gauge/pointers/bar_pointer.dart @@ -0,0 +1,234 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge bar pointer sample. +class BarPointer extends SampleView { + /// Creates linear gauge with default and customized bar pointer styles. + const BarPointer(Key key) : super(key: key); + + @override + _BarPointerState createState() => _BarPointerState(); +} + +/// State class of linear gauge bar pointer. +class _BarPointerState extends SampleViewState { + _BarPointerState(); + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildBarPointer(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge bar pointer. + Widget _buildBarPointer(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges( + 'Outside', _buildBarPointerOutsideAxis()), + _buildHorizontalGauges('Cross', _buildBarPointerCrossAxis()), + _buildHorizontalGauges('Inside', _buildBarPointerInsideAxis()), + _buildHorizontalGauges( + 'Gradient shader', _buildBarPointerWithShader()), + _buildHorizontalGauges('Multiple bar pointers', + _buildMultipleBarPointers(context)), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges( + 'Outside', _buildBarPointerOutsideAxis()), + _buildVerticalGauges('Cross', _buildBarPointerCrossAxis()), + _buildVerticalGauges( + 'Inside', _buildBarPointerInsideAxis()), + _buildVerticalGauges( + 'Gradient shader', _buildBarPointerWithShader()), + _buildVerticalGauges('Multiple bar pointers', + _buildMultipleBarPointers(context)), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + )); + } + + /// Returns the outside axis bar pointer. + Widget _buildBarPointerOutsideAxis() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [ + LinearBarPointer( + value: 70, position: LinearElementPosition.outside) + ])); + } + + /// Returns the cross axis bar pointer. + Widget _buildBarPointerCrossAxis() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [LinearBarPointer(value: 70)], + )); + } + + /// Returns the inside axis bar pointer. + Widget _buildBarPointerInsideAxis() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [ + LinearBarPointer( + value: 70, + position: LinearElementPosition.inside, + ) + ])); + } + + /// Returns the bar pointer with shader. + Widget _buildBarPointerWithShader() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + barPointers: [ + LinearBarPointer( + value: 70, + offset: 5, + shaderCallback: (bounds) { + return LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomCenter, + colors: [Colors.green, Colors.blue]).createShader(bounds); + }, + position: LinearElementPosition.outside, + edgeStyle: LinearEdgeStyle.bothCurve, + ) + ])); + } + + /// Returns the multiple bar pointers. + Widget _buildMultipleBarPointers(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + animateAxis: true, + barPointers: [ + LinearBarPointer( + value: 10, + position: LinearElementPosition.inside, + color: _brightness == Brightness.light + ? Color(0xffF45656) + : Color(0xffFF7B7B), + ), + LinearBarPointer( + value: 70, + position: LinearElementPosition.outside, + ), + ])); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/pointers/shape_pointer.dart b/lib/samples/linear_gauge/pointers/shape_pointer.dart new file mode 100644 index 00000000..1b761e62 --- /dev/null +++ b/lib/samples/linear_gauge/pointers/shape_pointer.dart @@ -0,0 +1,263 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge shape pointer sample. +class ShapePointer extends SampleView { + /// Creates linear gauge with default and customized shape pointer styles + const ShapePointer(Key key) : super(key: key); + + @override + _ShapePointerState createState() => _ShapePointerState(); +} + +/// State class of linear gauge shape pointer. +class _ShapePointerState extends SampleViewState { + _ShapePointerState(); + double _invertedTrianglePointerValue = 40; + double _circlePointerValue = 20; + double _diamondPointerValue = 50; + double _rectanglePointerValue = 30; + double _pointerValue = 10; + double _multiPointerValue = 100; + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildShapePointer(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge with shape pointer. + Widget _buildShapePointer(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges( + 'Inverted triangle', _buildInvertedTriangleShapePointer()), + _buildHorizontalGauges('Circle', _buildCircleShapePointer()), + _buildHorizontalGauges('Diamond', _buildDiamondShapePointer()), + _buildHorizontalGauges( + 'Rectangle', _buildRectangleShapePointer()), + _buildHorizontalGauges( + 'Multiple pointers', _buildMultipleShapePointers()), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges('Inverted triangle', + _buildInvertedTriangleShapePointer()), + _buildVerticalGauges('Circle', _buildCircleShapePointer()), + _buildVerticalGauges( + 'Diamond', _buildDiamondShapePointer()), + _buildVerticalGauges( + 'Rectangle', _buildRectangleShapePointer()), + _buildVerticalGauges( + 'Multiple pointers', _buildMultipleShapePointers()), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + )); + } + + /// Returns the inverted triangle shape pointer sample. + Widget _buildInvertedTriangleShapePointer() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearShapePointer( + value: _invertedTrianglePointerValue, + onValueChanged: (value) => { + setState(() => {_invertedTrianglePointerValue = value}) + }, + ), + ], + barPointers: [ + LinearBarPointer(value: _invertedTrianglePointerValue), + ], + )); + } + + /// Returns the circle shape pointer sample. + Widget _buildCircleShapePointer() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearShapePointer( + value: _circlePointerValue, + onValueChanged: (value) => { + setState(() => {_circlePointerValue = value}) + }, + shapeType: LinearShapePointerType.circle), + ], + barPointers: [ + LinearBarPointer(value: _circlePointerValue), + ])); + } + + /// Returns the diamond shape pointer sample. + Widget _buildDiamondShapePointer() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearShapePointer( + value: _diamondPointerValue, + onValueChanged: (value) => { + setState(() => {_diamondPointerValue = value}) + }, + shapeType: LinearShapePointerType.diamond), + ], + barPointers: [ + LinearBarPointer(value: _diamondPointerValue), + ])); + } + + /// Returns the rectangle shape pointer sample. + Widget _buildRectangleShapePointer() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearShapePointer( + value: _rectanglePointerValue, + onValueChanged: (value) => { + setState(() => {_rectanglePointerValue = value}) + }, + shapeType: LinearShapePointerType.rectangle, + ), + ], + barPointers: [ + LinearBarPointer(value: _rectanglePointerValue), + ])); + } + + /// Returns the multiple shape pointers sample. + Widget _buildMultipleShapePointers() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearShapePointer( + value: _pointerValue, + onValueChanged: (value) => { + setState(() => {_pointerValue = value}) + }, + ), + LinearShapePointer( + value: _multiPointerValue, + onValueChanged: (value) => { + setState(() => {_multiPointerValue = value}) + }, + shapeType: LinearShapePointerType.diamond) + ], + barPointers: [ + LinearBarPointer(value: _pointerValue), + ])); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/pointers/widget_pointer.dart b/lib/samples/linear_gauge/pointers/widget_pointer.dart new file mode 100644 index 00000000..b38690ad --- /dev/null +++ b/lib/samples/linear_gauge/pointers/widget_pointer.dart @@ -0,0 +1,311 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge widget pointer sample. +class WidgetPointer extends SampleView { + /// Creates linear gauge with default and customized widget pointer styles + const WidgetPointer(Key key) : super(key: key); + + @override + _WidgetPointerState createState() => _WidgetPointerState(); +} + +/// State class of linear gauge widget pointer. +class _WidgetPointerState extends SampleViewState { + _WidgetPointerState(); + double _textWidgetPointerValue = 40; + double _iconWidgetPointerValue = 30; + double _iconPointerValue = 20; + double _textPointerValue = 60; + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildWidgetPointer(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge widget pointer. + Widget _buildWidgetPointer(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges( + 'Text widget', _buildTextWidgetPointer(context)), + _buildHorizontalGauges( + 'Icon widget', _buildIconWidgetPointer(context)), + _buildHorizontalGauges('Multiple widget pointers', + _buildMultipleWidgetPointers(context)), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges( + 'Text widget', _buildTextWidgetPointer(context)), + _buildVerticalGauges( + 'Icon widget', _buildIconWidgetPointer(context)), + _buildVerticalGauges('Multiple widget pointers', + _buildMultipleWidgetPointers(context)), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + ), + ); + } + + /// Returns the text widget pointer sample. + Widget _buildTextWidgetPointer(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + axisTrackStyle: LinearAxisTrackStyle(thickness: 24), + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearWidgetPointer( + value: _textWidgetPointerValue, + onValueChanged: (value) => { + setState(() => {_textWidgetPointerValue = value}) + }, + child: Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: _brightness == Brightness.dark + ? Color(0xFFFFFFFF) + : Color(0xff06589C), + boxShadow: [ + BoxShadow( + color: _brightness == Brightness.light + ? Colors.grey + : Colors.black54, + offset: Offset(0.0, 1.0), //(x,y) + blurRadius: 6.0, + ), + ], + shape: BoxShape.circle), + child: Center( + child: Text(_textWidgetPointerValue.toStringAsFixed(0), + style: TextStyle( + fontWeight: FontWeight.bold, + color: _brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xffF45656), + )))), + ) + ])); + } + + /// Returns the icon widget pointer sample. + Widget _buildIconWidgetPointer(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + axisTrackStyle: LinearAxisTrackStyle(thickness: 24), + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearWidgetPointer( + value: _iconWidgetPointerValue, + onValueChanged: (value) => { + setState(() => {_iconWidgetPointerValue = value}) + }, + child: Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: _brightness == Brightness.dark + ? Color(0xFFFFFFFF) + : Color(0xff06589C), + boxShadow: [ + BoxShadow( + color: _brightness == Brightness.light + ? Colors.grey + : Colors.black54, + offset: Offset(0.0, 1.0), //(x,y) + blurRadius: 6.0, + ), + ], + shape: BoxShape.circle), + child: Center( + child: Icon( + Icons.thumb_up_rounded, + size: 20, + color: _brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xffF45656), + ))), + ) + ])); + } + + /// Returns the multiple widget pointers sample. + Widget _buildMultipleWidgetPointers(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + axisTrackStyle: LinearAxisTrackStyle(thickness: 24), + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + markerPointers: [ + LinearWidgetPointer( + value: _textPointerValue, + onValueChanged: (value) => { + setState(() => {_textPointerValue = value}) + }, + child: Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: _brightness == Brightness.dark + ? Color(0xFFFFFFFF) + : Color(0xff06589C), + boxShadow: [ + BoxShadow( + color: _brightness == Brightness.light + ? Colors.grey + : Colors.black54, + offset: Offset(0.0, 1.0), //(x,y) + blurRadius: 6.0, + ), + ], + shape: BoxShape.circle), + child: Center( + child: Text(_textPointerValue.toStringAsFixed(0), + style: TextStyle( + fontWeight: FontWeight.bold, + color: _brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xffF45656), + )))), + ), + LinearWidgetPointer( + value: _iconPointerValue, + onValueChanged: (value) => { + setState(() => {_iconPointerValue = value}) + }, + child: Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: _brightness == Brightness.dark + ? Color(0xFFFFFFFF) + : Color(0xff06589C), + boxShadow: [ + BoxShadow( + color: _brightness == Brightness.light + ? Colors.grey + : Colors.black54, + offset: Offset(0.0, 1.0), //(x,y) + blurRadius: 6.0, + ), + ], + shape: BoxShape.circle), + child: Center( + child: Icon( + Icons.thumb_up_rounded, + size: 20, + color: _brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xffF45656), + ))), + ) + ])); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/ranges/range_customization.dart b/lib/samples/linear_gauge/ranges/range_customization.dart new file mode 100644 index 00000000..6590cae1 --- /dev/null +++ b/lib/samples/linear_gauge/ranges/range_customization.dart @@ -0,0 +1,349 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge range customization sample. +class RangeCustomization extends SampleView { + /// Creates linear gauge with default and customized range styles + const RangeCustomization(Key key) : super(key: key); + + @override + _RangeCustomizationState createState() => _RangeCustomizationState(); +} + +/// State class of linear gauge range customization. +class _RangeCustomizationState extends SampleViewState { + bool _isHorizontalOrientation = true; + + @override + Widget build(BuildContext context) { + return Column(children: [ + Container(margin: EdgeInsets.all(32.0), child: _buildSegmentedView()), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: getScreenWidth(context, _isHorizontalOrientation), + child: _buildRange(context), + ) + ])))) + ]); + } + + /// Returns the linear gauge range. + Widget _buildRange(BuildContext context) { + return Container( + padding: EdgeInsets.fromLTRB(24.0, 0.0, 24.0, 32.0), + child: _isHorizontalOrientation + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHorizontalGauges('Default', _buildDefaultRange()), + _buildHorizontalGauges( + 'Exponential', _buildExponentialRange(context)), + _buildHorizontalGauges('Concave', _buildConcaveRange(context)), + _buildHorizontalGauges( + 'Gradient shader', _buildRangeShader(context)), + _buildHorizontalGauges( + 'Multiple ranges', _buildMultipleRanges(context)), + ], + ) + : Column( + children: [ + Wrap( + direction: Axis.horizontal, + runSpacing: 30, + spacing: 16, + alignment: WrapAlignment.center, + children: [ + _buildVerticalGauges('Default', _buildDefaultRange()), + _buildVerticalGauges( + 'Exponential', _buildExponentialRange(context)), + _buildVerticalGauges( + 'Concave', _buildConcaveRange(context)), + _buildVerticalGauges( + 'Gradient shader', _buildRangeShader(context)), + _buildVerticalGauges( + 'Multiple ranges', _buildMultipleRanges(context)), + ], + ), + ], + ), + ); + } + + /// Returns the horizontal axis track. + Widget _buildHorizontalGauges(String axisTrackName, Widget linearGauge) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(axisTrackName), + linearGauge, + SizedBox(height: 10), + ], + ); + } + + /// Returns the vertical axis track. + Widget _buildVerticalGauges(String axisTrackName, Widget linearGauge) { + return Container( + width: 150, + child: Column( + children: [Text(axisTrackName), SizedBox(height: 16), linearGauge], + ), + ); + } + + /// Returns the default range sample. + Widget _buildDefaultRange() { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + animateRange: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + ranges: [LinearGaugeRange()], + )); + } + + /// Returns the exponential range sample. + Widget _buildExponentialRange(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + animateRange: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + ranges: [ + LinearGaugeRange( + startValue: 0.0, + midValue: 50.0, + endValue: 100, + startWidth: 0, + midWidth: 10, + endWidth: 50), + ], + )); + } + + /// Returns the concave range sample. + Widget _buildConcaveRange(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 120 : 300, + child: SfLinearGauge( + animateAxis: true, + animateRange: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + ranges: [ + LinearGaugeRange( + startValue: 0.0, + midValue: 50.0, + endValue: 100, + startWidth: 70, + midWidth: -20, + endWidth: 70, + rangeShapeType: LinearRangeShapeType.curve, + ), + ], + )); + } + + /// Returns the range shader sample. + Widget _buildRangeShader(BuildContext context) { + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + animateAxis: true, + animateRange: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + ranges: [ + LinearGaugeRange( + startValue: 0.0, + midValue: 50.0, + endValue: 100, + startWidth: 40, + midWidth: 40, + endWidth: 40, + shaderCallback: (Rect bounds) { + return LinearGradient( + begin: _isHorizontalOrientation + ? Alignment.centerLeft + : Alignment.topCenter, + end: _isHorizontalOrientation + ? Alignment.centerRight + : Alignment.bottomCenter, + colors: [ + Color(0xff42C09A), + Color(0xffE8DA5D), + Color(0xffFB7D55), + ], + stops: [ + 0.1, + 0.4, + 0.8 + ]).createShader(bounds); + }, + ), + ], + )); + } + + /// Returns the multiple ranges sample. + Widget _buildMultipleRanges(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Container( + height: _isHorizontalOrientation ? 100 : 300, + child: SfLinearGauge( + minimum: 0, + maximum: 100, + animateAxis: true, + animateRange: true, + orientation: _isHorizontalOrientation + ? LinearGaugeOrientation.horizontal + : LinearGaugeOrientation.vertical, + ranges: [ + LinearGaugeRange( + startValue: 0.0, + endValue: 30, + startWidth: 40, + midWidth: 40, + endWidth: 40, + child: Container( + color: _brightness == Brightness.light + ? Color(0xffF45656) + : Color(0xffFF7B7B)), + ), + LinearGaugeRange( + startValue: 30.0, + endValue: 65, + startWidth: 40, + midWidth: 40, + endWidth: 40, + child: Container( + color: _brightness == Brightness.light + ? Color(0xffFFC93E) + : Color(0xffFFC93E)), + ), + LinearGaugeRange( + startValue: 65.0, + endValue: 100, + startWidth: 40, + midWidth: 40, + endWidth: 40, + child: Container( + color: _brightness == Brightness.light + ? Color(0xff0DC9AB) + : Color(0xff0DC9AB)), + ), + LinearGaugeRange( + startValue: 0, + endValue: 30, + startWidth: 40, + endWidth: 40, + color: Colors.transparent, + child: RotatedBox( + quarterTurns: _isHorizontalOrientation ? 0 : 3, + child: Container( + child: Center( + child: Text( + 'Bad', + style: TextStyle( + fontFamily: 'Roboto-Medium', + fontWeight: FontWeight.w500, + color: Color(0xff191A1B)), + )))), + ), + LinearGaugeRange( + startValue: 30, + endValue: 65, + startWidth: 40, + endWidth: 40, + color: Colors.transparent, + child: RotatedBox( + quarterTurns: _isHorizontalOrientation ? 0 : 3, + child: Container( + height: 20, + child: Center( + child: Text( + 'Good', + style: TextStyle( + fontFamily: 'Roboto-Medium', + fontWeight: FontWeight.w500, + color: Color(0xff191A1B)), + )))), + ), + LinearGaugeRange( + startValue: 65, + endValue: 100, + startWidth: 40, + endWidth: 40, + color: Colors.transparent, + child: RotatedBox( + quarterTurns: _isHorizontalOrientation ? 0 : 3, + child: Container( + height: 20, + child: Center( + child: Text( + 'Excellent', + style: TextStyle( + fontFamily: 'Roboto-Medium', + fontWeight: FontWeight.w500, + color: Color(0xff191A1B)), + )))), + ) + ], + )); + } + + /// Returns the segmented view for linear gauge orientation. + Widget _buildSegmentedView() { + return Center( + child: CupertinoSegmentedControl( + selectedColor: model.backgroundColor, + borderColor: model.backgroundColor, + children: { + true: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Horizontal', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.white + : Colors.black), + )), + false: Container( + padding: EdgeInsets.all(10.0), + child: Text( + 'Vertical', + style: TextStyle( + color: _isHorizontalOrientation + ? Colors.black + : Colors.white), + )), + }, + onValueChanged: (bool value) => + setState(() => {_isHorizontalOrientation = value}), + groupValue: _isHorizontalOrientation)); + } +} diff --git a/lib/samples/linear_gauge/showcase/battery_indicator.dart b/lib/samples/linear_gauge/showcase/battery_indicator.dart new file mode 100644 index 00000000..91157d6d --- /dev/null +++ b/lib/samples/linear_gauge/showcase/battery_indicator.dart @@ -0,0 +1,197 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge battery indicator showcase sample. +class BatteryIndicator extends SampleView { + /// Creates the linear gauge battery indicator showcase sample. + const BatteryIndicator(Key key) : super(key: key); + + @override + _BatteryIndicatorState createState() => _BatteryIndicatorState(); +} + +/// State class of battery indicator showcase sample. +class _BatteryIndicatorState extends SampleViewState { + _BatteryIndicatorState(); + + final double _minimum = 0; + final double _maximum = 100; + final double _batteryPercentage = 75; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildBatteryIndicator(context), + )) + : Center(child: _buildBatteryIndicator(context)); + } + + /// Returns the battery indicator. + Widget _buildBatteryIndicator(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + final Color? _fillColor = _batteryPercentage <= 25 + ? Color(0xffF45656) + : _batteryPercentage <= 50 + ? Color(0xffFFC93E) + : Colors.green[400]; + return Container( + width: 145, + child: SfLinearGauge( + minimum: _minimum, + maximum: _maximum, + showLabels: false, + showTicks: false, + tickPosition: LinearElementPosition.cross, + majorTickStyle: LinearTickStyle(color: Colors.green, length: 20), + minorTickStyle: LinearTickStyle(color: Colors.red, length: 10), + axisTrackStyle: + LinearAxisTrackStyle(thickness: 1, color: Colors.transparent), + ranges: [ + LinearGaugeRange( + startValue: _minimum, + startWidth: 70, + endWidth: 70, + color: Colors.transparent, + endValue: _maximum - 2, + position: LinearElementPosition.cross, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + shape: BoxShape.rectangle, + border: Border.all( + color: _brightness == Brightness.light + ? Color(0xffAAAAAA) + : Color(0xff4D4D4D), + width: 4), + borderRadius: BorderRadius.all(Radius.circular(12))))), + LinearGaugeRange( + startValue: _minimum + 5, + startWidth: 55, + endWidth: 55, + endValue: _batteryPercentage < _maximum / 4 + ? _batteryPercentage + : _maximum / 4, + position: LinearElementPosition.cross, + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: _fillColor, + borderRadius: BorderRadius.circular(4)))), + LinearGaugeRange( + startValue: _batteryPercentage >= (_maximum / 4 + 2) + ? (_maximum / 4 + 2) + : _minimum + 5, + endValue: _batteryPercentage < (_maximum / 4 + 2) + ? _minimum + 5 + : _batteryPercentage <= _maximum / 2 + ? _batteryPercentage + : _maximum / 2, + startWidth: 55, + endWidth: 55, + position: LinearElementPosition.cross, + edgeStyle: LinearEdgeStyle.bothFlat, + rangeShapeType: LinearRangeShapeType.flat, + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: _fillColor, + borderRadius: BorderRadius.circular(4)))), + LinearGaugeRange( + startValue: _batteryPercentage >= (_maximum / 2 + 2) + ? (_maximum / 2 + 2) + : _minimum + 5, + endValue: _batteryPercentage < (_maximum / 2 + 2) + ? _minimum + 5 + : _batteryPercentage <= (_maximum * 3 / 4) + ? _batteryPercentage + : (_maximum * 3 / 4), + startWidth: 55, + endWidth: 55, + position: LinearElementPosition.cross, + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: _fillColor, + borderRadius: BorderRadius.circular(4)))), + LinearGaugeRange( + startValue: _batteryPercentage >= (_maximum * 3 / 4 + 2) + ? (_maximum * 3 / 4 + 2) + : _minimum + 5, + endValue: _batteryPercentage < (_maximum * 3 / 4 + 2) + ? _minimum + 5 + : _batteryPercentage < _maximum + ? _batteryPercentage + : _maximum - 7, + startWidth: 55, + endWidth: 55, + position: LinearElementPosition.cross, + color: Colors.transparent, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: _fillColor, + borderRadius: BorderRadius.circular(4)))), + ], + markerPointers: [ + LinearWidgetPointer( + value: _maximum, + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.start, + child: Container( + height: 38, + width: 16, + decoration: BoxDecoration( + color: _brightness == Brightness.light + ? Colors.transparent + : Color(0xff232323), + shape: BoxShape.rectangle, + border: Border.all( + color: _brightness == Brightness.light + ? Color(0xffAAAAAA) + : Color(0xff4D4D4D), + width: 4), + borderRadius: BorderRadius.only( + topRight: Radius.circular(6), + bottomRight: Radius.circular(6))))) + ], + barPointers: [ + LinearBarPointer( + value: 100, + thickness: 30, + position: LinearElementPosition.outside, + offset: 50, + enableAnimation: false, + color: Colors.transparent, + child: Center( + child: Text( + 'Charged: ' + _batteryPercentage.toStringAsFixed(0) + '%', + style: TextStyle( + fontSize: + (defaultTargetPlatform == TargetPlatform.macOS || + defaultTargetPlatform == TargetPlatform.iOS) + ? 18 + : 20, + fontWeight: FontWeight.w500)), + ), + ), + ], + )); + } +} diff --git a/lib/samples/linear_gauge/showcase/heat_meter.dart b/lib/samples/linear_gauge/showcase/heat_meter.dart new file mode 100644 index 00000000..5b0507c4 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/heat_meter.dart @@ -0,0 +1,100 @@ +// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge heat meter sample. +class HeatMeter extends SampleView { + /// Creates the linear gauge heat meter sample. + const HeatMeter(Key key) : super(key: key); + + @override + _HeatMeterState createState() => _HeatMeterState(); +} + +/// State class of heat meter sample. +class _HeatMeterState extends SampleViewState { + double _widgetPointerWithGradientValue = 60; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildHeatMeter(context), + )) + : _buildHeatMeter(context); + } + + /// Returns the heat meter. + Widget _buildHeatMeter(BuildContext context) { + return SfLinearGauge( + minimum: 0.0, + maximum: 80.0, + interval: 20.0, + minorTicksPerInterval: 0, + animateAxis: true, + labelFormatterCallback: (value) { + return value + '°c'; + }, + axisTrackStyle: LinearAxisTrackStyle(thickness: 1), + barPointers: [ + LinearBarPointer( + value: 80, + thickness: 24, + position: LinearElementPosition.outside, + shaderCallback: (Rect bounds) { + return LinearGradient(colors: [ + Colors.green, + Colors.orange, + Colors.red + ], stops: [ + 0.1, + 0.4, + 0.9, + ]).createShader(bounds); + }), + ], + markerPointers: [ + LinearWidgetPointer( + value: _widgetPointerWithGradientValue, + offset: 26, + position: LinearElementPosition.outside, + child: Container( + width: 55, + height: 45, + child: Center( + child: Text( + _widgetPointerWithGradientValue.toStringAsFixed(0) + '°C', + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 14, + color: _widgetPointerWithGradientValue < 20 + ? Colors.green + : _widgetPointerWithGradientValue < 60 + ? Colors.orange + : Colors.red), + )))), + LinearShapePointer( + offset: 25, + onValueChanged: (value) => { + setState(() => {_widgetPointerWithGradientValue = value}) + }, + value: _widgetPointerWithGradientValue, + color: _widgetPointerWithGradientValue < 20 + ? Colors.green + : _widgetPointerWithGradientValue < 60 + ? Colors.orange + : Colors.red, + ), + ]); + } +} diff --git a/lib/samples/linear_gauge/showcase/height_calculator.dart b/lib/samples/linear_gauge/showcase/height_calculator.dart new file mode 100644 index 00000000..494c9d39 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/height_calculator.dart @@ -0,0 +1,160 @@ +// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge height calculator sample. +class HeightCalculator extends SampleView { + /// Creates the linear gauge height calculator sample. + const HeightCalculator(Key key) : super(key: key); + + @override + _HeightCalculatorState createState() => _HeightCalculatorState(); +} + +class _HeightCalculatorState extends SampleViewState { + _HeightCalculatorState(); + double _pointerValue = 130; + double minimumLevel = 0; + double maximumLevel = 200; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + height: 500, + child: _buildHeightCalculator(context), + )) + : _buildHeightCalculator(context); + } + + /// Returns the height calculator. + Widget _buildHeightCalculator(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Padding( + padding: EdgeInsets.all(10), + child: Center( + child: Container( + height: isCardView + ? MediaQuery.of(context).size.height + : MediaQuery.of(context).size.height * 3 / 4, + padding: EdgeInsets.all(5.0), + child: SfLinearGauge( + orientation: LinearGaugeOrientation.vertical, + minimum: 0, + maximum: maximumLevel, + tickPosition: LinearElementPosition.outside, + labelPosition: LinearLabelPosition.outside, + minorTicksPerInterval: 0, + interval: isCardView ? 50 : 25, + onGenerateLabels: () { + return isCardView + ? [ + LinearAxisLabel(text: '0 cm', value: 0), + LinearAxisLabel(text: '50 cm', value: 50), + LinearAxisLabel(text: '100 cm', value: 100), + LinearAxisLabel(text: '150 cm', value: 150), + LinearAxisLabel(text: '200 cm', value: 200), + ] + : [ + LinearAxisLabel(text: '0 cm', value: 0), + LinearAxisLabel(text: '25 cm', value: 25), + LinearAxisLabel(text: '50 cm', value: 50), + LinearAxisLabel(text: '75 cm', value: 75), + LinearAxisLabel(text: '100 cm', value: 100), + LinearAxisLabel(text: '125 cm', value: 125), + LinearAxisLabel(text: '150 cm', value: 150), + LinearAxisLabel(text: '175 cm', value: 175), + LinearAxisLabel(text: '200 cm', value: 200), + ]; + }, + axisTrackStyle: LinearAxisTrackStyle(thickness: 5.0), + markerPointers: [ + LinearShapePointer( + value: _pointerValue, + enableAnimation: false, + onValueChanged: (value) => { + setState(() => {_pointerValue = value}) + }, + position: LinearElementPosition.outside, + shapeType: LinearShapePointerType.rectangle, + color: Color(0xff0074E3), + height: 1.5, + width: isCardView ? 150 : 250), + LinearWidgetPointer( + value: _pointerValue, + enableAnimation: false, + position: LinearElementPosition.cross, + onValueChanged: (value) => { + setState(() { + _pointerValue = value; + }) + }, + child: Container( + width: 24, + height: 16, + child: Image.asset( + 'images/rectangle_pointer.png', + ))), + LinearWidgetPointer( + value: _pointerValue, + markerAlignment: LinearMarkerAlignment.center, + enableAnimation: false, + onValueChanged: (value) => { + setState(() => {_pointerValue = value}) + }, + offset: isCardView ? 150 : 230, + position: LinearElementPosition.outside, + child: Container( + width: 60, + height: 25, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: model.cardColor, + boxShadow: [ + BoxShadow( + color: _brightness == Brightness.light + ? Colors.grey + : Colors.black54, + offset: Offset(0.0, 1.0), //(x,y) + blurRadius: 6.0, + ), + ], + borderRadius: BorderRadius.circular(4)), + child: Center( + child: Text( + _pointerValue.toStringAsFixed(0) + ' cm', + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + color: Color(0xff0074E3))), + ))), + ], + ranges: [ + LinearGaugeRange( + endValue: _pointerValue, + startWidth: 200, + midWidth: isCardView ? 200 : 300, + endWidth: 200, + color: Colors.transparent, + child: Image.asset( + _brightness == Brightness.light + ? 'images/bmi_light.png' + : 'images/bmi_dark.png', + fit: BoxFit.fitHeight, + ), + ), + ], + )))); + } +} diff --git a/lib/samples/linear_gauge/showcase/progress_bar.dart b/lib/samples/linear_gauge/showcase/progress_bar.dart new file mode 100644 index 00000000..b1696abd --- /dev/null +++ b/lib/samples/linear_gauge/showcase/progress_bar.dart @@ -0,0 +1,86 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the progress bar showcase sample. +class ProgressBar extends SampleView { + /// Creates the progress bar showcase sample. + const ProgressBar(Key key) : super(key: key); + + @override + _ProgressBarState createState() => _ProgressBarState(); +} + +/// State class of progress bar sample. +class _ProgressBarState extends SampleViewState { + _ProgressBarState(); + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildProgressBar(context), + )) + : _buildProgressBar(context); + } + + /// Returns the progress bar. + Widget _buildProgressBar(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + final double _progressvalue = 41.467; + + return Stack(children: [ + Padding( + padding: EdgeInsets.all(20), + child: Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + child: Container( + height: 30, + child: SfLinearGauge( + orientation: LinearGaugeOrientation.horizontal, + minimum: 0.0, + maximum: 100.0, + showTicks: false, + showLabels: false, + animateAxis: true, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 30, + edgeStyle: LinearEdgeStyle.bothCurve, + borderWidth: 1, + borderColor: _brightness == Brightness.dark + ? Color(0xff898989) + : Colors.grey[350], + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + barPointers: [ + LinearBarPointer( + value: _progressvalue, + thickness: 30, + edgeStyle: LinearEdgeStyle.bothCurve, + color: Colors.blue), + ], + ))))), + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.all(30), + child: Text( + _progressvalue.toStringAsFixed(2) + '%', + style: TextStyle(fontSize: 14, color: Color(0xffFFFFFF)), + ))), + ]); + } +} diff --git a/lib/samples/linear_gauge/showcase/sleep_watch_score.dart b/lib/samples/linear_gauge/showcase/sleep_watch_score.dart new file mode 100644 index 00000000..e9da2514 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/sleep_watch_score.dart @@ -0,0 +1,348 @@ +import 'package:flutter/foundation.dart'; + +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge sleep watch showcase sample. +class SleepWatch extends SampleView { + /// Creates the linear gauge sleep watch showcase sample. + const SleepWatch(Key key) : super(key: key); + + @override + _SleepWatchState createState() => _SleepWatchState(); +} + +/// State class of sleep watch showcase sample. +class _SleepWatchState extends SampleViewState { + _SleepWatchState(); + + double _todayValue = 280; + double _overallValue = 410; + + @override + Widget build(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Padding( + padding: EdgeInsets.all(10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: (defaultTargetPlatform == TargetPlatform.macOS || + defaultTargetPlatform == TargetPlatform.iOS) + ? 54 + : null, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'TODAY', + style: TextStyle( + fontSize: 10, fontWeight: FontWeight.w500), + ), + Text( + _todayValue.toStringAsFixed(0), + style: TextStyle( + fontSize: 26, + color: _todayValue < 200 + ? Colors.red + : _todayValue < 300 + ? Colors.amber + : _todayValue < 400 + ? Color(0xffFB7D55) + : Color(0xff0DC9AB), + fontWeight: FontWeight.bold), + ) + ], + )), + Container( + width: isWebOrDesktop + ? MediaQuery.of(context).size.width >= 550 + ? 450 + : MediaQuery.of(context).size.width * 0.68 + : MediaQuery.of(context).size.width * 0.70, + child: SfLinearGauge( + orientation: LinearGaugeOrientation.horizontal, + minimum: 100.0, + maximum: 500.0, + interval: 50.0, + animateAxis: true, + animateRange: true, + showLabels: false, + showTicks: false, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 15, + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + markerPointers: [ + LinearShapePointer( + value: _todayValue, + onValueChanged: (value) => { + setState(() => {_todayValue = value}) + }, + height: 20, + width: 20, + color: _todayValue < 200 + ? Colors.red + : _todayValue < 300 + ? Colors.amber + : _todayValue < 400 + ? Color(0xffFB7D55) + : Color(0xff0DC9AB), + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle), + LinearWidgetPointer( + value: 150, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Poor', + style: TextStyle( + fontSize: 12, + ), + ), + ), + LinearWidgetPointer( + value: 250, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Fair', + style: TextStyle(fontSize: 12), + ), + ), + LinearWidgetPointer( + value: 350, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Good', + style: TextStyle(fontSize: 12), + ), + ), + LinearWidgetPointer( + value: 450, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Excellent', + style: TextStyle(fontSize: 12), + ), + ) + ], + ranges: [ + LinearGaugeRange( + startValue: 100.0, + endValue: 200, + startWidth: 8, + midWidth: 8, + endWidth: 8, + position: LinearElementPosition.cross, + color: Colors.red, + ), + LinearGaugeRange( + startValue: 200.0, + endValue: 300, + startWidth: 8, + position: LinearElementPosition.cross, + midWidth: 8, + endWidth: 8, + color: Colors.amber, + ), + LinearGaugeRange( + startValue: 300.0, + endValue: 400, + position: LinearElementPosition.cross, + startWidth: 8, + midWidth: 8, + endWidth: 8, + color: Color(0xffFB7D55), + ), + LinearGaugeRange( + startValue: 400.0, + endValue: 500, + position: LinearElementPosition.cross, + startWidth: 8, + midWidth: 8, + endWidth: 8, + color: Color(0xff0DC9AB), + ), + ])) + ], + ), + SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: (defaultTargetPlatform == TargetPlatform.macOS || + defaultTargetPlatform == TargetPlatform.iOS) + ? 54 + : null, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'OVERALL', + style: TextStyle( + fontSize: 10, fontWeight: FontWeight.w500), + ), + Text( + _overallValue.toStringAsFixed(0), + style: TextStyle( + fontSize: 26, + color: _overallValue < 200 + ? Colors.red + : _overallValue < 300 + ? Colors.amber + : _overallValue < 400 + ? Color(0xffFB7D55) + : Color(0xff0DC9AB), + fontWeight: FontWeight.bold), + ) + ], + )), + Container( + width: isWebOrDesktop + ? MediaQuery.of(context).size.width >= 550 + ? 450 + : MediaQuery.of(context).size.width * 0.68 + : MediaQuery.of(context).size.width * 0.70, + child: SfLinearGauge( + orientation: LinearGaugeOrientation.horizontal, + minimum: 100.0, + maximum: 500.0, + interval: 50.0, + animateAxis: true, + animateRange: true, + showTicks: false, + showLabels: false, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 15, + edgeStyle: LinearEdgeStyle.bothFlat, + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + markerPointers: [ + LinearShapePointer( + value: _overallValue, + onValueChanged: (value) => { + setState(() => {_overallValue = value}) + }, + height: 20, + width: 20, + color: _overallValue < 200 + ? Colors.red + : _overallValue < 300 + ? Colors.amber + : _overallValue < 400 + ? Color(0xffFB7D55) + : Color(0xff0DC9AB), + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle), + LinearWidgetPointer( + value: 150, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Poor', + style: TextStyle(fontSize: 12), + ), + ), + LinearWidgetPointer( + value: 250, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Fair', + style: TextStyle(fontSize: 12), + ), + ), + LinearWidgetPointer( + value: 350, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Good', + style: TextStyle(fontSize: 12), + ), + ), + LinearWidgetPointer( + value: 450, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 4, + child: Text( + 'Excellent', + style: TextStyle(fontSize: 12), + ), + ) + ], + ranges: [ + LinearGaugeRange( + startValue: 100.0, + endValue: 200, + startWidth: 8, + midWidth: 8, + position: LinearElementPosition.cross, + endWidth: 8, + color: Colors.red, + ), + LinearGaugeRange( + startValue: 200.0, + endValue: 300, + startWidth: 8, + midWidth: 8, + endWidth: 8, + position: LinearElementPosition.cross, + color: Colors.amber, + ), + LinearGaugeRange( + startValue: 300.0, + endValue: 400, + startWidth: 8, + midWidth: 8, + endWidth: 8, + position: LinearElementPosition.cross, + color: Color(0xffFB7D55), + ), + LinearGaugeRange( + startValue: 400.0, + endValue: 500, + startWidth: 8, + midWidth: 8, + endWidth: 8, + position: LinearElementPosition.cross, + color: Color(0xff0DC9AB), + ), + ])) + ], + ), + ], + ), + ); + } +} diff --git a/lib/samples/linear_gauge/showcase/steps_counter.dart b/lib/samples/linear_gauge/showcase/steps_counter.dart new file mode 100644 index 00000000..3e0ac73e --- /dev/null +++ b/lib/samples/linear_gauge/showcase/steps_counter.dart @@ -0,0 +1,137 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge steps counter sample. +class StepsCounter extends SampleView { + /// Creates the linear gauge steps counter sample. + const StepsCounter(Key key) : super(key: key); + + @override + _StepsCounterState createState() => _StepsCounterState(); +} + +/// State class of steps counter sample. +class _StepsCounterState extends SampleViewState { + _StepsCounterState(); + final double _pointerValue = 8456; + String _image = 'images/person_walking.gif'; + + @override + void didChangeDependencies() { + precacheImage(AssetImage('images/person_walking.png'), context); + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + child: _buildStepsCounter(context), + )) + : _buildStepsCounter(context); + } + + /// Returns the steps counter. + Widget _buildStepsCounter(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Padding( + padding: EdgeInsets.all(10), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: isWebOrDesktop + ? MediaQuery.of(context).size.width >= 550 + ? 450 + : MediaQuery.of(context).size.width * 0.68 + : MediaQuery.of(context).size.width * 0.68, + child: SfLinearGauge( + minimum: 0.0, + maximum: 12000.0, + interval: 12000.0, + animateAxis: true, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 32, + borderWidth: 1, + borderColor: _brightness == Brightness.dark + ? Color(0xff898989) + : Colors.grey[350], + color: _brightness == Brightness.light + ? Color(0xffE8EAEB) + : Color(0xff62686A), + ), + barPointers: [ + LinearBarPointer( + value: _pointerValue, + animationDuration: 3000, + thickness: 32, + color: Color(0xff0DC9AB)), + LinearBarPointer( + value: 12000, + enableAnimation: false, + thickness: 25, + offset: isWebOrDesktop + ? (MediaQuery.of(context).size.height >= 50 ? 60 : 0) + : 60, + color: Colors.transparent, + position: LinearElementPosition.outside, + child: Container( + child: Text('Sun, 7 February', + style: TextStyle( + fontSize: 18, fontWeight: FontWeight.w500)))), + ], + markerPointers: [ + LinearWidgetPointer( + value: _pointerValue, + animationDuration: 2800, + onAnimationCompleted: () => { + setState(() { + _image = 'images/person_walking.png'; + }) + }, + position: LinearElementPosition.outside, + child: Container( + width: 45, + height: 45, + child: Image.asset( + _image, + fit: BoxFit.fitHeight, + ), + )), + ], + ), + ), + Container( + margin: EdgeInsets.only(top: 65), + child: + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text( + 'STEPS', + style: TextStyle(fontSize: 10, fontWeight: FontWeight.w500), + ), + Text( + _pointerValue.toStringAsFixed(0), + style: TextStyle( + fontSize: 24, + color: Color(0xff0DC9AB), + fontWeight: FontWeight.bold), + ) + ]), + ) + ], + ), + ); + } +} diff --git a/lib/samples/linear_gauge/showcase/task_tracker.dart b/lib/samples/linear_gauge/showcase/task_tracker.dart new file mode 100644 index 00000000..b3da692e --- /dev/null +++ b/lib/samples/linear_gauge/showcase/task_tracker.dart @@ -0,0 +1,101 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the task tracking showcase sample. +class TaskTracking extends SampleView { + /// Creates the task tracking showcase sample. + const TaskTracking(Key key) : super(key: key); + + @override + _TaskTrackingState createState() => _TaskTrackingState(); +} + +/// State class of task tracking sample. +class _TaskTrackingState extends SampleViewState { + _TaskTrackingState(); + double _pointerValue = 60; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildTaskTracker(context), + )) + : _buildTaskTracker(context); + } + + /// Returns the task tracker. + Widget _buildTaskTracker(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Padding( + padding: EdgeInsets.all(10), + child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + SfLinearGauge( + interval: 20, + animateAxis: true, + animateRange: true, + labelPosition: LinearLabelPosition.outside, + tickPosition: LinearElementPosition.outside, + onGenerateLabels: () { + return [ + LinearAxisLabel(text: 'Mar 19', value: 0), + LinearAxisLabel(text: 'Jul 19', value: 20), + LinearAxisLabel(text: 'Oct 19', value: 40), + LinearAxisLabel(text: 'Jan 20', value: 60), + LinearAxisLabel(text: 'Apr 20', value: 80), + LinearAxisLabel(text: 'Jul 20', value: 100), + ]; + }, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 16, color: Colors.transparent), + markerPointers: [ + LinearShapePointer( + value: _pointerValue, + onValueChanged: (value) => { + setState(() => {_pointerValue = value}) + }, + color: _brightness == Brightness.light + ? Color(0xff06589C) + : Color(0xffFFFFFF), + width: 24, + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.triangle, + height: 16), + ], + ranges: [ + LinearGaugeRange( + startValue: 0.0, + midValue: 0, + endValue: 80, + startWidth: 16, + midWidth: 16, + endWidth: 16, + position: LinearElementPosition.cross, + color: Color(0xff0DC9AB), + ), + LinearGaugeRange( + startValue: 80.0, + midValue: 0, + endValue: 100, + startWidth: 16, + midWidth: 16, + endWidth: 16, + position: LinearElementPosition.cross, + color: Color(0xffF45656), + ) + ]) + ])); + } +} diff --git a/lib/samples/linear_gauge/showcase/thermometer.dart b/lib/samples/linear_gauge/showcase/thermometer.dart new file mode 100644 index 00000000..fe8c1830 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/thermometer.dart @@ -0,0 +1,216 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge thermometer sample. +class Thermometer extends SampleView { + /// Creates the linear gauge thermometer sample. + const Thermometer(Key key) : super(key: key); + + @override + _ThermometerState createState() => _ThermometerState(); +} + +/// State class of thermometer sample. +class _ThermometerState extends SampleViewState { + double _meterValue = 35; + final double _temperatureValue = 37.5; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + height: 300, + child: _buildThermometer(context), + )) + : _buildThermometer(context); + } + + /// Returns the thermometer. + Widget _buildThermometer(BuildContext context) { + final Orientation orientation = MediaQuery.of(context).orientation; + final Brightness brightness = Theme.of(context).brightness; + + return Center( + child: Container( + height: isCardView + ? MediaQuery.of(context).size.height + : orientation == Orientation.portrait + ? MediaQuery.of(context).size.height / 2 + : MediaQuery.of(context).size.height * 3 / 4, + child: Padding( + padding: EdgeInsets.fromLTRB(0, 10, 0, 10), + child: Padding( + padding: EdgeInsets.only(bottom: 11), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /// Linear gauge to display celsius scale. + SfLinearGauge( + minimum: -20, + maximum: 50, + interval: 10, + minorTicksPerInterval: 0, + axisTrackExtent: 23, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 12, + color: model.cardThemeColor, + borderWidth: 1, + edgeStyle: LinearEdgeStyle.bothCurve), + tickPosition: LinearElementPosition.outside, + labelPosition: LinearLabelPosition.outside, + orientation: LinearGaugeOrientation.vertical, + markerPointers: [ + LinearWidgetPointer( + markerAlignment: LinearMarkerAlignment.end, + value: 50, + enableAnimation: false, + position: LinearElementPosition.outside, + offset: 8, + child: Container( + height: 30, + child: Text( + '°C', + style: TextStyle( + fontSize: isWebOrDesktop ? 14 : 12, + fontWeight: FontWeight.normal), + ), + )), + LinearShapePointer( + value: -20, + markerAlignment: LinearMarkerAlignment.start, + shapeType: LinearShapePointerType.circle, + borderWidth: 1, + borderColor: brightness == Brightness.dark + ? Colors.white30 + : Colors.black26, + color: model.cardThemeColor, + position: LinearElementPosition.cross, + width: 24, + height: 24, + ), + LinearShapePointer( + value: -20, + markerAlignment: LinearMarkerAlignment.start, + shapeType: LinearShapePointerType.circle, + borderWidth: 6, + borderColor: Colors.transparent, + color: _meterValue > _temperatureValue + ? Color(0xffFF7B7B) + : Color(0xff0074E3), + position: LinearElementPosition.cross, + width: 24, + height: 24, + ), + LinearWidgetPointer( + value: -20, + markerAlignment: LinearMarkerAlignment.start, + child: Container( + width: 10, + height: 3.4, + decoration: BoxDecoration( + border: Border( + left: BorderSide( + width: 2.0, + color: model.cardThemeColor), + right: BorderSide( + width: 2.0, + color: model.cardThemeColor), + ), + color: _meterValue > _temperatureValue + ? Color(0xffFF7B7B) + : Color(0xff0074E3), + ), + )), + LinearWidgetPointer( + value: _meterValue, + enableAnimation: false, + position: LinearElementPosition.outside, + onValueChanged: (value) => { + setState(() { + _meterValue = value; + }) + }, + child: Container( + width: 16, + height: 12, + transform: + Matrix4.translationValues(4, 0, 0.0), + child: Image.asset( + 'images/triangle_pointer.png', + color: _meterValue > _temperatureValue + ? Color(0xffFF7B7B) + : Color(0xff0074E3), + ))), + LinearShapePointer( + value: _meterValue, + width: 20, + height: 20, + enableAnimation: false, + color: Colors.transparent, + position: LinearElementPosition.cross, + onValueChanged: (value) => { + setState(() { + _meterValue = value; + }) + }, + ) + ], + barPointers: [ + LinearBarPointer( + value: _meterValue, + enableAnimation: false, + thickness: 6, + edgeStyle: LinearEdgeStyle.endCurve, + color: _meterValue > _temperatureValue + ? Color(0xffFF7B7B) + : Color(0xff0074E3), + ) + ]), + + /// Linear gauge to display Fahrenheit scale. + Container( + transform: Matrix4.translationValues(-6, 0, 0.0), + child: SfLinearGauge( + minimum: 0, + maximum: 120, + showAxisTrack: false, + interval: 20, + minorTicksPerInterval: 0, + axisTrackExtent: 24, + axisTrackStyle: + LinearAxisTrackStyle(thickness: 0), + orientation: LinearGaugeOrientation.vertical, + markerPointers: [ + LinearWidgetPointer( + markerAlignment: LinearMarkerAlignment.end, + value: 120, + position: LinearElementPosition.inside, + offset: 6, + enableAnimation: false, + child: Container( + height: 30, + child: Text( + '°F', + style: TextStyle( + fontSize: isWebOrDesktop ? 14 : 12, + fontWeight: FontWeight.normal), + ), + )), + ], + )) + ], + ))))); + } +} diff --git a/lib/samples/linear_gauge/showcase/volume_settings.dart b/lib/samples/linear_gauge/showcase/volume_settings.dart new file mode 100644 index 00000000..958efad0 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/volume_settings.dart @@ -0,0 +1,278 @@ +/// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; + +/// Renders the linear gauge volume settings showcase sample. +class VolumeSettings extends SampleView { + /// Creates the linear gauge volume settings showcase sample. + const VolumeSettings(Key key) : super(key: key); + + @override + _VolumeSettingsState createState() => _VolumeSettingsState(); +} + +/// State class of volume settings sample. +class _VolumeSettingsState extends SampleViewState { + _VolumeSettingsState(); + double _musicValue = 100.0; + double _ringValue = 85.0; + double _alarmValue = 65.0; + + @override + Widget build(BuildContext context) { + final Orientation orientation = MediaQuery.of(context).orientation; + return isCardView + ? _buildVolumeControl() + : Center( + child: Container( + height: orientation == Orientation.landscape + ? MediaQuery.of(context).size.height / 2 + : MediaQuery.of(context).size.height / 3, + child: _buildVolumeControl(), + )); + } + + /// Returns the volume settings. + Widget _buildVolumeControl() { + final Brightness _brightness = Theme.of(context).brightness; + + return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Container( + height: isCardView ? 205 : 240, + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(20.0)), + child: SfLinearGauge( + orientation: LinearGaugeOrientation.vertical, + interval: 20.0, + showTicks: false, + showLabels: false, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + borderWidth: 1, + borderColor: _brightness == Brightness.dark + ? Color(0xff898989) + : Colors.grey[350], + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + barPointers: [ + LinearBarPointer( + enableAnimation: false, + value: _musicValue, + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + color: Colors.blueAccent) + ], + markerPointers: [ + LinearWidgetPointer( + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + value: 100, + child: Container( + height: 25, + child: Text(_musicValue.toStringAsFixed(0) + '%'), + )), + LinearWidgetPointer( + value: 5, + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + child: GestureDetector( + onTap: () { + setState(() { + _musicValue = 0; + }); + }, + child: Container( + height: 30, + width: 30, + child: Center( + child: Icon( + _musicValue > 0 + ? Icons.music_note + : Icons.music_off, + color: Color(0xffFFFFFF), + )))), + ), + LinearShapePointer( + enableAnimation: false, + value: _musicValue - 20, + onValueChanged: (value) => { + setState(() { + _musicValue = value; + }) + }, + color: Colors.transparent, + width: 40, + markerAlignment: LinearMarkerAlignment.end, + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle, + height: 40), + ], + )), + ), + SizedBox( + width: 25, + ), + Container( + height: isCardView ? 205 : 240, + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(20.0)), + child: SfLinearGauge( + orientation: LinearGaugeOrientation.vertical, + interval: 20.0, + showTicks: false, + showLabels: false, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + borderWidth: 1, + borderColor: _brightness == Brightness.dark + ? Color(0xff898989) + : Colors.grey[350], + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + barPointers: [ + LinearBarPointer( + enableAnimation: false, + value: _ringValue, + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + color: Colors.blueAccent) + ], + markerPointers: [ + LinearWidgetPointer( + value: 5, + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + child: Container( + height: 30, + width: 30, + child: GestureDetector( + onTap: () { + setState(() { + _ringValue = 0; + }); + }, + child: Center( + child: Icon( + _ringValue > 0 + ? Icons.notifications + : Icons.notifications_off, + color: Color(0xffFFFFFF), + )))), + ), + LinearWidgetPointer( + markerAlignment: LinearMarkerAlignment.end, + value: 100, + enableAnimation: false, + child: Container( + height: 25, + child: Text(_ringValue.toStringAsFixed(0) + '%'), + )), + LinearShapePointer( + value: _ringValue - 20, + enableAnimation: false, + onValueChanged: (value) => { + setState(() { + _ringValue = value; + }) + }, + color: Colors.transparent, + width: 40, + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle, + markerAlignment: LinearMarkerAlignment.end, + height: 40), + ]))), + SizedBox( + width: 25, + ), + Container( + height: isCardView ? 205 : 240, + child: ClipRRect( + borderRadius: BorderRadius.circular(20.0), + child: SfLinearGauge( + orientation: LinearGaugeOrientation.vertical, + interval: 20.0, + showTicks: false, + showLabels: false, + minorTicksPerInterval: 0, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + borderWidth: 1, + borderColor: _brightness == Brightness.dark + ? Color(0xff898989) + : Colors.grey[350], + color: _brightness == Brightness.dark + ? Colors.transparent + : Colors.grey[350], + ), + barPointers: [ + LinearBarPointer( + enableAnimation: false, + value: _alarmValue, + thickness: 40, + edgeStyle: LinearEdgeStyle.bothCurve, + color: Colors.blueAccent) + ], + markerPointers: [ + LinearWidgetPointer( + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + value: 100, + child: Container( + height: 25, + child: Text(_alarmValue.toStringAsFixed(0) + '%'), + )), + LinearWidgetPointer( + value: 5, + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + child: GestureDetector( + onTap: () { + setState(() { + _alarmValue = 0; + }); + }, + child: Container( + height: 30, + width: 30, + child: Center( + child: Icon( + _alarmValue > 0 + ? Icons.access_alarm + : Icons.alarm_off, + color: Color(0xffFFFFFF), + )))), + ), + LinearShapePointer( + value: _alarmValue - 20, + enableAnimation: false, + onValueChanged: (value) => { + setState(() { + _alarmValue = value; + }) + }, + color: Colors.transparent, + width: 40, + position: LinearElementPosition.cross, + shapeType: LinearShapePointerType.circle, + markerAlignment: LinearMarkerAlignment.end, + height: 40), + ]), + )) + ]); + } +} diff --git a/lib/samples/linear_gauge/showcase/water_indicator.dart b/lib/samples/linear_gauge/showcase/water_indicator.dart new file mode 100644 index 00000000..a1d54bf8 --- /dev/null +++ b/lib/samples/linear_gauge/showcase/water_indicator.dart @@ -0,0 +1,188 @@ +// Flutter package imports +import 'package:flutter/material.dart'; + +/// Gauge imports +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +/// Local imports +import '../../../model/sample_view.dart'; +import '../utils.dart'; + +/// Renders the linear gauge water level indicator sample. +class WaterLevelIndicator extends SampleView { + /// Creates the linear gauge water level indicator sample. + const WaterLevelIndicator(Key key) : super(key: key); + + @override + _WaterLevelIndicatorState createState() => _WaterLevelIndicatorState(); +} + +/// State class of water indicator sample. +class _WaterLevelIndicatorState extends SampleViewState { + _WaterLevelIndicatorState(); + + double _level = 150; + final double _minimumLevel = 0; + final double _maximumLevel = 500; + + @override + Widget build(BuildContext context) { + return isWebOrDesktop + ? Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + height: 350, + child: _buildWaterIndicator(context), + )) + : isCardView + ? _buildWaterIndicator(context) + : Center( + child: Container( + height: 300, + child: _buildWaterIndicator(context), + )); + } + + /// Returns the water indicator. + Widget _buildWaterIndicator(BuildContext context) { + final Brightness _brightness = Theme.of(context).brightness; + + return Padding( + padding: EdgeInsets.all(10), + child: SfLinearGauge( + minimum: _minimumLevel, + maximum: _maximumLevel, + orientation: LinearGaugeOrientation.vertical, + interval: 100, + axisTrackStyle: LinearAxisTrackStyle( + thickness: 2, + ), + markerPointers: [ + LinearWidgetPointer( + value: _level, + enableAnimation: false, + onValueChanged: (value) { + setState(() => {_level = value}); + }, + child: Material( + elevation: 4.0, + shape: CircleBorder(), + clipBehavior: Clip.hardEdge, + color: Colors.blue, + child: Ink( + width: 32.0, + height: 32.0, + child: InkWell( + splashColor: Colors.grey, + hoverColor: Colors.blueAccent, + onTap: () {}, + child: Center( + child: _level == _minimumLevel + ? Icon(Icons.keyboard_arrow_up_outlined, + color: Colors.white, + size: isCardView ? 18.0 : 20.0) + : _level == _maximumLevel + ? Icon(Icons.keyboard_arrow_down_outlined, + color: Colors.white, + size: isCardView ? 18.0 : 20.0) + : RotatedBox( + quarterTurns: 3, + child: Icon(Icons.code_outlined, + color: Colors.white, + size: isCardView ? 18.0 : 20.0)), + ), + ), + ), + ), + ), + LinearWidgetPointer( + value: _level, + enableAnimation: false, + markerAlignment: LinearMarkerAlignment.end, + offset: isCardView + ? 67 + : isWebOrDesktop + ? 120 + : 95, + position: LinearElementPosition.outside, + child: Container( + width: 50, + height: 20, + child: Center( + child: Text( + _level.toStringAsFixed(0) + ' ml', + style: TextStyle( + color: _brightness == Brightness.light + ? Colors.black + : Colors.white, + fontSize: 14, + fontWeight: FontWeight.bold), + ))), + ) + ], + barPointers: [ + LinearBarPointer( + value: _maximumLevel, + enableAnimation: false, + thickness: isCardView + ? 150 + : isWebOrDesktop + ? 250 + : 200, + offset: 18, + position: LinearElementPosition.outside, + color: Colors.transparent, + child: CustomPaint( + painter: _CustomPathPainter( + color: Colors.blue, + waterLevel: _level, + maximumPoint: _maximumLevel)), + ) + ], + )); + } +} + +class _CustomPathPainter extends CustomPainter { + _CustomPathPainter( + {required this.color, + required this.waterLevel, + required this.maximumPoint}); + final Color color; + final double waterLevel; + final double maximumPoint; + + @override + void paint(Canvas canvas, Size size) { + final Path path = _buildTumblerPath(size.width, size.height); + final double factor = (size.height / maximumPoint); + final double height = 2 * factor * waterLevel; + final strokePaint = Paint() + ..color = Colors.grey + ..style = PaintingStyle.stroke + ..strokeWidth = 1; + final paint = Paint()..color = color; + canvas.drawPath(path, strokePaint); + final Rect clipper = Rect.fromCenter( + center: Offset(size.width / 2, size.height), + height: height, + width: size.width); + canvas.clipRect(clipper); + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(_CustomPathPainter oldDelegate) => true; +} + +Path _buildTumblerPath(double width, double height) { + return Path() + ..lineTo(width, 0) + ..lineTo(width * 0.75, height - 15) + ..quadraticBezierTo(width * 0.74, height, width * 0.67, height) + ..lineTo(width * 0.33, height) + ..quadraticBezierTo(width * 0.26, height, width * 0.25, height - 15) + ..close(); +} diff --git a/lib/samples/linear_gauge/utils.dart b/lib/samples/linear_gauge/utils.dart new file mode 100644 index 00000000..1ce07306 --- /dev/null +++ b/lib/samples/linear_gauge/utils.dart @@ -0,0 +1,21 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; + +/// Renders a given fixed size widget +bool get isWebOrDesktop { + return (defaultTargetPlatform == TargetPlatform.windows || + defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.macOS || + kIsWeb); +} + +/// Renders the width of the screen. +double getScreenWidth(BuildContext context, bool orientation) { + return isWebOrDesktop + ? MediaQuery.of(context).size.width >= 1000 + ? orientation + ? MediaQuery.of(context).size.width / 3 + : MediaQuery.of(context).size.width + : 440 + : MediaQuery.of(context).size.width; +} diff --git a/lib/samples/maps/shape_layer/bubble/bubble.dart b/lib/samples/maps/shape_layer/bubble/bubble.dart index f6c21776..7796c0da 100644 --- a/lib/samples/maps/shape_layer/bubble/bubble.dart +++ b/lib/samples/maps/shape_layer/bubble/bubble.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_core/theme.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import @@ -24,54 +25,54 @@ class _MapBubblePageState extends SampleViewState with TickerProviderStateMixin { _MapBubblePageState(); - MapShapeSource _mapSource; - MapShapeSource _facebookMapSource; - MapShapeSource _twitterMapSource; - MapShapeSource _tikTokMapSorce; - MapShapeSource _instagramMapSource; - MapShapeSource _snapChatMapSource; - - bool _isLightTheme; - - Color _shapeColor; - Color _shapeStrokeColor; - Color _bubbleColor; - Color _bubbleStrokeColor; - Color _tooltipColor; - Color _tooltipStrokeColor; - Color _tooltipTextColor; - - String _currentDelegate; - - BoxDecoration _facebookBoxDecoration; - BoxDecoration _twitterBoxDecoration; - BoxDecoration _instagramBoxDecoration; - BoxDecoration _snapchatBoxDecoration; - BoxDecoration _tiktokBoxDecoration; - - List<_UsersModel> _facebookUsers; - List<_UsersModel> _twitterUsers; - List<_UsersModel> _tikTokUsers; - List<_UsersModel> _snapChatUsers; - List<_UsersModel> _instagramUsers; - - AnimationController _facebookController; - AnimationController _twitterController; - AnimationController _tiktokController; - AnimationController _instagramController; - AnimationController _snapchatController; - - Animation _facebookAnimation; - Animation _twitterAnimation; - Animation _tiktokAnimation; - Animation _instagramAnimation; - Animation _snapchatAnimation; + late MapShapeSource _mapSource; + late MapShapeSource _facebookMapSource; + late MapShapeSource _twitterMapSource; + late MapShapeSource _tikTokMapSorce; + late MapShapeSource _instagramMapSource; + late MapShapeSource _snapChatMapSource; + + late bool _isLightTheme; + + late Color _shapeColor; + late Color _shapeStrokeColor; + late Color _bubbleColor; + late Color _bubbleStrokeColor; + late Color _tooltipColor; + late Color _tooltipStrokeColor; + late Color _tooltipTextColor; + + late String _currentDelegate; + + BoxDecoration? _facebookBoxDecoration; + BoxDecoration? _twitterBoxDecoration; + BoxDecoration? _instagramBoxDecoration; + BoxDecoration? _snapchatBoxDecoration; + BoxDecoration? _tiktokBoxDecoration; + + late List<_UserDetails> _facebookUsers; + late List<_UserDetails> _twitterUsers; + late List<_UserDetails> _tikTokUsers; + late List<_UserDetails> _snapChatUsers; + late List<_UserDetails> _instagramUsers; + + late AnimationController _facebookController; + late AnimationController _twitterController; + late AnimationController _tiktokController; + late AnimationController _instagramController; + late AnimationController _snapchatController; + + late Animation _facebookAnimation; + late Animation _twitterAnimation; + late Animation _tiktokAnimation; + late Animation _instagramAnimation; + late Animation _snapchatAnimation; @override void initState() { super.initState(); - _isLightTheme = model?.themeData?.brightness == Brightness.light; + _isLightTheme = model.themeData.brightness == Brightness.light; _facebookController = AnimationController( duration: const Duration(milliseconds: 500), @@ -124,96 +125,96 @@ class _MapBubblePageState extends SampleViewState // // [usersCount]: On the basis of this value, color mapping color has been // applied to the shape. - _facebookUsers = <_UsersModel>[ - _UsersModel('India', 280), - _UsersModel('United States of America', 190), - _UsersModel('Indonesia', 130), - _UsersModel('Brazil', 120), - _UsersModel('Mexico', 86), - _UsersModel('Philippines', 72), - _UsersModel('Vietnam', 63), - _UsersModel('Thailand', 48), - _UsersModel('Egypt', 41), - _UsersModel('Bangladesh', 37), - _UsersModel('Pakistan', 37), - _UsersModel('Turkey', 37), - _UsersModel('United Kingdom', 37), - _UsersModel('Colombia', 33), - _UsersModel('France', 32), + _facebookUsers = <_UserDetails>[ + _UserDetails('India', 280), + _UserDetails('United States of America', 190), + _UserDetails('Indonesia', 130), + _UserDetails('Brazil', 120), + _UserDetails('Mexico', 86), + _UserDetails('Philippines', 72), + _UserDetails('Vietnam', 63), + _UserDetails('Thailand', 48), + _UserDetails('Egypt', 41), + _UserDetails('Bangladesh', 37), + _UserDetails('Pakistan', 37), + _UserDetails('Turkey', 37), + _UserDetails('United Kingdom', 37), + _UserDetails('Colombia', 33), + _UserDetails('France', 32), ]; - _twitterUsers = <_UsersModel>[ - _UsersModel('United States of America', 64), - _UsersModel('Japan', 48), - _UsersModel('Russia', 23), - _UsersModel('United Kingdom', 17), - _UsersModel('Saudi Arabia', 15), - _UsersModel('Brazil', 14), - _UsersModel('Turkey', 13), - _UsersModel('India', 13), - _UsersModel('Indonesia', 11), - _UsersModel('Mexico', 10), - _UsersModel('France', 8), - _UsersModel('Spain', 8), - _UsersModel('Canada', 8), - _UsersModel('Thailand', 7), - _UsersModel('Philippines', 7), - _UsersModel('South Africa', 6), + _twitterUsers = <_UserDetails>[ + _UserDetails('United States of America', 64), + _UserDetails('Japan', 48), + _UserDetails('Russia', 23), + _UserDetails('United Kingdom', 17), + _UserDetails('Saudi Arabia', 15), + _UserDetails('Brazil', 14), + _UserDetails('Turkey', 13), + _UserDetails('India', 13), + _UserDetails('Indonesia', 11), + _UserDetails('Mexico', 10), + _UserDetails('France', 8), + _UserDetails('Spain', 8), + _UserDetails('Canada', 8), + _UserDetails('Thailand', 7), + _UserDetails('Philippines', 7), + _UserDetails('South Africa', 6), ]; - _tikTokUsers = <_UsersModel>[ - _UsersModel('United States of America', 39), - _UsersModel('Turkey', 28), - _UsersModel('Russia', 24), - _UsersModel('Mexico', 19), - _UsersModel('Brazil', 18), - _UsersModel('Pakistan', 11), - _UsersModel('Saudi Arabia', 9), - _UsersModel('France', 9), - _UsersModel('Germany', 8), - _UsersModel('Egypt', 8), - _UsersModel('Italy', 7), - _UsersModel('United Kingdom', 6), - _UsersModel('Spain', 6), - _UsersModel('Poland', 5), + _tikTokUsers = <_UserDetails>[ + _UserDetails('United States of America', 39), + _UserDetails('Turkey', 28), + _UserDetails('Russia', 24), + _UserDetails('Mexico', 19), + _UserDetails('Brazil', 18), + _UserDetails('Pakistan', 11), + _UserDetails('Saudi Arabia', 9), + _UserDetails('France', 9), + _UserDetails('Germany', 8), + _UserDetails('Egypt', 8), + _UserDetails('Italy', 7), + _UserDetails('United Kingdom', 6), + _UserDetails('Spain', 6), + _UserDetails('Poland', 5), ]; - _instagramUsers = <_UsersModel>[ - _UsersModel('United States of America', 120), - _UsersModel('India', 88), - _UsersModel('Brazil', 82), - _UsersModel('Indonesia', 64), - _UsersModel('Russia', 46), - _UsersModel('Turkey', 39), - _UsersModel('Japan', 31), - _UsersModel('Mexico', 26), - _UsersModel('United Kingdom', 25), - _UsersModel('Germany', 22), - _UsersModel('Italy', 21), - _UsersModel('France', 19), - _UsersModel('Argentina', 18), - _UsersModel('Spain', 17), - _UsersModel('Canada', 13), - _UsersModel('South Korea', 13), + _instagramUsers = <_UserDetails>[ + _UserDetails('United States of America', 120), + _UserDetails('India', 88), + _UserDetails('Brazil', 82), + _UserDetails('Indonesia', 64), + _UserDetails('Russia', 46), + _UserDetails('Turkey', 39), + _UserDetails('Japan', 31), + _UserDetails('Mexico', 26), + _UserDetails('United Kingdom', 25), + _UserDetails('Germany', 22), + _UserDetails('Italy', 21), + _UserDetails('France', 19), + _UserDetails('Argentina', 18), + _UserDetails('Spain', 17), + _UserDetails('Canada', 13), + _UserDetails('South Korea', 13), ]; - _snapChatUsers = <_UsersModel>[ - _UsersModel('United States of America', 102), - _UsersModel('India', 28), - _UsersModel('France', 21), - _UsersModel('United Kingdom', 18), - _UsersModel('Saudi Arabia', 16), - _UsersModel('Mexico', 16), - _UsersModel('Japan', 31), - _UsersModel('Mexico', 26), - _UsersModel('Brazil', 13), - _UsersModel('Germany', 11), - _UsersModel('Canada', 9), - _UsersModel('Turkey', 8), - _UsersModel('Russia', 8), - _UsersModel('Philippines', 8), - _UsersModel('Iraq', 7), - _UsersModel('Egypt', 7), + _snapChatUsers = <_UserDetails>[ + _UserDetails('United States of America', 102), + _UserDetails('India', 28), + _UserDetails('France', 21), + _UserDetails('United Kingdom', 18), + _UserDetails('Saudi Arabia', 16), + _UserDetails('Mexico', 16), + _UserDetails('Japan', 31), + _UserDetails('Mexico', 26), + _UserDetails('Brazil', 13), + _UserDetails('Germany', 11), + _UserDetails('Canada', 9), + _UserDetails('Turkey', 8), + _UserDetails('Russia', 8), + _UserDetails('Philippines', 8), + _UserDetails('Iraq', 7), + _UserDetails('Egypt', 7), ]; _facebookMapSource = MapShapeSource.asset( @@ -311,74 +312,81 @@ class _MapBubblePageState extends SampleViewState @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget() + model.isWebFullView + ? _buildMapsWidget() : SingleChildScrollView( - child: Container(height: 400, child: _getMapsWidget())); + child: Container(height: 400, child: _buildMapsWidget())); } - Widget _getMapsWidget() { + Widget _buildMapsWidget() { return Stack( children: [ Padding( padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? EdgeInsets.only( top: MediaQuery.of(context).size.height * 0.05, bottom: MediaQuery.of(context).size.height * 0.15, right: 10) : const EdgeInsets.only(bottom: 75.0, right: 10), child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Colors.transparent, - shapeHoverStrokeColor: Colors.transparent, - bubbleHoverColor: _shapeColor, - bubbleHoverStrokeColor: _bubbleColor, - bubbleHoverStrokeWidth: 1.5, - ), - child: SfMaps( - title: const MapTitle( - 'Social Media Users Statistics', - padding: EdgeInsets.only(top: 15, bottom: 30), + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + shapeHoverStrokeColor: Colors.transparent, + bubbleHoverColor: _shapeColor, + bubbleHoverStrokeColor: _bubbleColor, + bubbleHoverStrokeWidth: 1.5, ), - layers: [ - MapShapeLayer( - loadingBuilder: (BuildContext context) { - return Container( - height: 25, - width: 25, - child: const CircularProgressIndicator( - strokeWidth: 3, + child: Column(children: [ + Padding( + padding: EdgeInsets.only(top: 15, bottom: 30), + child: Align( + alignment: Alignment.center, + child: Text('Social Media Users Statistics', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( + layers: [ + MapShapeLayer( + loadingBuilder: (BuildContext context) { + return Container( + height: 25, + width: 25, + child: const CircularProgressIndicator( + strokeWidth: 3, + ), + ); + }, + source: _mapSource, + color: _shapeColor, + strokeWidth: 1, + strokeColor: _shapeStrokeColor, + // Returns the custom tooltip for each bubble. + bubbleTooltipBuilder: + (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text(_getCustomizedString(index), + style: Theme.of(context) + .textTheme + .caption! + .copyWith(color: _tooltipTextColor)), + ); + }, + bubbleSettings: MapBubbleSettings( + strokeColor: _bubbleStrokeColor, + strokeWidth: 0.5, + color: _bubbleColor, + minRadius: 10, + maxRadius: 40), + tooltipSettings: MapTooltipSettings( + color: _tooltipColor, + strokeColor: _tooltipStrokeColor), ), - ); - }, - source: _mapSource, - color: _shapeColor, - strokeWidth: 1, - strokeColor: _shapeStrokeColor, - // Returns the custom tooltip for each bubble. - bubbleTooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text(_getCustomizedString(index), - style: Theme.of(context) - .textTheme - .caption - .copyWith(color: _tooltipTextColor)), - ); - }, - bubbleSettings: MapBubbleSettings( - strokeColor: _bubbleStrokeColor, - strokeWidth: 0.5, - color: _bubbleColor, - minRadius: 10, - maxRadius: 40), - tooltipSettings: MapTooltipSettings( - color: _tooltipColor, strokeColor: _tooltipStrokeColor), - ), - ], - ), - ), + ], + ), + ) + ])), ), Align( alignment: Alignment.bottomCenter, @@ -631,7 +639,6 @@ class _MapBubblePageState extends SampleViewState ); } - // ignore: missing_return String _getCustomizedString(int index) { switch (_currentDelegate) { case 'FaceBook': @@ -639,32 +646,29 @@ class _MapBubblePageState extends SampleViewState ' : ' + _facebookUsers[index].usersCount.toStringAsFixed(0) + 'M users'; - break; case 'Twitter': return _twitterUsers[index].country + ' : ' + _twitterUsers[index].usersCount.toStringAsFixed(0) + 'M users'; - break; case 'Instagram': return _instagramUsers[index].country + ' : ' + _instagramUsers[index].usersCount.toStringAsFixed(0) + 'M users'; - break; case 'SnapChat': return _snapChatUsers[index].country + ' : ' + _snapChatUsers[index].usersCount.toStringAsFixed(0) + 'M users'; - break; case 'Tiktok': return _tikTokUsers[index].country + ' : ' + _tikTokUsers[index].usersCount.toStringAsFixed(0) + 'M users'; - break; + default: + return ''; } } @@ -680,8 +684,9 @@ class _MapBubblePageState extends SampleViewState } } -class _UsersModel { - _UsersModel(this.country, this.usersCount); +class _UserDetails { + _UserDetails(this.country, this.usersCount); + final String country; final double usersCount; } diff --git a/lib/samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart b/lib/samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart index 472b6d34..6a274678 100644 --- a/lib/samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart +++ b/lib/samples/maps/shape_layer/equal_color_mapping/equal_color_mapping.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import @@ -18,7 +19,8 @@ class MapEqualColorMappingPage extends SampleView { } class _MapEqualColorMappingPageState extends SampleViewState { - List<_GMTModel> _gmtDetails; + late List<_CountryTimeInGMT> _timeZones; + late MapShapeSource _mapSource; @override void initState() { @@ -33,61 +35,110 @@ class _MapEqualColorMappingPageState extends SampleViewState { // // [gmtTime]: On the basis of this value, color mapping color has been // applied to the shape. - _gmtDetails = <_GMTModel>[ - _GMTModel('Albania', 'GMT+2'), - _GMTModel('Aland', 'GMT+3'), - _GMTModel('Andorra', 'GMT+1'), - _GMTModel('Austria', 'GMT+2'), - _GMTModel('Belgium', 'GMT+2'), - _GMTModel('Bulgaria', 'GMT+3'), - _GMTModel('Bosnia and Herz.', 'GMT+2'), - _GMTModel('Belarus', 'GMT+3'), - _GMTModel('Switzerland', 'GMT+2'), - _GMTModel('Czech Rep.', 'GMT+2'), - _GMTModel('Germany', 'GMT+2'), - _GMTModel('Denmark', 'GMT+2'), - _GMTModel('Spain', 'GMT+2'), - _GMTModel('Estonia', 'GMT+3'), - _GMTModel('Finland', 'GMT+3'), - _GMTModel('France', 'GMT+2'), - _GMTModel('Faeroe Is.', 'GMT+1'), - _GMTModel('United Kingdom', 'GMT+1'), - _GMTModel('Guernsey', 'GMT+1'), - _GMTModel('Greece', 'GMT+3'), - _GMTModel('Croatia', 'GMT+2'), - _GMTModel('Hungary', 'GMT+2'), - _GMTModel('Isle of Man', 'GMT+1'), - _GMTModel('Ireland', 'GMT+1'), - _GMTModel('Iceland', 'GMT+0'), - _GMTModel('Italy', 'GMT+2'), - _GMTModel('Jersey', 'GMT+1'), - _GMTModel('Kosovo', 'GMT+2'), - _GMTModel('Liechtenstein', 'GMT+2'), - _GMTModel('Lithuania', 'GMT+3'), - _GMTModel('Luxembourg', 'GMT+2'), - _GMTModel('Latvia', 'GMT+3'), - _GMTModel('Monaco', 'GMT+2'), - _GMTModel('Moldova', 'GMT+3'), - _GMTModel('Macedonia', 'GMT+2'), - _GMTModel('Malta', 'GMT+2'), - _GMTModel('Montenegro', 'GMT+2'), - _GMTModel('Netherlands', 'GMT+2'), - _GMTModel('Poland', 'GMT+2'), - _GMTModel('Portugal', 'GMT+1'), - _GMTModel('Romania', 'GMT+3'), - _GMTModel('San Marino', 'GMT+2'), - _GMTModel('Serbia', 'GMT+2'), - _GMTModel('Slovakia', 'GMT+2'), - _GMTModel('Slovenia', 'GMT+2'), - _GMTModel('Sweden', 'GMT+2'), - _GMTModel('Ukraine', 'GMT+3'), - _GMTModel('Vatican', 'GMT+1'), + _timeZones = <_CountryTimeInGMT>[ + _CountryTimeInGMT('Albania', 'GMT+2'), + _CountryTimeInGMT('Aland', 'GMT+3'), + _CountryTimeInGMT('Andorra', 'GMT+1'), + _CountryTimeInGMT('Austria', 'GMT+2'), + _CountryTimeInGMT('Belgium', 'GMT+2'), + _CountryTimeInGMT('Bulgaria', 'GMT+3'), + _CountryTimeInGMT('Bosnia and Herz.', 'GMT+2'), + _CountryTimeInGMT('Belarus', 'GMT+3'), + _CountryTimeInGMT('Switzerland', 'GMT+2'), + _CountryTimeInGMT('Czech Rep.', 'GMT+2'), + _CountryTimeInGMT('Germany', 'GMT+2'), + _CountryTimeInGMT('Denmark', 'GMT+2'), + _CountryTimeInGMT('Spain', 'GMT+2'), + _CountryTimeInGMT('Estonia', 'GMT+3'), + _CountryTimeInGMT('Finland', 'GMT+3'), + _CountryTimeInGMT('France', 'GMT+2'), + _CountryTimeInGMT('Faeroe Is.', 'GMT+1'), + _CountryTimeInGMT('United Kingdom', 'GMT+1'), + _CountryTimeInGMT('Guernsey', 'GMT+1'), + _CountryTimeInGMT('Greece', 'GMT+3'), + _CountryTimeInGMT('Croatia', 'GMT+2'), + _CountryTimeInGMT('Hungary', 'GMT+2'), + _CountryTimeInGMT('Isle of Man', 'GMT+1'), + _CountryTimeInGMT('Ireland', 'GMT+1'), + _CountryTimeInGMT('Iceland', 'GMT+0'), + _CountryTimeInGMT('Italy', 'GMT+2'), + _CountryTimeInGMT('Jersey', 'GMT+1'), + _CountryTimeInGMT('Kosovo', 'GMT+2'), + _CountryTimeInGMT('Liechtenstein', 'GMT+2'), + _CountryTimeInGMT('Lithuania', 'GMT+3'), + _CountryTimeInGMT('Luxembourg', 'GMT+2'), + _CountryTimeInGMT('Latvia', 'GMT+3'), + _CountryTimeInGMT('Monaco', 'GMT+2'), + _CountryTimeInGMT('Moldova', 'GMT+3'), + _CountryTimeInGMT('Macedonia', 'GMT+2'), + _CountryTimeInGMT('Malta', 'GMT+2'), + _CountryTimeInGMT('Montenegro', 'GMT+2'), + _CountryTimeInGMT('Netherlands', 'GMT+2'), + _CountryTimeInGMT('Poland', 'GMT+2'), + _CountryTimeInGMT('Portugal', 'GMT+1'), + _CountryTimeInGMT('Romania', 'GMT+3'), + _CountryTimeInGMT('San Marino', 'GMT+2'), + _CountryTimeInGMT('Serbia', 'GMT+2'), + _CountryTimeInGMT('Slovakia', 'GMT+2'), + _CountryTimeInGMT('Slovenia', 'GMT+2'), + _CountryTimeInGMT('Sweden', 'GMT+2'), + _CountryTimeInGMT('Ukraine', 'GMT+3'), + _CountryTimeInGMT('Vatican', 'GMT+1'), ]; + + _mapSource = MapShapeSource.asset( + // Path of the GeoJSON file. + 'assets/europe.json', + // Field or group name in the .json file to identify + // the shapes. + // + // Which is used to map the respective shape + // to data source. + // + // On the basis of this value, shape tooltip text + // is rendered. + shapeDataField: 'name', + // The number of data in your data source collection. + // + // The callback for the [primaryValueMapper] will be + // called the number of times equal to the [dataCount]. + // The value returned in the [primaryValueMapper] should + // exactly matched with the value of the [shapeDataField] + // in the .json file. This is how the mapping between the + // data source and the shapes in the .json file is done. + dataCount: _timeZones.length, + primaryValueMapper: (int index) => _timeZones[index].countryName, + // Used for color mapping. + // + // The value of the [MapColorMapper.value] will be + // compared with the value returned in the + // [shapeColorValueMapper]. If it is equal, the respective + // [MapColorMapper.color] will be applied to the shape. + shapeColorValueMapper: (int index) => _timeZones[index].gmtTime, + // Group and differentiate the shapes using the color + // based on [MapColorMapper.value] value. + // + // The value of the [MapColorMapper.value] + // will be compared with the value returned in the + // [shapeColorValueMapper] and the respective + // [MapColorMapper.color] will be applied to the shape. + // + // [MapColorMapper.text] which is used for the text of + // legend item and [MapColorMapper.color] will be used for + // the color of the legend icon respectively. + shapeColorMappers: const [ + MapColorMapper(value: 'GMT+0', color: Colors.lightBlue, text: 'GMT+0'), + MapColorMapper( + value: 'GMT+1', color: Colors.orangeAccent, text: 'GMT+1'), + MapColorMapper(value: 'GMT+2', color: Colors.lightGreen, text: 'GMT+2'), + MapColorMapper(value: 'GMT+3', color: Colors.purple, text: 'GMT+3'), + ], + ); } @override void dispose() { - _gmtDetails?.clear(); + _timeZones.clear(); super.dispose(); } @@ -95,28 +146,32 @@ class _MapEqualColorMappingPageState extends SampleViewState { Widget build(BuildContext context) { final ThemeData themeData = Theme.of(context); return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget(themeData) - : SingleChildScrollView(child: _getMapsWidget(themeData)); + model.isWebFullView + ? _buildMapsWidget(themeData) + : SingleChildScrollView(child: _buildMapsWidget(themeData)); } - Widget _getMapsWidget(ThemeData themeData) { + Widget _buildMapsWidget(ThemeData themeData) { final bool isLightTheme = themeData.brightness == Brightness.light; return Center( - child: Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.05, - right: 10, - left: 10) - : const EdgeInsets.only(left: 10, right: 10, bottom: 15), - child: SfMaps( - title: const MapTitle( - 'European Time Zones', + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.05, + right: 10, + left: 10) + : const EdgeInsets.only(left: 10, right: 10, bottom: 15), + child: Column(children: [ + Padding( padding: EdgeInsets.only(top: 15, bottom: 30), - ), + child: Align( + alignment: Alignment.center, + child: Text('European Time Zones', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( layers: [ MapShapeLayer( loadingBuilder: (BuildContext context) { @@ -128,61 +183,7 @@ class _MapEqualColorMappingPageState extends SampleViewState { ), ); }, - source: MapShapeSource.asset( - // Path of the GeoJSON file. - 'assets/europe.json', - // Field or group name in the .json file to identify - // the shapes. - // - // Which is used to map the respective shape - // to data source. - // - // On the basis of this value, shape tooltip text - // is rendered. - shapeDataField: 'name', - // The number of data in your data source collection. - // - // The callback for the [primaryValueMapper] will be - // called the number of times equal to the [dataCount]. - // The value returned in the [primaryValueMapper] should - // exactly matched with the value of the [shapeDataField] - // in the .json file. This is how the mapping between the - // data source and the shapes in the .json file is done. - dataCount: _gmtDetails.length, - primaryValueMapper: (int index) => - _gmtDetails[index].countryName, - // Used for color mapping. - // - // The value of the [MapColorMapper.value] will be - // compared with the value returned in the - // [shapeColorValueMapper]. If it is equal, the respective - // [MapColorMapper.color] will be applied to the shape. - shapeColorValueMapper: (int index) => - _gmtDetails[index].gmtTime, - // Group and differentiate the shapes using the color - // based on [MapColorMapper.value] value. - // - // The value of the [MapColorMapper.value] - // will be compared with the value returned in the - // [shapeColorValueMapper] and the respective - // [MapColorMapper.color] will be applied to the shape. - // - // [MapColorMapper.text] which is used for the text of - // legend item and [MapColorMapper.color] will be used for - // the color of the legend icon respectively. - shapeColorMappers: const [ - MapColorMapper( - value: 'GMT+0', color: Colors.lightBlue, text: 'GMT+0'), - MapColorMapper( - value: 'GMT+1', - color: Colors.orangeAccent, - text: 'GMT+1'), - MapColorMapper( - value: 'GMT+2', color: Colors.lightGreen, text: 'GMT+2'), - MapColorMapper( - value: 'GMT+3', color: Colors.purple, text: 'GMT+3'), - ], - ), + source: _mapSource, strokeColor: isLightTheme ? Colors.white : const Color.fromRGBO(224, 224, 224, 0.5), @@ -191,10 +192,10 @@ class _MapEqualColorMappingPageState extends SampleViewState { return Padding( padding: const EdgeInsets.all(8.0), child: Text( - _gmtDetails[index].countryName + + _timeZones[index].countryName + ' : ' + - _gmtDetails[index].gmtTime, - style: themeData.textTheme.caption.copyWith( + _timeZones[index].gmtTime, + style: themeData.textTheme.caption!.copyWith( color: isLightTheme ? Color.fromRGBO(255, 255, 255, 1) : Color.fromRGBO(10, 10, 10, 1), @@ -202,11 +203,11 @@ class _MapEqualColorMappingPageState extends SampleViewState { ), ); }, - legend: MapLegend.bar( + legend: const MapLegend.bar( MapElement.shape, position: MapLegendPosition.bottom, padding: EdgeInsets.only(top: 15), - segmentSize: const Size(60.0, 10.0), + segmentSize: Size(60.0, 10.0), ), tooltipSettings: MapTooltipSettings( color: isLightTheme @@ -215,14 +216,14 @@ class _MapEqualColorMappingPageState extends SampleViewState { ), ), ], - ), - ), - ); + )), + ]), + )); } } -class _GMTModel { - _GMTModel(this.countryName, this.gmtTime); +class _CountryTimeInGMT { + _CountryTimeInGMT(this.countryName, this.gmtTime); final String countryName; final String gmtTime; diff --git a/lib/samples/maps/shape_layer/legend/legend.dart b/lib/samples/maps/shape_layer/legend/legend.dart index d6b8519e..b33a2ccc 100644 --- a/lib/samples/maps/shape_layer/legend/legend.dart +++ b/lib/samples/maps/shape_layer/legend/legend.dart @@ -5,13 +5,17 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_core/theme.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import import '../../../../model/sample_view.dart'; +/// Renders the legend map sample class MapLegendPage extends SampleView { + /// Creates the legend map sample const MapLegendPage(Key key) : super(key: key); + @override _MapLegendPageState createState() => _MapLegendPageState(); } @@ -19,144 +23,140 @@ class MapLegendPage extends SampleView { class _MapLegendPageState extends SampleViewState { _MapLegendPageState(); - MapShapeSource _mapBubbleSource; - MapShapeSource _mapShapeSource; + late MapShapeSource _mapBubbleSource; + late MapShapeSource _mapShapeSource; - List _shapeInternetData; - List _bubbleInternetData; - List _shapeColorMappers; - List _bubbleColorMappers; - List _shapeBarLegendColorMappers; - List _bubbleBarLegendColorMappers; + late List<_InternetPrice> _internetPriceForShapes; + late List<_InternetPrice> _internetPriceForBubbles; + late List _shapeColorMappers; + late List _bubbleColorMappers; + late List _shapeBarLegendColorMappers; + late List _bubbleBarLegendColorMappers; bool _showBubbleData = false; bool _showBarLegend = false; bool _enableToggleInteraction = true; bool _enableGradient = false; - List> _dropDownMenuItems; - String _currentLegend; + late List> _dropDownMenuItems; + late String _currentLegend; @override void initState() { super.initState(); - _shapeInternetData = [ - InternetDataModel('Algeria', price: 5.15), - InternetDataModel('Angola', price: 7.95), - InternetDataModel('Benin', price: 20.99), - InternetDataModel('Botswana', price: 14.12), - InternetDataModel('Burkina Faso', price: 4.69), - InternetDataModel('Burundi', price: 2), - InternetDataModel('Cameroon', price: 1.71), - InternetDataModel('Cape Verde', price: 4.25), - InternetDataModel('Central African Rep.', + _internetPriceForShapes = <_InternetPrice>[ + _InternetPrice('Algeria', price: 5.15), + _InternetPrice('Angola', price: 7.95), + _InternetPrice('Benin', price: 20.99), + _InternetPrice('Botswana', price: 14.12), + _InternetPrice('Burkina Faso', price: 4.69), + _InternetPrice('Burundi', price: 2), + _InternetPrice('Cameroon', price: 1.71), + _InternetPrice('Cape Verde', price: 4.25), + _InternetPrice('Central African Rep.', price: 6.03, countryName: 'Central African Republic'), - InternetDataModel('Chad', price: 23.33), - InternetDataModel('Comoros', price: 12.57), - InternetDataModel('Congo', price: 5.63), - InternetDataModel('C�te d\'Ivoire', - price: 4.1, countryName: 'Ivory Coast'), - InternetDataModel('Dem. Rep. Congo', + _InternetPrice('Chad', price: 23.33), + _InternetPrice('Comoros', price: 12.57), + _InternetPrice('Congo', price: 5.63), + _InternetPrice('C�te d\'Ivoire', price: 4.1, countryName: 'Ivory Coast'), + _InternetPrice('Dem. Rep. Congo', price: 0.88, countryName: 'Democratic Republic of the Congo'), - InternetDataModel('Djibouti', price: 37.92), - InternetDataModel('Egypt', price: 1.49), - InternetDataModel('Eq. Guinea', + _InternetPrice('Djibouti', price: 37.92), + _InternetPrice('Egypt', price: 1.49), + _InternetPrice('Eq. Guinea', price: 65.83, countryName: 'Equatorial Guinea'), - InternetDataModel('Eritrea'), - InternetDataModel('Ethiopia', price: 2.91), - InternetDataModel('Gabon', price: 5.84), - InternetDataModel('Gambia', price: 5.33), - InternetDataModel('Ghana', price: 1.56), - InternetDataModel('Guinea', price: 1.97), - InternetDataModel('Guinea-Bissau', price: 4.96), - InternetDataModel('Kenya', price: 2.73), - InternetDataModel('Lesotho', price: 2.43), - InternetDataModel('Liberia', price: 3.75), - InternetDataModel('Libya', price: 4.87), - InternetDataModel('Madagascar', price: 3.39), - InternetDataModel('Malawi', price: 3.59), - InternetDataModel('Mali', price: 9.22), - InternetDataModel('Mauritania', price: 3.12), - InternetDataModel('Mauritius', price: 3.71), - InternetDataModel('Mayotte', price: 10.18), - InternetDataModel('Morocco', price: 1.6), - InternetDataModel('Mozambique', price: 15.82), - InternetDataModel('Namibia', price: 11.02), - InternetDataModel('Niger', price: 2.98), - InternetDataModel('Nigeria', price: 2.22), - InternetDataModel('Rwanda', price: 0.56), - InternetDataModel('Sao Tome and Principe', price: 5.33), - InternetDataModel('Saint Helena', price: 55.47), - InternetDataModel('Senegal', price: 3.28), - InternetDataModel('Seychelles', price: 19.55), - InternetDataModel('Sierra Leone', price: 5.79), - InternetDataModel('Somalia', price: 6.19), - InternetDataModel('Somaliland'), - InternetDataModel('South Africa', price: 7.19), - InternetDataModel('S. Sudan', countryName: 'South Sudan'), - InternetDataModel('Sudan', price: 0.68), - InternetDataModel('Swaziland', price: 12.14), - InternetDataModel('Tanzania', price: 5.93), - InternetDataModel('Togo', price: 11.76), - InternetDataModel('Tunisia', price: 2.87), - InternetDataModel('Uganda', price: 4.69), - InternetDataModel('W. Sahara', - price: 1.66, countryName: 'Western Sahara'), - InternetDataModel('Zambia', price: 2.25), - InternetDataModel('Zimbabwe', price: 75.2), + _InternetPrice('Eritrea'), + _InternetPrice('Ethiopia', price: 2.91), + _InternetPrice('Gabon', price: 5.84), + _InternetPrice('Gambia', price: 5.33), + _InternetPrice('Ghana', price: 1.56), + _InternetPrice('Guinea', price: 1.97), + _InternetPrice('Guinea-Bissau', price: 4.96), + _InternetPrice('Kenya', price: 2.73), + _InternetPrice('Lesotho', price: 2.43), + _InternetPrice('Liberia', price: 3.75), + _InternetPrice('Libya', price: 4.87), + _InternetPrice('Madagascar', price: 3.39), + _InternetPrice('Malawi', price: 3.59), + _InternetPrice('Mali', price: 9.22), + _InternetPrice('Mauritania', price: 3.12), + _InternetPrice('Mauritius', price: 3.71), + _InternetPrice('Mayotte', price: 10.18), + _InternetPrice('Morocco', price: 1.6), + _InternetPrice('Mozambique', price: 15.82), + _InternetPrice('Namibia', price: 11.02), + _InternetPrice('Niger', price: 2.98), + _InternetPrice('Nigeria', price: 2.22), + _InternetPrice('Rwanda', price: 0.56), + _InternetPrice('Sao Tome and Principe', price: 5.33), + _InternetPrice('Saint Helena', price: 55.47), + _InternetPrice('Senegal', price: 3.28), + _InternetPrice('Seychelles', price: 19.55), + _InternetPrice('Sierra Leone', price: 5.79), + _InternetPrice('Somalia', price: 6.19), + _InternetPrice('Somaliland'), + _InternetPrice('South Africa', price: 7.19), + _InternetPrice('S. Sudan', countryName: 'South Sudan'), + _InternetPrice('Sudan', price: 0.68), + _InternetPrice('Swaziland', price: 12.14), + _InternetPrice('Tanzania', price: 5.93), + _InternetPrice('Togo', price: 11.76), + _InternetPrice('Tunisia', price: 2.87), + _InternetPrice('Uganda', price: 4.69), + _InternetPrice('W. Sahara', price: 1.66, countryName: 'Western Sahara'), + _InternetPrice('Zambia', price: 2.25), + _InternetPrice('Zimbabwe', price: 75.2), ]; - _bubbleInternetData = [ - InternetDataModel('Algeria', price: 5.15), - InternetDataModel('Angola', price: 7.95), - InternetDataModel('Benin', price: 20.99), - InternetDataModel('Botswana', price: 14.12), - InternetDataModel('Cape Verde', price: 4.25), - InternetDataModel('Central African Rep.', + _internetPriceForBubbles = <_InternetPrice>[ + _InternetPrice('Algeria', price: 5.15), + _InternetPrice('Angola', price: 7.95), + _InternetPrice('Benin', price: 20.99), + _InternetPrice('Botswana', price: 14.12), + _InternetPrice('Cape Verde', price: 4.25), + _InternetPrice('Central African Rep.', price: 6.03, countryName: 'Central African Republic'), - InternetDataModel('Chad', price: 23.33), - InternetDataModel('Comoros', price: 12.57), - InternetDataModel('Congo', price: 5.63), - InternetDataModel('C�te d\'Ivoire', - price: 4.1, countryName: 'Ivory Coast'), - InternetDataModel('Dem. Rep. Congo', + _InternetPrice('Chad', price: 23.33), + _InternetPrice('Comoros', price: 12.57), + _InternetPrice('Congo', price: 5.63), + _InternetPrice('C�te d\'Ivoire', price: 4.1, countryName: 'Ivory Coast'), + _InternetPrice('Dem. Rep. Congo', price: 0.88, countryName: 'Democratic Republic of the Congo'), - InternetDataModel('Djibouti', price: 37.92), - InternetDataModel('Egypt', price: 1.49), - InternetDataModel('Eq. Guinea', + _InternetPrice('Djibouti', price: 37.92), + _InternetPrice('Egypt', price: 1.49), + _InternetPrice('Eq. Guinea', price: 65.83, countryName: 'Equatorial Guinea'), - InternetDataModel('Eritrea'), - InternetDataModel('Guinea', price: 1.97), - InternetDataModel('Kenya', price: 2.73), - InternetDataModel('Madagascar', price: 3.39), - InternetDataModel('Malawi', price: 3.59), - InternetDataModel('Mali', price: 9.22), - InternetDataModel('Mauritania', price: 3.12), - InternetDataModel('Mauritius', price: 3.71), - InternetDataModel('Mayotte', price: 10.18), - InternetDataModel('Morocco', price: 1.6), - InternetDataModel('Mozambique', price: 15.82), - InternetDataModel('Namibia', price: 11.02), - InternetDataModel('Niger', price: 2.98), - InternetDataModel('Nigeria', price: 2.22), - InternetDataModel('Rwanda', price: 0.56), - InternetDataModel('Sao Tome and Principe', price: 5.33), - InternetDataModel('Saint Helena', price: 55.47), - InternetDataModel('Senegal', price: 3.28), - InternetDataModel('Seychelles', price: 19.55), - InternetDataModel('Somalia', price: 6.19), - InternetDataModel('Somaliland'), - InternetDataModel('South Africa', price: 7.19), - InternetDataModel('S. Sudan', countryName: 'South Sudan'), - InternetDataModel('Sudan', price: 0.68), - InternetDataModel('Swaziland', price: 12.14), - InternetDataModel('Tanzania', price: 5.93), - InternetDataModel('Tunisia', price: 2.87), - InternetDataModel('W. Sahara', - price: 1.66, countryName: 'Western Sahara'), - InternetDataModel('Zambia', price: 2.25), - InternetDataModel('Zimbabwe', price: 75.2), + _InternetPrice('Eritrea'), + _InternetPrice('Guinea', price: 1.97), + _InternetPrice('Kenya', price: 2.73), + _InternetPrice('Madagascar', price: 3.39), + _InternetPrice('Malawi', price: 3.59), + _InternetPrice('Mali', price: 9.22), + _InternetPrice('Mauritania', price: 3.12), + _InternetPrice('Mauritius', price: 3.71), + _InternetPrice('Mayotte', price: 10.18), + _InternetPrice('Morocco', price: 1.6), + _InternetPrice('Mozambique', price: 15.82), + _InternetPrice('Namibia', price: 11.02), + _InternetPrice('Niger', price: 2.98), + _InternetPrice('Nigeria', price: 2.22), + _InternetPrice('Rwanda', price: 0.56), + _InternetPrice('Sao Tome and Principe', price: 5.33), + _InternetPrice('Saint Helena', price: 55.47), + _InternetPrice('Senegal', price: 3.28), + _InternetPrice('Seychelles', price: 19.55), + _InternetPrice('Somalia', price: 6.19), + _InternetPrice('Somaliland'), + _InternetPrice('South Africa', price: 7.19), + _InternetPrice('S. Sudan', countryName: 'South Sudan'), + _InternetPrice('Sudan', price: 0.68), + _InternetPrice('Swaziland', price: 12.14), + _InternetPrice('Tanzania', price: 5.93), + _InternetPrice('Tunisia', price: 2.87), + _InternetPrice('W. Sahara', price: 1.66, countryName: 'Western Sahara'), + _InternetPrice('Zambia', price: 2.25), + _InternetPrice('Zimbabwe', price: 75.2), ]; _shapeColorMappers = [ @@ -274,207 +274,229 @@ class _MapLegendPageState extends SampleViewState { _mapBubbleSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', - dataCount: _bubbleInternetData.length, + dataCount: _internetPriceForBubbles.length, primaryValueMapper: (int index) => - _bubbleInternetData[index].actualCountryName, - bubbleSizeMapper: (int index) => _bubbleInternetData[index].price, - bubbleColorValueMapper: (int index) => _bubbleInternetData[index].price, + _internetPriceForBubbles[index].actualCountryName, + bubbleSizeMapper: (int index) => _internetPriceForBubbles[index].price, + bubbleColorValueMapper: (int index) => + _internetPriceForBubbles[index].price, bubbleColorMappers: _bubbleColorMappers, ); _mapShapeSource = MapShapeSource.asset( 'assets/africa.json', shapeDataField: 'name', - dataCount: _shapeInternetData.length, + dataCount: _internetPriceForShapes.length, primaryValueMapper: (int index) => - _shapeInternetData[index].actualCountryName, - shapeColorValueMapper: (int index) => _shapeInternetData[index].price, + _internetPriceForShapes[index].actualCountryName, + shapeColorValueMapper: (int index) => + _internetPriceForShapes[index].price, shapeColorMappers: _shapeColorMappers, ); _dropDownMenuItems = _getDropDownMenuItems(); - _currentLegend = _dropDownMenuItems[0].value; + _currentLegend = _dropDownMenuItems[0].value!; } @override void dispose() { - _shapeInternetData?.clear(); - _bubbleInternetData?.clear(); - _shapeColorMappers?.clear(); - _bubbleColorMappers?.clear(); - _shapeBarLegendColorMappers?.clear(); - _bubbleBarLegendColorMappers?.clear(); + _internetPriceForShapes.clear(); + _internetPriceForBubbles.clear(); + _shapeColorMappers.clear(); + _bubbleColorMappers.clear(); + _shapeBarLegendColorMappers.clear(); + _bubbleBarLegendColorMappers.clear(); super.dispose(); } List> _getDropDownMenuItems() { - List> legendItems = List() - ..add(DropdownMenuItem(value: 'Default', child: Text('Default'))) - ..add(DropdownMenuItem(value: 'Bar', child: Text('Bar'))); + final List> legendItems = [ + DropdownMenuItem(value: 'Default', child: Text('Default')), + DropdownMenuItem(value: 'Bar', child: Text('Bar')) + ]; return legendItems; } @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget() + model.isWebFullView + ? _buildMapsWidget() : SingleChildScrollView( - child: Container(height: 400, child: _getMapsWidget())); + child: Container(height: 400, child: _buildMapsWidget())); } - Widget _getMapsWidget() { - bool isLightTheme = model?.themeData?.brightness == Brightness.light; + Widget _buildMapsWidget() { + final bool isLightTheme = model.themeData.brightness == Brightness.light; return Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - right: 10, - left: 5) - : const EdgeInsets.only(left: 5, right: 10), - child: SfMapsTheme( - data: SfMapsThemeData( - brightness: model?.themeData?.brightness, - shapeHoverColor: _showBubbleData - ? Colors.transparent - : (isLightTheme - ? const Color.fromRGBO(204, 204, 204, 0.8) - : const Color.fromRGBO(77, 77, 77, 0.8)), - shapeHoverStrokeColor: _showBubbleData - ? Colors.transparent - : (isLightTheme - ? const Color.fromRGBO(158, 158, 158, 1) - : const Color.fromRGBO(255, 255, 255, 1)), - bubbleHoverColor: _showBubbleData - ? (isLightTheme - ? const Color.fromRGBO(204, 204, 204, 0.8) - : const Color.fromRGBO(115, 115, 115, 0.8)) - : Colors.transparent, - bubbleHoverStrokeColor: _showBubbleData - ? const Color.fromRGBO(158, 158, 158, 1) - : Colors.transparent, - toggledItemColor: Colors.transparent, - toggledItemStrokeColor: _showBubbleData ? Colors.transparent : null, - ), - child: SfMaps( - title: const MapTitle( - 'Average Internet Prices in Africa', - padding: EdgeInsets.only(top: 15, bottom: 30), + padding: MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + right: 10, + left: 5) + : const EdgeInsets.only(left: 5, right: 10), + child: SfMapsTheme( + data: SfMapsThemeData( + brightness: model.themeData.brightness, + shapeHoverColor: _showBubbleData + ? Colors.transparent + : (isLightTheme + ? const Color.fromRGBO(204, 204, 204, 0.8) + : const Color.fromRGBO(77, 77, 77, 0.8)), + shapeHoverStrokeColor: _showBubbleData + ? Colors.transparent + : (isLightTheme + ? const Color.fromRGBO(158, 158, 158, 1) + : const Color.fromRGBO(255, 255, 255, 1)), + bubbleHoverColor: _showBubbleData + ? (isLightTheme + ? const Color.fromRGBO(204, 204, 204, 0.8) + : const Color.fromRGBO(115, 115, 115, 0.8)) + : Colors.transparent, + bubbleHoverStrokeColor: _showBubbleData + ? const Color.fromRGBO(158, 158, 158, 1) + : Colors.transparent, + toggledItemColor: Colors.transparent, + toggledItemStrokeColor: _showBubbleData ? Colors.transparent : null, ), - layers: [ - MapShapeLayer( - loadingBuilder: (BuildContext context) { - return Container( - height: 25, - width: 25, - child: const CircularProgressIndicator( - strokeWidth: 3, - ), - ); - }, + child: Column(children: [ + Padding( + padding: EdgeInsets.only(top: 15, bottom: 30), + child: Align( + alignment: Alignment.center, + child: Text('Average Internet Prices in Africa', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( + layers: [ + MapShapeLayer( + loadingBuilder: (BuildContext context) { + return Container( + height: 25, + width: 25, + child: const CircularProgressIndicator( + strokeWidth: 3, + ), + ); + }, - /// Changing the data based on whether data will be - /// visualized using the shape colors or bubbles. - source: _showBubbleData ? _mapBubbleSource : _mapShapeSource, - // Returns the custom tooltip for each shape. - shapeTooltipBuilder: _showBubbleData - ? null - : (BuildContext context, int index) { - if (_shapeInternetData[index].price == null) { - return null; - } - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - 'Country : ' + - (_shapeInternetData[index].countryName ?? - _shapeInternetData[index].actualCountryName) + - '\nPrice : \$' + - _shapeInternetData[index].price.toString(), - style: Theme.of(context).textTheme.caption.copyWith( - color: isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(10, 10, 10, 1), - ), - ), - ); - }, - // Returns the custom tooltip for each bubble. - bubbleTooltipBuilder: _showBubbleData - ? (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - 'Country : ' + - (_bubbleInternetData[index].countryName ?? - _bubbleInternetData[index] - .actualCountryName) + - '\nPrice : \$' + - _bubbleInternetData[index].price.toString(), - style: Theme.of(context).textTheme.caption.copyWith( - color: isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(10, 10, 10, 1), - ), + /// Changing the data based on whether data will be + /// visualized using the shape colors or bubbles. + source: _showBubbleData ? _mapBubbleSource : _mapShapeSource, + // Returns the custom tooltip for each shape. + shapeTooltipBuilder: _showBubbleData + ? null + : (BuildContext context, int index) { + if (_internetPriceForShapes[index].price == null) { + return SizedBox(); + } + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Country : ' + + (_internetPriceForShapes[index].countryName ?? + _internetPriceForShapes[index] + .actualCountryName) + + '\nPrice : \$' + + _internetPriceForShapes[index] + .price + .toString(), + style: + Theme.of(context).textTheme.caption!.copyWith( + color: isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(10, 10, 10, 1), + ), + ), + ); + }, + // Returns the custom tooltip for each bubble. + bubbleTooltipBuilder: _showBubbleData + ? (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Country : ' + + (_internetPriceForBubbles[index] + .countryName ?? + _internetPriceForBubbles[index] + .actualCountryName) + + '\nPrice : \$' + + _internetPriceForBubbles[index] + .price + .toString(), + style: + Theme.of(context).textTheme.caption!.copyWith( + color: isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(10, 10, 10, 1), + ), + ), + ); + } + : null, + color: _showBubbleData + ? (isLightTheme + ? Color.fromRGBO(204, 204, 204, 1) + : Color.fromRGBO(103, 103, 103, 1)) + : null, + strokeColor: _showBubbleData + ? (isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(49, 49, 49, 1)) + : Color.fromRGBO(255, 255, 255, 1), + bubbleSettings: MapBubbleSettings( + minRadius: 13, + maxRadius: 20, + strokeColor: Colors.black, + strokeWidth: 0.5, + ), + legend: _showBarLegend + ? MapLegend.bar( + /// You can show legend for the shapes or bubbles. By + /// default, the legend will not be shown. + _showBubbleData + ? MapElement.bubble + : MapElement.shape, + edgeLabelsPlacement: + MapLegendEdgeLabelsPlacement.inside, + labelsPlacement: + MapLegendLabelsPlacement.betweenItems, + position: MapLegendPosition.top, + spacing: _enableGradient ? 10.0 : 1.0, + segmentPaintingStyle: _enableGradient + ? MapLegendPaintingStyle.gradient + : MapLegendPaintingStyle.solid, + segmentSize: _enableGradient + ? Size(300.0, 9.0) + : Size(55.0, 9.0), + padding: EdgeInsets.only(bottom: 20), + ) + : MapLegend( + /// You can show legend for the shapes or bubbles. By + /// default, the legend will not be shown. + _showBubbleData + ? MapElement.bubble + : MapElement.shape, + position: MapLegendPosition.left, + offset: Offset( + MediaQuery.of(context).size.width * + (model.isWebFullView ? 0.25 : 0.12), + 50), + iconType: MapIconType.rectangle, + enableToggleInteraction: _enableToggleInteraction, ), - ); - } - : null, - color: _showBubbleData - ? (isLightTheme - ? Color.fromRGBO(204, 204, 204, 1) - : Color.fromRGBO(103, 103, 103, 1)) - : null, - strokeColor: _showBubbleData - ? (isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(49, 49, 49, 1)) - : Color.fromRGBO(255, 255, 255, 1), - bubbleSettings: MapBubbleSettings( - minRadius: 13, - maxRadius: 20, - strokeColor: Colors.black, - strokeWidth: 0.5, - ), - legend: _showBarLegend - ? MapLegend.bar( - /// You can show legend for the shapes or bubbles. By - /// default, the legend will not be shown. - _showBubbleData ? MapElement.bubble : MapElement.shape, - edgeLabelsPlacement: MapLegendEdgeLabelsPlacement.inside, - labelsPlacement: MapLegendLabelsPlacement.betweenItems, - position: MapLegendPosition.top, - spacing: _enableGradient ? 10.0 : 1.0, - segmentPaintingStyle: _enableGradient - ? MapLegendPaintingStyle.gradient - : MapLegendPaintingStyle.solid, - segmentSize: - _enableGradient ? Size(300.0, 9.0) : Size(55.0, 9.0), - padding: EdgeInsets.only(bottom: 20), - ) - : MapLegend( - /// You can show legend for the shapes or bubbles. By - /// default, the legend will not be shown. - _showBubbleData ? MapElement.bubble : MapElement.shape, - position: MapLegendPosition.left, - offset: Offset( - MediaQuery.of(context).size.width * - (model.isWeb ? 0.25 : 0.12), - 50), - iconType: MapIconType.rectangle, - enableToggleInteraction: _enableToggleInteraction, - ), - tooltipSettings: MapTooltipSettings( - color: isLightTheme - ? Color.fromRGBO(45, 45, 45, 1) - : Color.fromRGBO(242, 242, 242, 1), - ), - ), - ], - ), - ), - ); + tooltipSettings: MapTooltipSettings( + color: isLightTheme + ? Color.fromRGBO(45, 45, 45, 1) + : Color.fromRGBO(242, 242, 242, 1), + ), + ), + ], + )), + ]), + )); } @override @@ -482,187 +504,184 @@ class _MapLegendPageState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return SingleChildScrollView( - child: Container( - height: 220, - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Legend type", - style: TextStyle( - color: model.textColor, - fontSize: 16, - ), - ), - Padding( - padding: EdgeInsets.only(right: 15.0), - child: DropdownButton( - value: _currentLegend, - items: _dropDownMenuItems, - onChanged: (String value) { - setState(() { - _currentLegend = value; - if (_currentLegend == 'Bar') { - _showBarLegend = true; - _mapBubbleSource = MapShapeSource.asset( - 'assets/africa.json', - shapeDataField: 'name', - dataCount: _bubbleInternetData.length, - primaryValueMapper: (int index) => - _bubbleInternetData[index] - .actualCountryName, - bubbleSizeMapper: (int index) => - _bubbleInternetData[index].price, - bubbleColorValueMapper: (int index) => - _bubbleInternetData[index].price, - bubbleColorMappers: - _bubbleBarLegendColorMappers, - ); + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Legend type', + style: TextStyle( + color: model.textColor, + fontSize: 16, + ), + ), + Padding( + padding: EdgeInsets.only(right: 15.0), + child: DropdownButton( + value: _currentLegend, + items: _dropDownMenuItems, + onChanged: (String? value) { + setState(() { + _currentLegend = value!; + if (_currentLegend == 'Bar') { + _showBarLegend = true; + _mapBubbleSource = MapShapeSource.asset( + 'assets/africa.json', + shapeDataField: 'name', + dataCount: _internetPriceForBubbles.length, + primaryValueMapper: (int index) => + _internetPriceForBubbles[index] + .actualCountryName, + bubbleSizeMapper: (int index) => + _internetPriceForBubbles[index].price, + bubbleColorValueMapper: (int index) => + _internetPriceForBubbles[index].price, + bubbleColorMappers: _bubbleBarLegendColorMappers, + ); - _mapShapeSource = MapShapeSource.asset( - 'assets/africa.json', - shapeDataField: 'name', - dataCount: _shapeInternetData.length, - primaryValueMapper: (int index) => - _shapeInternetData[index] - .actualCountryName, - shapeColorValueMapper: (int index) => - _shapeInternetData[index].price, - shapeColorMappers: - _shapeBarLegendColorMappers, - ); - } else { - _showBarLegend = false; - _mapBubbleSource = MapShapeSource.asset( - 'assets/africa.json', - shapeDataField: 'name', - dataCount: _bubbleInternetData.length, - primaryValueMapper: (int index) => - _bubbleInternetData[index] - .actualCountryName, - bubbleSizeMapper: (int index) => - _bubbleInternetData[index].price, - bubbleColorValueMapper: (int index) => - _bubbleInternetData[index].price, - bubbleColorMappers: _bubbleColorMappers, - ); + _mapShapeSource = MapShapeSource.asset( + 'assets/africa.json', + shapeDataField: 'name', + dataCount: _internetPriceForShapes.length, + primaryValueMapper: (int index) => + _internetPriceForShapes[index] + .actualCountryName, + shapeColorValueMapper: (int index) => + _internetPriceForShapes[index].price, + shapeColorMappers: _shapeBarLegendColorMappers, + ); + } else { + _showBarLegend = false; + _mapBubbleSource = MapShapeSource.asset( + 'assets/africa.json', + shapeDataField: 'name', + dataCount: _internetPriceForBubbles.length, + primaryValueMapper: (int index) => + _internetPriceForBubbles[index] + .actualCountryName, + bubbleSizeMapper: (int index) => + _internetPriceForBubbles[index].price, + bubbleColorValueMapper: (int index) => + _internetPriceForBubbles[index].price, + bubbleColorMappers: _bubbleColorMappers, + ); - _mapShapeSource = MapShapeSource.asset( - 'assets/africa.json', - shapeDataField: 'name', - dataCount: _shapeInternetData.length, - primaryValueMapper: (int index) => - _shapeInternetData[index] - .actualCountryName, - shapeColorValueMapper: (int index) => - _shapeInternetData[index].price, - shapeColorMappers: _shapeColorMappers, - ); - } - stateSetter(() {}); - }); - }, - )) - ], - ), - Row( - children: [ - Expanded( - child: Text( - 'Enable legend for bubbles', - style: TextStyle( - color: model.textColor, - fontSize: 16, - ), - ), - ), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _showBubbleData, - onChanged: (bool value) { - setState(() { - _showBubbleData = value; - stateSetter(() {}); - }); - })), - ], + _mapShapeSource = MapShapeSource.asset( + 'assets/africa.json', + shapeDataField: 'name', + dataCount: _internetPriceForShapes.length, + primaryValueMapper: (int index) => + _internetPriceForShapes[index] + .actualCountryName, + shapeColorValueMapper: (int index) => + _internetPriceForShapes[index].price, + shapeColorMappers: _shapeColorMappers, + ); + } + stateSetter(() {}); + }); + }, + )) + ], + ), + Row( + children: [ + Expanded( + child: Text( + 'Enable legend for bubbles', + style: TextStyle( + color: model.textColor, + fontSize: 16, ), - Row( - children: [ - Expanded( - child: Text( - 'Enable toggle interaction', - style: TextStyle( - color: _showBarLegend - ? model.textColor.withOpacity(0.5) - : model.textColor, - fontSize: 16, - ), - ), - ), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _enableToggleInteraction, - onChanged: !_showBarLegend - ? (bool value) { - setState(() { - _enableToggleInteraction = value; - stateSetter(() {}); - }); - } - : null), - ), - ], + ), + ), + Container( + width: 90, + child: CheckboxListTile( + activeColor: model.backgroundColor, + value: _showBubbleData, + onChanged: (bool? value) { + setState(() { + _showBubbleData = value!; + stateSetter(() {}); + }); + })), + ], + ), + Row( + children: [ + Expanded( + child: Text( + 'Enable toggle interaction', + style: TextStyle( + color: _showBarLegend + ? model.textColor.withOpacity(0.5) + : model.textColor, + fontSize: 16, ), - Row( - children: [ - Expanded( - child: Text( - 'Enable gradient', - style: TextStyle( - color: _showBarLegend - ? model.textColor - : model.textColor.withOpacity(0.5), - fontSize: 16, - ), - ), - ), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _enableGradient, - onChanged: _showBarLegend - ? (bool value) { - setState(() { - _enableGradient = value; - stateSetter(() {}); - }); - } - : null), - ), - ], + ), + ), + Container( + width: 90, + child: CheckboxListTile( + activeColor: model.backgroundColor, + value: _enableToggleInteraction, + onChanged: !_showBarLegend + ? (bool? value) { + setState(() { + _enableToggleInteraction = value!; + stateSetter(() {}); + }); + } + : null), + ), + ], + ), + Row( + children: [ + Expanded( + child: Text( + 'Enable gradient', + style: TextStyle( + color: _showBarLegend + ? model.textColor + : model.textColor.withOpacity(0.5), + fontSize: 16, ), - ], - ))); + ), + ), + Container( + width: 90, + child: CheckboxListTile( + activeColor: model.backgroundColor, + value: _enableGradient, + onChanged: _showBarLegend + ? (bool? value) { + setState(() { + _enableGradient = value!; + stateSetter(() {}); + }); + } + : null), + ), + ], + ), + ], + )); }); } } -class InternetDataModel { - const InternetDataModel( +class _InternetPrice { + const _InternetPrice( this.actualCountryName, { this.price, this.countryName, }); final String actualCountryName; - final double price; - final String countryName; + final double? price; + final String? countryName; } diff --git a/lib/samples/maps/shape_layer/marker/marker.dart b/lib/samples/maps/shape_layer/marker/marker.dart index d172fcba..11de7da6 100644 --- a/lib/samples/maps/shape_layer/marker/marker.dart +++ b/lib/samples/maps/shape_layer/marker/marker.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart' show DateFormat; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Core theme import @@ -24,7 +25,8 @@ class MapMarkerPage extends SampleView { } class _MapMarkerPageState extends SampleViewState { - List<_ClockModel> _clockModelData; + late List<_TimeDetails> _worldClockData; + late MapShapeSource _mapSource; @override void initState() { @@ -33,60 +35,75 @@ class _MapMarkerPageState extends SampleViewState { final DateTime _currentTime = DateTime.now().toUtc(); // Data source to the map markers. - _clockModelData = <_ClockModel>[ - _ClockModel('Seattle', 47.60621, -122.332071, + _worldClockData = <_TimeDetails>[ + _TimeDetails('Seattle', 47.60621, -122.332071, _currentTime.subtract(const Duration(hours: 7))), - _ClockModel('Belem', -1.455833, -48.503887, + _TimeDetails('Belem', -1.455833, -48.503887, _currentTime.subtract(const Duration(hours: 3))), - _ClockModel('Greenland', 71.706936, -42.604303, + _TimeDetails('Greenland', 71.706936, -42.604303, _currentTime.subtract(const Duration(hours: 2))), - _ClockModel('Yakutsk', 62.035452, 129.675475, + _TimeDetails('Yakutsk', 62.035452, 129.675475, _currentTime.add(const Duration(hours: 9))), - _ClockModel('Delhi', 28.704059, 77.10249, + _TimeDetails('Delhi', 28.704059, 77.10249, _currentTime.add(const Duration(hours: 5, minutes: 30))), - _ClockModel('Brisbane', -27.469771, 153.025124, + _TimeDetails('Brisbane', -27.469771, 153.025124, _currentTime.add(const Duration(hours: 10))), - _ClockModel('Harare', -17.825166, 31.03351, + _TimeDetails('Harare', -17.825166, 31.03351, _currentTime.add(const Duration(hours: 2))), ]; + + _mapSource = MapShapeSource.asset( + // Path of the GeoJSON file. + 'assets/world_map.json', + // Field or group name in the .json file to identify + // the shapes. + // + // Which is used to map the respective shape to + // data source. + shapeDataField: 'name', + ); } @override void dispose() { - _clockModelData?.clear(); + _worldClockData.clear(); super.dispose(); } @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget() - : SingleChildScrollView(child: _getMapsWidget()); + model.isWebFullView + ? _buildMapsWidget() + : SingleChildScrollView(child: _buildMapsWidget()); } - Widget _getMapsWidget() { + Widget _buildMapsWidget() { return Center( - child: Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.1, - right: 10, - left: 10) - : const EdgeInsets.only(left: 10, right: 10, bottom: 10), - child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Colors.transparent, - shapeHoverStrokeColor: Colors.transparent, - shapeHoverStrokeWidth: 0, - ), - child: SfMaps( - title: const MapTitle( - 'World Clock', + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.1, + right: 10, + left: 10) + : const EdgeInsets.only(left: 10, right: 10, bottom: 10), + child: SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + shapeHoverStrokeColor: Colors.transparent, + shapeHoverStrokeWidth: 0, + ), + child: Column(children: [ + Padding( padding: EdgeInsets.only(top: 15, bottom: 30), - ), + child: Align( + alignment: Alignment.center, + child: Text('World Clock', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( layers: [ MapShapeLayer( loadingBuilder: (BuildContext context) { @@ -98,16 +115,7 @@ class _MapMarkerPageState extends SampleViewState { ), ); }, - source: MapShapeSource.asset( - // Path of the GeoJSON file. - 'assets/world_map.json', - // Field or group name in the .json file to identify - // the shapes. - // - // Which is used to map the respective shape to - // data source. - shapeDataField: 'name', - ), + source: _mapSource, // The number of initial markers. // // The callback for the [markerBuilder] will be called @@ -115,12 +123,13 @@ class _MapMarkerPageState extends SampleViewState { initialMarkersCount: 7, markerBuilder: (_, int index) { return MapMarker( - longitude: _clockModelData[index].longitude, - latitude: _clockModelData[index].latitude, - child: _ClockWidget( - countryName: _clockModelData[index].countryName, - date: _clockModelData[index].date), - size: const Size(150, 150)); + longitude: _worldClockData[index].longitude, + latitude: _worldClockData[index].latitude, + size: const Size(150, 150), + child: _ClockWidget( + countryName: _worldClockData[index].countryName, + date: _worldClockData[index].date), + ); }, strokeWidth: 0, color: model.themeData.brightness == Brightness.light @@ -128,15 +137,16 @@ class _MapMarkerPageState extends SampleViewState { : const Color.fromRGBO(71, 70, 75, 1), ), ], - ), - ), + )), + ]), ), - ); + )); } } class _ClockWidget extends StatefulWidget { - const _ClockWidget({Key key, this.countryName, this.date}) : super(key: key); + const _ClockWidget({Key? key, required this.countryName, required this.date}) + : super(key: key); final String countryName; final DateTime date; @@ -146,9 +156,9 @@ class _ClockWidget extends StatefulWidget { } class _ClockWidgetState extends State<_ClockWidget> { - String _currentTime; - DateTime _date; - Timer _timer; + late String _currentTime; + late DateTime _date; + Timer? _timer; @override void initState() { @@ -161,7 +171,7 @@ class _ClockWidgetState extends State<_ClockWidget> { @override void dispose() { - _timer.cancel(); + _timer?.cancel(); _timer = null; super.dispose(); } @@ -187,12 +197,12 @@ class _ClockWidgetState extends State<_ClockWidget> { widget.countryName, style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith(fontWeight: FontWeight.bold), ), Center( child: Text(_currentTime, - style: Theme.of(context).textTheme.overline.copyWith( + style: Theme.of(context).textTheme.overline!.copyWith( letterSpacing: 0.5, fontWeight: FontWeight.w500)), ), ], @@ -214,8 +224,8 @@ class _ClockWidgetState extends State<_ClockWidget> { } } -class _ClockModel { - _ClockModel(this.countryName, this.latitude, this.longitude, this.date); +class _TimeDetails { + _TimeDetails(this.countryName, this.latitude, this.longitude, this.date); final String countryName; final double latitude; diff --git a/lib/samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart b/lib/samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart index 5fa00100..5ce61a39 100644 --- a/lib/samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart +++ b/lib/samples/maps/shape_layer/range_color_mapping/range_color_mapping.dart @@ -6,6 +6,7 @@ import 'package:intl/intl.dart' show NumberFormat; import 'package:syncfusion_flutter_core/theme.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import @@ -22,11 +23,13 @@ class MapRangeColorMappingPage extends SampleView { } class _MapRangeColorMappingPageState extends SampleViewState { - List<_CountryDensityModel> _worldPopulationDensityDetails; + late List<_CountryDensity> _worldPopulationDensity; // The format which is used for formatting the tooltip text. final NumberFormat _numberFormat = NumberFormat('#.#'); + late MapShapeSource _mapSource; + @override void initState() { super.initState(); @@ -40,406 +43,414 @@ class _MapRangeColorMappingPageState extends SampleViewState { // // [density]: On the basis of this value, color mapping color has been // applied to the shape. - _worldPopulationDensityDetails = <_CountryDensityModel>[ - _CountryDensityModel('Monaco', 26337), - _CountryDensityModel('Macao', 21717), - _CountryDensityModel('Singapore', 8358), - _CountryDensityModel('Hong kong', 7140), - _CountryDensityModel('Gibraltar', 3369), - _CountryDensityModel('Bahrain', 2239), - _CountryDensityModel('Holy See', 1820), - _CountryDensityModel('Maldives', 1802), - _CountryDensityModel('Malta', 1380), - _CountryDensityModel('Bangladesh', 1265), - _CountryDensityModel('Sint Maarten', 1261), - _CountryDensityModel('Bermuda', 1246), - _CountryDensityModel('Channel Islands', 915), - _CountryDensityModel('State of Palestine', 847), - _CountryDensityModel('Saint-Martin', 729), - _CountryDensityModel('Mayotte', 727), - _CountryDensityModel('Taiwan', 672), - _CountryDensityModel('Barbados', 668), - _CountryDensityModel('Lebanon', 667), - _CountryDensityModel('Mauritius', 626), - _CountryDensityModel('Aruba', 593), - _CountryDensityModel('San Marino', 565), - _CountryDensityModel('Nauru', 541), - _CountryDensityModel('Korea', 527), - _CountryDensityModel('Rwanda', 525), - _CountryDensityModel('Netherlands', 508), - _CountryDensityModel('Comoros', 467), - _CountryDensityModel('India', 464), - _CountryDensityModel('Burundi', 463), - _CountryDensityModel('Saint-Barthélemy', 449), - _CountryDensityModel('Haiti', 413), - _CountryDensityModel('Israel', 400), - _CountryDensityModel('Tuvalu', 393), - _CountryDensityModel('Belgium', 382), - _CountryDensityModel('Curacao', 369), - _CountryDensityModel('Philippines', 367), - _CountryDensityModel('Reunion', 358), - _CountryDensityModel('Martinique', 354), - _CountryDensityModel('Japan', 346), - _CountryDensityModel('Sri Lanka', 341), - _CountryDensityModel('Grenada', 331), - _CountryDensityModel('Marshall Islands', 328), - _CountryDensityModel('Puerto Rico', 322), - _CountryDensityModel('Vietnam', 313), - _CountryDensityModel('El Salvador', 313), - _CountryDensityModel('Guam', 312), - _CountryDensityModel('Saint Lucia', 301), - _CountryDensityModel('United States Virgin Islands', 298), - _CountryDensityModel('Pakistan', 286), - _CountryDensityModel('Saint Vincent and the Grenadines', 284), - _CountryDensityModel('United Kingdom', 280), - _CountryDensityModel('American Samoa', 276), - _CountryDensityModel('Cayman Islands', 273), - _CountryDensityModel('Jamaica', 273), - _CountryDensityModel('Trinidad and Tobago', 272), - _CountryDensityModel('Qatar', 248), - _CountryDensityModel('Guadeloupe', 245), - _CountryDensityModel('Luxembourg', 241), - _CountryDensityModel('Germany', 240), - _CountryDensityModel('Kuwait', 239), - _CountryDensityModel('Gambia', 238), - _CountryDensityModel('Liechtenstein', 238), - _CountryDensityModel('Uganda', 228), - _CountryDensityModel('Sao Tome and Principe', 228), - _CountryDensityModel('Nigeria', 226), - _CountryDensityModel('Dominican Rep.', 224), - _CountryDensityModel('Antigua and Barbuda', 222), - _CountryDensityModel('Switzerland', 219), - _CountryDensityModel('Dem. Rep. Korea', 214), - _CountryDensityModel('Seychelles', 213), - _CountryDensityModel('Italy', 205), - _CountryDensityModel('Saint Kitts and Nevis', 204), - _CountryDensityModel('Nepal', 203), - _CountryDensityModel('Malawi', 202), - _CountryDensityModel('British Virgin Islands', 201), - _CountryDensityModel('Guatemala', 167), - _CountryDensityModel('Anguilla', 166), - _CountryDensityModel('Andorra', 164), - _CountryDensityModel('Micronesia', 164), - _CountryDensityModel('China', 153), - _CountryDensityModel('Togo', 152), - _CountryDensityModel('Indonesia', 151), - _CountryDensityModel('Isle of Man', 149), - _CountryDensityModel('Kiribati', 147), - _CountryDensityModel('Tonga', 146), - _CountryDensityModel('Czech Rep.', 138), - _CountryDensityModel('Cabo Verde', 138), - _CountryDensityModel('Thailand', 136), - _CountryDensityModel('Ghana', 136), - _CountryDensityModel('Denmark', 136), - _CountryDensityModel('Tokelau', 135), - _CountryDensityModel('Cyprus', 130), - _CountryDensityModel('Northern Mariana Islands', 125), - _CountryDensityModel('Poland', 123), - _CountryDensityModel('Moldova', 122), - _CountryDensityModel('Azerbaijan', 122), - _CountryDensityModel('France', 119), - _CountryDensityModel('United Arab Emirates', 118), - _CountryDensityModel('Ethiopia', 115), - _CountryDensityModel('Jordan', 114), - _CountryDensityModel('Slovakia', 113), - _CountryDensityModel('Portugal', 111), - _CountryDensityModel('Sierra Leone', 110), - _CountryDensityModel('Turkey', 109), - _CountryDensityModel('Austria', 109), - _CountryDensityModel('Benin', 107), - _CountryDensityModel('Hungary', 106), - _CountryDensityModel('Cuba', 106), - _CountryDensityModel('Albania', 105), - _CountryDensityModel('Armenia', 104), - _CountryDensityModel('Slovenia', 103), - _CountryDensityModel('Egypt', 102), - _CountryDensityModel('Serbia', 99), - _CountryDensityModel('Costa Rica', 99), - _CountryDensityModel('Malaysia', 98), - _CountryDensityModel('Dominica', 95), - _CountryDensityModel('Syria', 95), - _CountryDensityModel('Cambodia', 94), - _CountryDensityModel('Kenya', 94), - _CountryDensityModel('Spain', 93), - _CountryDensityModel('Iraq', 92), - _CountryDensityModel('Timor-Leste', 88), - _CountryDensityModel('Honduras', 88), - _CountryDensityModel('Senegal', 86), - _CountryDensityModel('Romania', 83), - _CountryDensityModel('Myanmar', 83), - _CountryDensityModel('Brunei Darussalam', 83), - _CountryDensityModel("Côte d'Ivoire", 82), - _CountryDensityModel('Morocco', 82), - _CountryDensityModel('Macedonia', 82), - _CountryDensityModel('Greece', 80), - _CountryDensityModel('Wallis and Futuna Islands', 80), - _CountryDensityModel('Bonaire, Sint Eustatius and Saba', 79), - _CountryDensityModel('Uzbekistan', 78), - _CountryDensityModel('French Polynesia', 76), - _CountryDensityModel('Burkina Faso', 76), - _CountryDensityModel('Tunisia', 76), - _CountryDensityModel('Ukraine', 75), - _CountryDensityModel('Croatia', 73), - _CountryDensityModel('Cook Islands', 73), - _CountryDensityModel('Ireland', 71), - _CountryDensityModel('Ecuador', 71), - _CountryDensityModel('Lesotho', 70), - _CountryDensityModel('Samoa', 70), - _CountryDensityModel('Guinea-Bissau', 69), - _CountryDensityModel('Tajikistan', 68), - _CountryDensityModel('Eswatini', 67), - _CountryDensityModel('Tanzania', 67), - _CountryDensityModel('Mexico', 66), - _CountryDensityModel('Bosnia and Herz.', 64), - _CountryDensityModel('Bulgaria', 64), - _CountryDensityModel('Afghanistan', 59), - _CountryDensityModel('Panama', 58), - _CountryDensityModel('Georgia', 57), - _CountryDensityModel('Yemen', 56), - _CountryDensityModel('Cameroon', 56), - _CountryDensityModel('Nicaragua', 55), - _CountryDensityModel('Guinea', 53), - _CountryDensityModel('Liberia', 52), - _CountryDensityModel('Iran', 51), - _CountryDensityModel('Eq. Guinea', 50), - _CountryDensityModel('Montserrat', 49), - _CountryDensityModel('Fiji', 49), - _CountryDensityModel('South Africa', 48), - _CountryDensityModel('Madagascar', 47), - _CountryDensityModel('Montenegro', 46), - _CountryDensityModel('Belarus', 46), - _CountryDensityModel('Colombia', 45), - _CountryDensityModel('Lithuania', 43), - _CountryDensityModel('Djibouti', 42), - _CountryDensityModel('Turks and Caicos Islands', 40), - _CountryDensityModel('Mozambique', 39), - _CountryDensityModel('Dem. Rep. Congo', 39), - _CountryDensityModel('Palau', 39), - _CountryDensityModel('Bahamas', 39), - _CountryDensityModel('Zimbabwe', 38), - _CountryDensityModel('United States of America', 36), - _CountryDensityModel('Eritrea', 35), - _CountryDensityModel('Faroe Islands', 35), - _CountryDensityModel('Kyrgyzstan', 34), - _CountryDensityModel('Venezuela', 32), - _CountryDensityModel('Lao PDR', 31), - _CountryDensityModel('Estonia', 31), - _CountryDensityModel('Latvia', 30), - _CountryDensityModel('Angola', 26), - _CountryDensityModel('Peru', 25), - _CountryDensityModel('Chile', 25), - _CountryDensityModel('Brazil', 25), - _CountryDensityModel('Somalia', 25), - _CountryDensityModel('Vanuatu', 25), - _CountryDensityModel('Saint Pierre and Miquelon', 25), - _CountryDensityModel('Sudan', 24), - _CountryDensityModel('Zambia', 24), - _CountryDensityModel('Sweden', 24), - _CountryDensityModel('Solomon Islands', 24), - _CountryDensityModel('Bhutan', 20), - _CountryDensityModel('Uruguay', 19), - _CountryDensityModel('Papua New Guinea', 19), - _CountryDensityModel('Niger', 19), - _CountryDensityModel('Algeria', 18), - _CountryDensityModel('S. Sudan', 18), - _CountryDensityModel('New Zealand', 18), - _CountryDensityModel('Finland', 18), - _CountryDensityModel('Paraguay', 17), - _CountryDensityModel('Belize', 17), - _CountryDensityModel('Mali', 16), - _CountryDensityModel('Argentina', 16), - _CountryDensityModel('Oman', 16), - _CountryDensityModel('Saudi Arabia', 16), - _CountryDensityModel('Congo', 16), - _CountryDensityModel('New Caledonia', 15), - _CountryDensityModel('Saint Helena', 15), - _CountryDensityModel('Norway', 14), - _CountryDensityModel('Chad', 13), - _CountryDensityModel('Turkmenistan', 12), - _CountryDensityModel('Bolivia', 10), - _CountryDensityModel('Russia', 8), - _CountryDensityModel('Gabon', 8), - _CountryDensityModel('Central African Rep.', 7), - _CountryDensityModel('Kazakhstan', 6), - _CountryDensityModel('Niue', 6), - _CountryDensityModel('Mauritania', 4), - _CountryDensityModel('Canada', 4), - _CountryDensityModel('Botswana', 4), - _CountryDensityModel('Guyana', 3), - _CountryDensityModel('Libya', 3), - _CountryDensityModel('Suriname', 3), - _CountryDensityModel('French Guiana', 3), - _CountryDensityModel('Iceland', 3), - _CountryDensityModel('Australia', 3), - _CountryDensityModel('Namibia', 3), - _CountryDensityModel('W. Sahara', 2), - _CountryDensityModel('Mongolia', 2), - _CountryDensityModel('Falkland Is.', 0.2), - _CountryDensityModel('Greenland', 0.1), + _worldPopulationDensity = <_CountryDensity>[ + _CountryDensity('Monaco', 26337), + _CountryDensity('Macao', 21717), + _CountryDensity('Singapore', 8358), + _CountryDensity('Hong kong', 7140), + _CountryDensity('Gibraltar', 3369), + _CountryDensity('Bahrain', 2239), + _CountryDensity('Holy See', 1820), + _CountryDensity('Maldives', 1802), + _CountryDensity('Malta', 1380), + _CountryDensity('Bangladesh', 1265), + _CountryDensity('Sint Maarten', 1261), + _CountryDensity('Bermuda', 1246), + _CountryDensity('Channel Islands', 915), + _CountryDensity('State of Palestine', 847), + _CountryDensity('Saint-Martin', 729), + _CountryDensity('Mayotte', 727), + _CountryDensity('Taiwan', 672), + _CountryDensity('Barbados', 668), + _CountryDensity('Lebanon', 667), + _CountryDensity('Mauritius', 626), + _CountryDensity('Aruba', 593), + _CountryDensity('San Marino', 565), + _CountryDensity('Nauru', 541), + _CountryDensity('Korea', 527), + _CountryDensity('Rwanda', 525), + _CountryDensity('Netherlands', 508), + _CountryDensity('Comoros', 467), + _CountryDensity('India', 464), + _CountryDensity('Burundi', 463), + _CountryDensity('Saint-Barthélemy', 449), + _CountryDensity('Haiti', 413), + _CountryDensity('Israel', 400), + _CountryDensity('Tuvalu', 393), + _CountryDensity('Belgium', 382), + _CountryDensity('Curacao', 369), + _CountryDensity('Philippines', 367), + _CountryDensity('Reunion', 358), + _CountryDensity('Martinique', 354), + _CountryDensity('Japan', 346), + _CountryDensity('Sri Lanka', 341), + _CountryDensity('Grenada', 331), + _CountryDensity('Marshall Islands', 328), + _CountryDensity('Puerto Rico', 322), + _CountryDensity('Vietnam', 313), + _CountryDensity('El Salvador', 313), + _CountryDensity('Guam', 312), + _CountryDensity('Saint Lucia', 301), + _CountryDensity('United States Virgin Islands', 298), + _CountryDensity('Pakistan', 286), + _CountryDensity('Saint Vincent and the Grenadines', 284), + _CountryDensity('United Kingdom', 280), + _CountryDensity('American Samoa', 276), + _CountryDensity('Cayman Islands', 273), + _CountryDensity('Jamaica', 273), + _CountryDensity('Trinidad and Tobago', 272), + _CountryDensity('Qatar', 248), + _CountryDensity('Guadeloupe', 245), + _CountryDensity('Luxembourg', 241), + _CountryDensity('Germany', 240), + _CountryDensity('Kuwait', 239), + _CountryDensity('Gambia', 238), + _CountryDensity('Liechtenstein', 238), + _CountryDensity('Uganda', 228), + _CountryDensity('Sao Tome and Principe', 228), + _CountryDensity('Nigeria', 226), + _CountryDensity('Dominican Rep.', 224), + _CountryDensity('Antigua and Barbuda', 222), + _CountryDensity('Switzerland', 219), + _CountryDensity('Dem. Rep. Korea', 214), + _CountryDensity('Seychelles', 213), + _CountryDensity('Italy', 205), + _CountryDensity('Saint Kitts and Nevis', 204), + _CountryDensity('Nepal', 203), + _CountryDensity('Malawi', 202), + _CountryDensity('British Virgin Islands', 201), + _CountryDensity('Guatemala', 167), + _CountryDensity('Anguilla', 166), + _CountryDensity('Andorra', 164), + _CountryDensity('Micronesia', 164), + _CountryDensity('China', 153), + _CountryDensity('Togo', 152), + _CountryDensity('Indonesia', 151), + _CountryDensity('Isle of Man', 149), + _CountryDensity('Kiribati', 147), + _CountryDensity('Tonga', 146), + _CountryDensity('Czech Rep.', 138), + _CountryDensity('Cabo Verde', 138), + _CountryDensity('Thailand', 136), + _CountryDensity('Ghana', 136), + _CountryDensity('Denmark', 136), + _CountryDensity('Tokelau', 135), + _CountryDensity('Cyprus', 130), + _CountryDensity('Northern Mariana Islands', 125), + _CountryDensity('Poland', 123), + _CountryDensity('Moldova', 122), + _CountryDensity('Azerbaijan', 122), + _CountryDensity('France', 119), + _CountryDensity('United Arab Emirates', 118), + _CountryDensity('Ethiopia', 115), + _CountryDensity('Jordan', 114), + _CountryDensity('Slovakia', 113), + _CountryDensity('Portugal', 111), + _CountryDensity('Sierra Leone', 110), + _CountryDensity('Turkey', 109), + _CountryDensity('Austria', 109), + _CountryDensity('Benin', 107), + _CountryDensity('Hungary', 106), + _CountryDensity('Cuba', 106), + _CountryDensity('Albania', 105), + _CountryDensity('Armenia', 104), + _CountryDensity('Slovenia', 103), + _CountryDensity('Egypt', 102), + _CountryDensity('Serbia', 99), + _CountryDensity('Costa Rica', 99), + _CountryDensity('Malaysia', 98), + _CountryDensity('Dominica', 95), + _CountryDensity('Syria', 95), + _CountryDensity('Cambodia', 94), + _CountryDensity('Kenya', 94), + _CountryDensity('Spain', 93), + _CountryDensity('Iraq', 92), + _CountryDensity('Timor-Leste', 88), + _CountryDensity('Honduras', 88), + _CountryDensity('Senegal', 86), + _CountryDensity('Romania', 83), + _CountryDensity('Myanmar', 83), + _CountryDensity('Brunei Darussalam', 83), + _CountryDensity("Côte d'Ivoire", 82), + _CountryDensity('Morocco', 82), + _CountryDensity('Macedonia', 82), + _CountryDensity('Greece', 80), + _CountryDensity('Wallis and Futuna Islands', 80), + _CountryDensity('Bonaire, Sint Eustatius and Saba', 79), + _CountryDensity('Uzbekistan', 78), + _CountryDensity('French Polynesia', 76), + _CountryDensity('Burkina Faso', 76), + _CountryDensity('Tunisia', 76), + _CountryDensity('Ukraine', 75), + _CountryDensity('Croatia', 73), + _CountryDensity('Cook Islands', 73), + _CountryDensity('Ireland', 71), + _CountryDensity('Ecuador', 71), + _CountryDensity('Lesotho', 70), + _CountryDensity('Samoa', 70), + _CountryDensity('Guinea-Bissau', 69), + _CountryDensity('Tajikistan', 68), + _CountryDensity('Eswatini', 67), + _CountryDensity('Tanzania', 67), + _CountryDensity('Mexico', 66), + _CountryDensity('Bosnia and Herz.', 64), + _CountryDensity('Bulgaria', 64), + _CountryDensity('Afghanistan', 59), + _CountryDensity('Panama', 58), + _CountryDensity('Georgia', 57), + _CountryDensity('Yemen', 56), + _CountryDensity('Cameroon', 56), + _CountryDensity('Nicaragua', 55), + _CountryDensity('Guinea', 53), + _CountryDensity('Liberia', 52), + _CountryDensity('Iran', 51), + _CountryDensity('Eq. Guinea', 50), + _CountryDensity('Montserrat', 49), + _CountryDensity('Fiji', 49), + _CountryDensity('South Africa', 48), + _CountryDensity('Madagascar', 47), + _CountryDensity('Montenegro', 46), + _CountryDensity('Belarus', 46), + _CountryDensity('Colombia', 45), + _CountryDensity('Lithuania', 43), + _CountryDensity('Djibouti', 42), + _CountryDensity('Turks and Caicos Islands', 40), + _CountryDensity('Mozambique', 39), + _CountryDensity('Dem. Rep. Congo', 39), + _CountryDensity('Palau', 39), + _CountryDensity('Bahamas', 39), + _CountryDensity('Zimbabwe', 38), + _CountryDensity('United States of America', 36), + _CountryDensity('Eritrea', 35), + _CountryDensity('Faroe Islands', 35), + _CountryDensity('Kyrgyzstan', 34), + _CountryDensity('Venezuela', 32), + _CountryDensity('Lao PDR', 31), + _CountryDensity('Estonia', 31), + _CountryDensity('Latvia', 30), + _CountryDensity('Angola', 26), + _CountryDensity('Peru', 25), + _CountryDensity('Chile', 25), + _CountryDensity('Brazil', 25), + _CountryDensity('Somalia', 25), + _CountryDensity('Vanuatu', 25), + _CountryDensity('Saint Pierre and Miquelon', 25), + _CountryDensity('Sudan', 24), + _CountryDensity('Zambia', 24), + _CountryDensity('Sweden', 24), + _CountryDensity('Solomon Islands', 24), + _CountryDensity('Bhutan', 20), + _CountryDensity('Uruguay', 19), + _CountryDensity('Papua New Guinea', 19), + _CountryDensity('Niger', 19), + _CountryDensity('Algeria', 18), + _CountryDensity('S. Sudan', 18), + _CountryDensity('New Zealand', 18), + _CountryDensity('Finland', 18), + _CountryDensity('Paraguay', 17), + _CountryDensity('Belize', 17), + _CountryDensity('Mali', 16), + _CountryDensity('Argentina', 16), + _CountryDensity('Oman', 16), + _CountryDensity('Saudi Arabia', 16), + _CountryDensity('Congo', 16), + _CountryDensity('New Caledonia', 15), + _CountryDensity('Saint Helena', 15), + _CountryDensity('Norway', 14), + _CountryDensity('Chad', 13), + _CountryDensity('Turkmenistan', 12), + _CountryDensity('Bolivia', 10), + _CountryDensity('Russia', 8), + _CountryDensity('Gabon', 8), + _CountryDensity('Central African Rep.', 7), + _CountryDensity('Kazakhstan', 6), + _CountryDensity('Niue', 6), + _CountryDensity('Mauritania', 4), + _CountryDensity('Canada', 4), + _CountryDensity('Botswana', 4), + _CountryDensity('Guyana', 3), + _CountryDensity('Libya', 3), + _CountryDensity('Suriname', 3), + _CountryDensity('French Guiana', 3), + _CountryDensity('Iceland', 3), + _CountryDensity('Australia', 3), + _CountryDensity('Namibia', 3), + _CountryDensity('W. Sahara', 2), + _CountryDensity('Mongolia', 2), + _CountryDensity('Falkland Is.', 0.2), + _CountryDensity('Greenland', 0.1), ]; + + _mapSource = MapShapeSource.asset( + // Path of the GeoJSON file. + 'assets/world_map.json', + // Field or group name in the .json file + // to identify the shapes. + // + // Which is used to map the respective + // shape to data source. + // + // On the basis of this value, + // shape tooltip text is rendered. + shapeDataField: 'name', + // The number of data in your data source collection. + // + // The callback for the [primaryValueMapper] + // will be called the number of times equal + // to the [dataCount]. + // The value returned in the [primaryValueMapper] + // should be exactly matched with the value of the + // [shapeDataField] in the .json file. This is how + // the mapping between the data source and the shapes + // in the .json file is done. + dataCount: _worldPopulationDensity.length, + primaryValueMapper: (int index) => + _worldPopulationDensity[index].countryName, + // Used for color mapping. + // + // The value of the [MapColorMapper.from] + // and [MapColorMapper.to] + // will be compared with the value returned in the + // [shapeColorValueMapper] and the respective + // [MapColorMapper.color] will be applied to the shape. + shapeColorValueMapper: (int index) => + _worldPopulationDensity[index].density, + // Group and differentiate the shapes using the color + // based on [MapColorMapper.from] and + //[MapColorMapper.to] value. + // + // The value of the [MapColorMapper.from] and + // [MapColorMapper.to] will be compared with the value + // returned in the [shapeColorValueMapper] and + // the respective [MapColorMapper.color] will be applied + // to the shape. + // + // [MapColorMapper.text] which is used for the text of + // legend item and [MapColorMapper.color] will be used for + // the color of the legend icon respectively. + shapeColorMappers: const [ + MapColorMapper( + from: 0, + to: 100, + color: Color.fromRGBO(128, 159, 255, 1), + text: '{0},{100}'), + MapColorMapper( + from: 100, + to: 500, + color: Color.fromRGBO(51, 102, 255, 1), + text: '500'), + MapColorMapper( + from: 500, + to: 1000, + color: Color.fromRGBO(0, 57, 230, 1), + text: '1k'), + MapColorMapper( + from: 1000, + to: 5000, + color: Color.fromRGBO(0, 45, 179, 1), + text: '5k'), + MapColorMapper( + from: 5000, + to: 50000, + color: Color.fromRGBO(0, 26, 102, 1), + text: '50k'), + ], + ); } @override void dispose() { - _worldPopulationDensityDetails?.clear(); + _worldPopulationDensity.clear(); super.dispose(); } @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget() - : SingleChildScrollView(child: _getMapsWidget()); + model.isWebFullView + ? _buildMapsWidget() + : SingleChildScrollView(child: _buildMapsWidget()); } - Widget _getMapsWidget() { + Widget _buildMapsWidget() { return Center( - child: Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.05, - right: 10) - : const EdgeInsets.only(right: 10, bottom: 15), - child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Color.fromRGBO(176, 237, 131, 1), - ), - child: SfMaps( - title: const MapTitle( - 'World Population Density (per sq. km.)', + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.05, + right: 10) + : const EdgeInsets.only(right: 10, bottom: 15), + child: SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Color.fromRGBO(176, 237, 131, 1), + ), + child: Column(children: [ + Padding( padding: EdgeInsets.only(top: 15, bottom: 30), - ), - layers: [ - MapShapeLayer( - loadingBuilder: (BuildContext context) { - return Container( - height: 25, - width: 25, - child: const CircularProgressIndicator( - strokeWidth: 3, - ), - ); - }, - source: MapShapeSource.asset( - // Path of the GeoJSON file. - 'assets/world_map.json', - // Field or group name in the .json file - // to identify the shapes. - // - // Which is used to map the respective - // shape to data source. - // - // On the basis of this value, - // shape tooltip text is rendered. - shapeDataField: 'name', - // The number of data in your data source collection. - // - // The callback for the [primaryValueMapper] - // will be called the number of times equal - // to the [dataCount]. - // The value returned in the [primaryValueMapper] - // should be exactly matched with the value of the - // [shapeDataField] in the .json file. This is how - // the mapping between the data source and the shapes - // in the .json file is done. - dataCount: _worldPopulationDensityDetails.length, - primaryValueMapper: (int index) => - _worldPopulationDensityDetails[index].countryName, - // Used for color mapping. - // - // The value of the [MapColorMapper.from] - // and [MapColorMapper.to] - // will be compared with the value returned in the - // [shapeColorValueMapper] and the respective - // [MapColorMapper.color] will be applied to the shape. - shapeColorValueMapper: (int index) => - _worldPopulationDensityDetails[index].density, - // Group and differentiate the shapes using the color - // based on [MapColorMapper.from] and - //[MapColorMapper.to] value. - // - // The value of the [MapColorMapper.from] and - // [MapColorMapper.to] will be compared with the value - // returned in the [shapeColorValueMapper] and - // the respective [MapColorMapper.color] will be applied - // to the shape. - // - // [MapColorMapper.text] which is used for the text of - // legend item and [MapColorMapper.color] will be used for - // the color of the legend icon respectively. - shapeColorMappers: const [ - MapColorMapper( - from: 0, - to: 100, - color: Color.fromRGBO(128, 159, 255, 1), - text: '{0},{100}'), - MapColorMapper( - from: 100, - to: 500, - color: Color.fromRGBO(51, 102, 255, 1), - text: '500'), - MapColorMapper( - from: 500, - to: 1000, - color: Color.fromRGBO(0, 57, 230, 1), - text: '1k'), - MapColorMapper( - from: 1000, - to: 5000, - color: Color.fromRGBO(0, 45, 179, 1), - text: '5k'), - MapColorMapper( - from: 5000, - to: 50000, - color: Color.fromRGBO(0, 26, 102, 1), - text: '50k'), - ], + child: Align( + alignment: Alignment.center, + child: Text('World Population Density (per sq. km.)', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( + layers: [ + MapShapeLayer( + loadingBuilder: (BuildContext context) { + return Container( + height: 25, + width: 25, + child: const CircularProgressIndicator( + strokeWidth: 3, + ), + ); + }, + source: _mapSource, + // Returns the custom tooltip for each shape. + shapeTooltipBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + _worldPopulationDensity[index].countryName + + ' : ' + + _numberFormat + .format( + _worldPopulationDensity[index].density) + .toString() + + ' per sq. km.', + style: Theme.of(context).textTheme.caption!.copyWith( + color: Theme.of(context).colorScheme.surface)), + ); + }, + strokeColor: Colors.white30, + legend: MapLegend.bar(MapElement.shape, + position: MapLegendPosition.bottom, + overflowMode: MapLegendOverflowMode.wrap, + labelsPlacement: MapLegendLabelsPlacement.betweenItems, + padding: EdgeInsets.only(top: 15), + spacing: 1.0, + segmentSize: Size(55.0, 9.0)), + tooltipSettings: MapTooltipSettings( + color: model.themeData.brightness == Brightness.light + ? const Color.fromRGBO(0, 32, 128, 1) + : const Color.fromRGBO(226, 233, 255, 1), + strokeColor: + model.themeData.brightness == Brightness.light + ? Colors.white + : Colors.black), ), - // Returns the custom tooltip for each shape. - shapeTooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - _worldPopulationDensityDetails[index].countryName + - ' : ' + - _numberFormat - .format(_worldPopulationDensityDetails[index] - .density) - .toString() + - ' per sq. km.', - style: Theme.of(context).textTheme.caption.copyWith( - color: Theme.of(context).colorScheme.surface)), - ); - }, - strokeColor: Colors.white30, - legend: MapLegend.bar(MapElement.shape, - position: MapLegendPosition.bottom, - overflowMode: MapLegendOverflowMode.wrap, - labelsPlacement: MapLegendLabelsPlacement.betweenItems, - padding: EdgeInsets.only(top: 15), - spacing: 1.0, - segmentSize: Size(55.0, 9.0)), - tooltipSettings: MapTooltipSettings( - color: model.themeData.brightness == Brightness.light - ? const Color.fromRGBO(0, 32, 128, 1) - : const Color.fromRGBO(226, 233, 255, 1), - strokeColor: model.themeData.brightness == Brightness.light - ? Colors.white - : Colors.black), - ), - ], - ), - ), + ], + ), + ) + ]), ), - ); + )); } } -class _CountryDensityModel { - _CountryDensityModel(this.countryName, this.density); +class _CountryDensity { + _CountryDensity(this.countryName, this.density); final String countryName; final double density; diff --git a/lib/samples/maps/shape_layer/selection/selection.dart b/lib/samples/maps/shape_layer/selection/selection.dart index 3892a4c5..e5285f36 100644 --- a/lib/samples/maps/shape_layer/selection/selection.dart +++ b/lib/samples/maps/shape_layer/selection/selection.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import @@ -17,13 +18,11 @@ class MapSelectionPage extends SampleView { } class _MapSelectionPageState extends SampleViewState { - int _selectedIndex; + int _selectedIndex = -1; - List<_ElectionResultModel> _electionResults; + late List<_StateDetails> _electionResults; - MapShapeSource _selectionMapSource; - - final GlobalKey _scaffoldKey = GlobalKey(); + late MapShapeSource _selectionMapSource; @override void initState() { @@ -38,56 +37,56 @@ class _MapSelectionPageState extends SampleViewState { // // [wonBy]: On the basis of this value, color mapping color has been // applied to the shape. - _electionResults = <_ElectionResultModel>[ - _ElectionResultModel('Washington', 52.5, 36.8, 'Wash.', 'Democratic'), - _ElectionResultModel('Oregon', 50.1, 39.1, 'Ore.', 'Democratic'), - _ElectionResultModel('California', 61.5, 31.5, 'Calif.', 'Democratic'), - _ElectionResultModel('Nevada', 47.9, 45.5, 'Nev.', 'Democratic'), - _ElectionResultModel('Idaho', 59.2, 27.5, 'Idaho', 'Republican'), - _ElectionResultModel('Montana', 55.6, 35.4, 'Mont.', 'Republican'), - _ElectionResultModel('Wyoming', 68.2, 21.9, 'Wyo.', 'Republican'), - _ElectionResultModel('Utah', 45.1, 27.2, 'Utah', 'Republican'), - _ElectionResultModel('Arizona', 48.1, 44.6, 'Ariz.', 'Republican'), - _ElectionResultModel('Colorado', 48.2, 43.3, 'Colo.', 'Democratic'), - _ElectionResultModel('New Mexico', 48.3, 40.0, 'N.M.', 'Democratic'), - _ElectionResultModel('Texas', 52.2, 43.2, 'Tex.', 'Republican'), - _ElectionResultModel('Oklahoma', 65.3, 28.9, 'Okla.', 'Republican'), - _ElectionResultModel('Kansas', 56.2, 36.7, 'Kan.', 'Republican'), - _ElectionResultModel('Nebraska', 58.7, 33.7, 'Neb.', 'Republican'), - _ElectionResultModel('South Dakota', 61.5, 31.7, 'S.D.', 'Republican'), - _ElectionResultModel('North Dakota', 63.0, 27.2, 'N.D.', 'Republican'), - _ElectionResultModel('Minnesota', 46.4, 44.9, 'Minn.', 'Democratic'), - _ElectionResultModel('Lowa', 51.1, 41.7, 'Lowa', 'Republican'), - _ElectionResultModel('Missouri', 56.4, 37.9, 'Mo.', 'Republican'), - _ElectionResultModel('Arkansas', 60.6, 33.7, 'Ark.', 'Republican'), - _ElectionResultModel('Louisiana', 58.1, 38.4, 'La.', 'Republican'), - _ElectionResultModel('Mississippi', 57.9, 40.1, 'Miss.', 'Republican'), - _ElectionResultModel('Tennessee', 60.7, 34.7, 'Tenn.', 'Republican'), - _ElectionResultModel('Alabama', 62.1, 34.4, 'Ala.', 'Republican'), - _ElectionResultModel('Georgia', 50.4, 45.3, 'Ga.', 'Republican'), - _ElectionResultModel('Florida', 48.6, 47.4, 'Fla.', 'Republican'), - _ElectionResultModel('South Carolina', 54.9, 40.7, 'S.C.', 'Republican'), - _ElectionResultModel('North Carolina', 49.8, 46.2, 'N.C.', 'Republican'), - _ElectionResultModel('Virginia', 49.8, 44.4, 'Va.', 'Democratic'), - _ElectionResultModel('West Virginia', 67.9, 26.2, 'W.Va.', 'Republican'), - _ElectionResultModel('Kentucky', 62.5, 32.7, 'Ky.', 'Republican'), - _ElectionResultModel('Illinois', 55.2, 38.4, 'Ill.', 'Democratic'), - _ElectionResultModel('Indiana', 56.5, 37.5, 'Ind.', 'Republican'), - _ElectionResultModel('Ohio', 51.3, 43.2, 'Ohio', 'Republican'), - _ElectionResultModel('Pennsylvania', 48.2, 47.5, 'Pa', 'Republican'), - _ElectionResultModel('Maryland', 60.3, 33.9, 'Md.', 'Democratic'), - _ElectionResultModel('New Jersey', 55.0, 41.0, 'N.J.', 'Democratic'), - _ElectionResultModel('New York', 59.0, 36.5, 'N.Y.', 'Democratic'), - _ElectionResultModel('Wisconsin', 47.2, 46.5, 'Wis.', 'Republican'), - _ElectionResultModel('Michigan', 47.3, 47.0, 'Mich.', 'Republican'), - _ElectionResultModel('Connecticut', 60.0, 32.8, 'Conn.', 'Democratic'), - _ElectionResultModel('Massachusetts', 55.0, 41.0, 'Mass.', 'Democratic'), - _ElectionResultModel('Vermont', 56.7, 30.3, 'Vt.', 'Democratic'), - _ElectionResultModel('New Hampshire', 46.8, 46.5, 'N.H.', 'Democratic'), - _ElectionResultModel('Massachusetts', 55.0, 41.0, 'Mass.', 'Democratic'), - _ElectionResultModel('Maine', 47.8, 44.9, 'Me.', 'Democratic'), - _ElectionResultModel('Alaska', 51.3, 36.6, 'Alaska', 'Republican'), - _ElectionResultModel('Hawaii', 62.2, 30.0, 'Hawaii', 'Democratic'), + _electionResults = <_StateDetails>[ + _StateDetails('Washington', 52.5, 36.8, 'Wash.', 'Democratic'), + _StateDetails('Oregon', 50.1, 39.1, 'Ore.', 'Democratic'), + _StateDetails('California', 61.5, 31.5, 'Calif.', 'Democratic'), + _StateDetails('Nevada', 47.9, 45.5, 'Nev.', 'Democratic'), + _StateDetails('Idaho', 59.2, 27.5, 'Idaho', 'Republican'), + _StateDetails('Montana', 55.6, 35.4, 'Mont.', 'Republican'), + _StateDetails('Wyoming', 68.2, 21.9, 'Wyo.', 'Republican'), + _StateDetails('Utah', 45.1, 27.2, 'Utah', 'Republican'), + _StateDetails('Arizona', 48.1, 44.6, 'Ariz.', 'Republican'), + _StateDetails('Colorado', 48.2, 43.3, 'Colo.', 'Democratic'), + _StateDetails('New Mexico', 48.3, 40.0, 'N.M.', 'Democratic'), + _StateDetails('Texas', 52.2, 43.2, 'Tex.', 'Republican'), + _StateDetails('Oklahoma', 65.3, 28.9, 'Okla.', 'Republican'), + _StateDetails('Kansas', 56.2, 36.7, 'Kan.', 'Republican'), + _StateDetails('Nebraska', 58.7, 33.7, 'Neb.', 'Republican'), + _StateDetails('South Dakota', 61.5, 31.7, 'S.D.', 'Republican'), + _StateDetails('North Dakota', 63.0, 27.2, 'N.D.', 'Republican'), + _StateDetails('Minnesota', 46.4, 44.9, 'Minn.', 'Democratic'), + _StateDetails('Lowa', 51.1, 41.7, 'Lowa', 'Republican'), + _StateDetails('Missouri', 56.4, 37.9, 'Mo.', 'Republican'), + _StateDetails('Arkansas', 60.6, 33.7, 'Ark.', 'Republican'), + _StateDetails('Louisiana', 58.1, 38.4, 'La.', 'Republican'), + _StateDetails('Mississippi', 57.9, 40.1, 'Miss.', 'Republican'), + _StateDetails('Tennessee', 60.7, 34.7, 'Tenn.', 'Republican'), + _StateDetails('Alabama', 62.1, 34.4, 'Ala.', 'Republican'), + _StateDetails('Georgia', 50.4, 45.3, 'Ga.', 'Republican'), + _StateDetails('Florida', 48.6, 47.4, 'Fla.', 'Republican'), + _StateDetails('South Carolina', 54.9, 40.7, 'S.C.', 'Republican'), + _StateDetails('North Carolina', 49.8, 46.2, 'N.C.', 'Republican'), + _StateDetails('Virginia', 49.8, 44.4, 'Va.', 'Democratic'), + _StateDetails('West Virginia', 67.9, 26.2, 'W.Va.', 'Republican'), + _StateDetails('Kentucky', 62.5, 32.7, 'Ky.', 'Republican'), + _StateDetails('Illinois', 55.2, 38.4, 'Ill.', 'Democratic'), + _StateDetails('Indiana', 56.5, 37.5, 'Ind.', 'Republican'), + _StateDetails('Ohio', 51.3, 43.2, 'Ohio', 'Republican'), + _StateDetails('Pennsylvania', 48.2, 47.5, 'Pa', 'Republican'), + _StateDetails('Maryland', 60.3, 33.9, 'Md.', 'Democratic'), + _StateDetails('New Jersey', 55.0, 41.0, 'N.J.', 'Democratic'), + _StateDetails('New York', 59.0, 36.5, 'N.Y.', 'Democratic'), + _StateDetails('Wisconsin', 47.2, 46.5, 'Wis.', 'Republican'), + _StateDetails('Michigan', 47.3, 47.0, 'Mich.', 'Republican'), + _StateDetails('Connecticut', 60.0, 32.8, 'Conn.', 'Democratic'), + _StateDetails('Massachusetts', 55.0, 41.0, 'Mass.', 'Democratic'), + _StateDetails('Vermont', 56.7, 30.3, 'Vt.', 'Democratic'), + _StateDetails('New Hampshire', 46.8, 46.5, 'N.H.', 'Democratic'), + _StateDetails('Massachusetts', 55.0, 41.0, 'Mass.', 'Democratic'), + _StateDetails('Maine', 47.8, 44.9, 'Me.', 'Democratic'), + _StateDetails('Alaska', 51.3, 36.6, 'Alaska', 'Republican'), + _StateDetails('Hawaii', 62.2, 30.0, 'Hawaii', 'Democratic'), ]; _selectionMapSource = MapShapeSource.asset( @@ -127,44 +126,45 @@ class _MapSelectionPageState extends SampleViewState { MapColorMapper(value: 'Republican', color: Colors.red), ], ); - - _selectedIndex = -1; } @override void dispose() { - _electionResults?.clear(); + _electionResults.clear(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( - key: _scaffoldKey, backgroundColor: - model.isWeb ? model.cardThemeColor : model.cardThemeColor, + model.isWebFullView ? model.cardThemeColor : model.cardThemeColor, body: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget() - : SingleChildScrollView(child: _getMapsWidget())); + model.isWebFullView + ? _buildMapsWidget() + : SingleChildScrollView(child: _buildMapsWidget())); } - Widget _getMapsWidget() { + Widget _buildMapsWidget() { return Center( - child: Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.05, - right: 10, - ) - : const EdgeInsets.only(right: 10, bottom: 15), - child: SfMaps( - title: const MapTitle( - '2016 US Election Results', + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.05, + right: 10, + ) + : const EdgeInsets.only(right: 10, bottom: 15), + child: Column(children: [ + Padding( padding: EdgeInsets.only(top: 15, bottom: 30), - ), + child: Align( + alignment: Alignment.center, + child: Text('2016 US Election Results', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( layers: [ MapShapeLayer( loadingBuilder: (BuildContext context) { @@ -193,8 +193,8 @@ class _MapSelectionPageState extends SampleViewState { // Passes the tapped or clicked shape index to the callback. onSelectionChanged: (int index) { if (index != _selectedIndex) { - _scaffoldKey.currentState.hideCurrentSnackBar(); - _scaffoldKey.currentState.showSnackBar(SnackBar( + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( backgroundColor: _electionResults[index].wonBy == 'Republican' ? Colors.red @@ -210,7 +210,7 @@ class _MapSelectionPageState extends SampleViewState { Text(_electionResults[index].primaryKey, style: Theme.of(context) .textTheme - .headline6 + .headline6! .copyWith( color: Colors.white, fontWeight: FontWeight.bold)), @@ -218,12 +218,12 @@ class _MapSelectionPageState extends SampleViewState { child: Align( alignment: Alignment.centerRight, child: GestureDetector( - child: const Icon(Icons.close, - color: Colors.white), onTap: () { - _scaffoldKey.currentState - .hideCurrentSnackBar(); + ScaffoldMessenger.of(context) + .removeCurrentSnackBar(); }, + child: const Icon(Icons.close, + color: Colors.white), )), ) ], @@ -234,7 +234,7 @@ class _MapSelectionPageState extends SampleViewState { Text('Won candidate : ', style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith( fontWeight: FontWeight.bold, color: Colors.white)), @@ -245,7 +245,7 @@ class _MapSelectionPageState extends SampleViewState { : 'Clinton', style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith( fontStyle: FontStyle.italic, color: Colors.white)) @@ -257,7 +257,7 @@ class _MapSelectionPageState extends SampleViewState { Text('Percentage : ', style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith( fontWeight: FontWeight.bold, color: Colors.white)), @@ -268,7 +268,7 @@ class _MapSelectionPageState extends SampleViewState { '%', style: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .copyWith( fontStyle: FontStyle.italic, color: Colors.white)) @@ -292,15 +292,15 @@ class _MapSelectionPageState extends SampleViewState { }, ), ], - ), - ), - ); + )), + ]), + )); } } -class _ElectionResultModel { - _ElectionResultModel(this.primaryKey, this.wonVotePercent, - this.lostVotePercent, this.state, this.wonBy); +class _StateDetails { + _StateDetails(this.primaryKey, this.wonVotePercent, this.lostVotePercent, + this.state, this.wonBy); final String primaryKey; final double wonVotePercent; diff --git a/lib/samples/maps/shape_layer/sublayer/sublayer.dart b/lib/samples/maps/shape_layer/sublayer/sublayer.dart index 240926a5..d69ed676 100644 --- a/lib/samples/maps/shape_layer/sublayer/sublayer.dart +++ b/lib/samples/maps/shape_layer/sublayer/sublayer.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Core theme import @@ -23,11 +24,11 @@ class MapSublayerPage extends SampleView { class _MapSublayerPageState extends SampleViewState with SingleTickerProviderStateMixin { - MapShapeSource _mapSource; - MapZoomPanBehavior _zoomPanBehavior; - bool _isDesktop; - List _state; - ThemeData _themeData; + late MapShapeSource _mapSource; + late MapZoomPanBehavior _zoomPanBehavior; + late bool _isDesktop; + late List _state; + late ThemeData _themeData; @override void initState() { @@ -65,15 +66,15 @@ class _MapSublayerPageState extends SampleViewState } Future>> getJsonData() async { - List> polylines = >[]; - String data = await rootBundle.loadString('assets/river.json'); - dynamic jsonData = json.decode(data); + final List> polylines = >[]; + final String data = await rootBundle.loadString('assets/river.json'); + final dynamic jsonData = json.decode(data); - int length = (jsonData['geometries']).length; + final int length = (jsonData['geometries']).length; for (int i = 0; i < length; i++) { List polylineData; if (jsonData['geometries'][i]['type'] == 'LineString') { - List riverPoints = []; + final List riverPoints = []; polylineData = jsonData['geometries'][i]['coordinates']; for (int j = 0; j < polylineData.length; j++) { riverPoints.add(MapLatLng(polylineData[j][1], polylineData[j][0])); @@ -81,13 +82,13 @@ class _MapSublayerPageState extends SampleViewState polylines.add(riverPoints); } else { polylineData = []; - int length = (jsonData['geometries'][i]['coordinates']).length; + final int length = (jsonData['geometries'][i]['coordinates']).length; for (int j = 0; j < length; j++) { polylineData.add(jsonData['geometries'][i]['coordinates'][j]); } for (int k = 0; k < polylineData.length; k++) { - List riverPoints = []; + final List riverPoints = []; for (int index = 0; index < polylineData[k].length; index++) { riverPoints.add(MapLatLng( polylineData[k][index][1], polylineData[k][index][0])); @@ -103,19 +104,20 @@ class _MapSublayerPageState extends SampleViewState @override Widget build(BuildContext context) { _themeData = Theme.of(context); - _isDesktop = model.isWeb || + _isDesktop = model.isWebFullView || _themeData.platform == TargetPlatform.macOS || - _themeData.platform == TargetPlatform.windows; + _themeData.platform == TargetPlatform.windows || + _themeData.platform == TargetPlatform.linux; return Scaffold( backgroundColor: _isDesktop ? model.cardThemeColor : model.cardThemeColor, body: MediaQuery.of(context).orientation == Orientation.portrait || _isDesktop - ? _getMapsWidget() - : SingleChildScrollView(child: _getMapsWidget())); + ? _buildMapsWidget() + : SingleChildScrollView(child: _buildMapsWidget())); } - Widget _getMapsWidget() { + Widget _buildMapsWidget() { final bool isLightTheme = _themeData.brightness == Brightness.light; return FutureBuilder( future: getJsonData(), @@ -123,26 +125,30 @@ class _MapSublayerPageState extends SampleViewState if (snapchat.hasData) { final List> polylines = snapchat.data; return Center( - child: Padding( - padding: MediaQuery.of(context).orientation == - Orientation.portrait || - _isDesktop - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.05, - right: 10, - ) - : const EdgeInsets.only(right: 10, bottom: 15), - child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Colors.transparent, - shapeHoverStrokeColor: Colors.transparent, - ), - child: SfMaps( - title: const MapTitle( - 'Rivers in Australia', + child: Padding( + padding: + MediaQuery.of(context).orientation == Orientation.portrait || + _isDesktop + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.05, + right: 10, + ) + : const EdgeInsets.only(right: 10, bottom: 15), + child: SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + shapeHoverStrokeColor: Colors.transparent, + ), + child: Column(children: [ + Padding( padding: EdgeInsets.only(top: 15, bottom: 30), - ), + child: Align( + alignment: Alignment.topCenter, + child: Text('Rivers in Australia', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( layers: [ MapShapeLayer( source: _mapSource, @@ -174,7 +180,7 @@ class _MapSublayerPageState extends SampleViewState showDataLabels: true, dataLabelSettings: MapDataLabelSettings( overflowMode: MapLabelOverflow.visible, - textStyle: _themeData.textTheme.caption.copyWith( + textStyle: _themeData.textTheme.caption!.copyWith( color: Color.fromRGBO(0, 0, 0, 1), ), ), @@ -193,12 +199,13 @@ class _MapSublayerPageState extends SampleViewState }, ).toSet(), tooltipBuilder: (BuildContext context, int index) { - final String tooltipText = _getTooltipText(index); + final String? tooltipText = + _getTooltipText(index); if (tooltipText != null) { return Padding( padding: const EdgeInsets.all(8.0), child: Text(tooltipText, - style: model.themeData.textTheme.caption + style: model.themeData.textTheme.caption! .copyWith( color: isLightTheme ? Color.fromRGBO( @@ -207,23 +214,23 @@ class _MapSublayerPageState extends SampleViewState 10, 10, 10, 1))), ); } - return null; + return SizedBox(); }, ), ], ), ], - ), - ), + )), + ]), ), - ); + )); } else { return Container(); } }); } - String _getTooltipText(int index) { + String? _getTooltipText(int index) { if (index == 0) { return 'Gwydir'; } else if (index == 1) { diff --git a/lib/samples/maps/shape_layer/tooltip/tooltip.dart b/lib/samples/maps/shape_layer/tooltip/tooltip.dart index 2621c4c5..c955ef3c 100644 --- a/lib/samples/maps/shape_layer/tooltip/tooltip.dart +++ b/lib/samples/maps/shape_layer/tooltip/tooltip.dart @@ -5,138 +5,138 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_core/theme.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import import '../../../../model/sample_view.dart'; +/// Renders the map tooltip sample. class MapTooltipPage extends SampleView { + /// Creates the map tooltip sample. const MapTooltipPage(Key key) : super(key: key); + @override _MapTooltipPageState createState() => _MapTooltipPageState(); } class _MapTooltipPageState extends SampleViewState { - List _forestData; - List _riverData; - List _rainfallData; + late List<_Area> _forestArea; + late List<_Area> _riverArea; + late List<_Area> _rainfallArea; - MapShapeSource _forestMapSource; - MapShapeSource _riverMapSource; - MapShapeSource _rainfallMapSource; - MapShapeSource _mapSource; + late MapShapeSource _forestMapSource; + late MapShapeSource _riverMapSource; + late MapShapeSource _rainfallMapSource; + late MapShapeSource _mapSource; - Color _bubbleColor; + late Color _bubbleColor; // Index of either forest, river or rainfall data. int _currentDataTypeIndex = 0; - String _mapTitle; + late String _title; @override void initState() { - _forestData = [ - IndiaDataModel('Madhya Pradesh', + _forestArea = <_Area>[ + _Area('Madhya Pradesh', areaInSqKm: 77414, percent: 25.11, imageSource: 'images/maps_forest_1.jpg'), - IndiaDataModel('Arunachal Pradesh', + _Area('Arunachal Pradesh', areaInSqKm: 66964, percent: 79.96, imageSource: 'images/maps_forest_2.jpg'), - IndiaDataModel('Chhattisgarh', + _Area('Chhattisgarh', areaInSqKm: 55547, percent: 41.09, imageSource: 'images/maps_forest_3.jpg'), - IndiaDataModel('Orissa', + _Area('Orissa', areaInSqKm: 51345, percent: 32.98, imageSource: 'images/maps_forest_1.jpg'), - IndiaDataModel('Maharashtra', + _Area('Maharashtra', areaInSqKm: 50682, percent: 16.47, imageSource: 'images/maps_forest_2.jpg'), - IndiaDataModel('Karnataka', + _Area('Karnataka', areaInSqKm: 37550, percent: 19.58, imageSource: 'images/maps_forest_3.jpg'), - IndiaDataModel('Andhra Pradesh', + _Area('Andhra Pradesh', areaInSqKm: 28147, percent: 17.27, imageSource: 'images/maps_forest_1.jpg'), - IndiaDataModel('Assam', + _Area('Assam', areaInSqKm: 28105, percent: 35.83, imageSource: 'images/maps_forest_2.jpg'), - IndiaDataModel('Tamil Nadu', + _Area('Tamil Nadu', areaInSqKm: 26281, percent: 20.21, imageSource: 'images/maps_forest_3.jpg'), - IndiaDataModel('Uttaranchal', + _Area('Uttaranchal', areaInSqKm: 24295, percent: 45.43, imageSource: 'images/maps_forest_1.jpg'), ]; - _riverData = [ - IndiaDataModel('Kerala', - riversCount: 20, imageSource: 'images/maps_river_1.jpg'), - IndiaDataModel('Maharashtra', + _riverArea = <_Area>[ + _Area('Kerala', riversCount: 20, imageSource: 'images/maps_river_1.jpg'), + _Area('Maharashtra', riversCount: 15, imageSource: 'images/maps_river_2.jpg'), - IndiaDataModel('Uttar Pradesh', + _Area('Uttar Pradesh', riversCount: 15, imageSource: 'images/maps_river_3.jpg'), - IndiaDataModel('West Bengal', + _Area('West Bengal', riversCount: 15, imageSource: 'images/maps_river_1.jpg'), - IndiaDataModel('Karnataka', + _Area('Karnataka', riversCount: 14, imageSource: 'images/maps_river_2.jpg'), - IndiaDataModel('Madhya Pradesh', + _Area('Madhya Pradesh', riversCount: 13, imageSource: 'images/maps_river_3.jpg'), - IndiaDataModel('Bihar', - riversCount: 11, imageSource: 'images/maps_river_1.jpg'), - IndiaDataModel('Andhra Pradesh', + _Area('Bihar', riversCount: 11, imageSource: 'images/maps_river_1.jpg'), + _Area('Andhra Pradesh', riversCount: 10, imageSource: 'images/maps_river_2.jpg'), - IndiaDataModel('Tamil Nadu', + _Area('Tamil Nadu', riversCount: 10, imageSource: 'images/maps_river_3.jpg'), - IndiaDataModel('Rajasthan', + _Area('Rajasthan', riversCount: 10, imageSource: 'images/maps_river_1.jpg'), - IndiaDataModel('Assam', - riversCount: 10, imageSource: 'images/maps_river_2.jpg'), - IndiaDataModel('Gujarat', - riversCount: 10, imageSource: 'images/maps_river_3.jpg'), - IndiaDataModel('Uttaranchal', + _Area('Assam', riversCount: 10, imageSource: 'images/maps_river_2.jpg'), + _Area('Gujarat', riversCount: 10, imageSource: 'images/maps_river_3.jpg'), + _Area('Uttaranchal', riversCount: 10, imageSource: 'images/maps_river_1.jpg'), ]; - _rainfallData = [ - IndiaDataModel('Arunachal Pradesh', + _rainfallArea = <_Area>[ + _Area('Arunachal Pradesh', rainfallInMillimeter: 2782, imageSource: 'images/maps_rainfall_1.jpg'), - IndiaDataModel('Meghalaya', + _Area('Meghalaya', rainfallInMillimeter: 2818, imageSource: 'images/maps_rainfall_2.jpg'), - IndiaDataModel('Goa', + _Area('Goa', rainfallInMillimeter: 3005, imageSource: 'images/maps_rainfall_3.jpg'), - IndiaDataModel('Madhya Pradesh', + _Area('Madhya Pradesh', rainfallInMillimeter: 1178, imageSource: 'images/maps_rainfall_1.jpg'), - IndiaDataModel('Maharastra', + _Area('Maharastra', rainfallInMillimeter: 2739, imageSource: 'images/maps_rainfall_2.jpg'), - IndiaDataModel('Uttar Pradesh', + _Area('Uttar Pradesh', rainfallInMillimeter: 3005, imageSource: 'images/maps_rainfall_3.jpg'), - IndiaDataModel('Karnataka', + _Area('Karnataka', rainfallInMillimeter: 1771, imageSource: 'images/maps_rainfall_1.jpg'), - IndiaDataModel('Kerala', + _Area('Kerala', rainfallInMillimeter: 3055, imageSource: 'images/maps_rainfall_2.jpg'), - IndiaDataModel('Andhra Pradesh', + _Area('Andhra Pradesh', rainfallInMillimeter: 912, imageSource: 'images/maps_rainfall_3.jpg'), - IndiaDataModel('Tamil Nadu', + _Area('Tamil Nadu', rainfallInMillimeter: 998, imageSource: 'images/maps_rainfall_1.jpg'), - IndiaDataModel('Orissa', + _Area('Orissa', rainfallInMillimeter: 1489, imageSource: 'images/maps_rainfall_2.jpg'), ]; @@ -144,25 +144,25 @@ class _MapTooltipPageState extends SampleViewState { _forestMapSource = MapShapeSource.asset( 'assets/india.json', shapeDataField: 'name', - dataCount: _forestData.length, - primaryValueMapper: (index) => _forestData[index].state, - bubbleSizeMapper: (index) => _forestData[index].areaInSqKm.toDouble(), + dataCount: _forestArea.length, + primaryValueMapper: (index) => _forestArea[index].state, + bubbleSizeMapper: (index) => _forestArea[index].areaInSqKm!.toDouble(), ); _riverMapSource = MapShapeSource.asset( 'assets/india.json', shapeDataField: 'name', - dataCount: _riverData.length, - primaryValueMapper: (index) => _riverData[index].state, - bubbleSizeMapper: (index) => _riverData[index].riversCount, + dataCount: _riverArea.length, + primaryValueMapper: (index) => _riverArea[index].state, + bubbleSizeMapper: (index) => _riverArea[index].riversCount, ); _rainfallMapSource = MapShapeSource.asset( 'assets/india.json', shapeDataField: 'name', - dataCount: _rainfallData.length, - primaryValueMapper: (index) => _rainfallData[index].state, - bubbleSizeMapper: (index) => _rainfallData[index].rainfallInMillimeter, + dataCount: _rainfallArea.length, + primaryValueMapper: (index) => _rainfallArea[index].state, + bubbleSizeMapper: (index) => _rainfallArea[index].rainfallInMillimeter, ); _setMapDelegate(_currentDataTypeIndex); @@ -172,34 +172,34 @@ class _MapTooltipPageState extends SampleViewState { @override void dispose() { - _forestData?.clear(); - _riverData?.clear(); - _rainfallData?.clear(); + _forestArea.clear(); + _riverArea.clear(); + _rainfallArea.clear(); super.dispose(); } void _setMapDelegate(int index) { switch (index) { case 0: - _mapTitle = 'Indian States with the Most Forest Area'; + _title = 'Indian States with the Most Forest Area'; _bubbleColor = Color.fromRGBO(34, 205, 72, 0.7); _mapSource = _forestMapSource; break; case 1: - _mapTitle = 'Indian States with the Most Rivers'; + _title = 'Indian States with the Most Rivers'; _bubbleColor = Color.fromRGBO(237, 171, 0, 0.7); _mapSource = _riverMapSource; break; case 2: - _mapTitle = 'Indian States with the Most Rainfall'; + _title = 'Indian States with the Most Rainfall'; _bubbleColor = Color.fromRGBO(24, 152, 207, 0.7); _mapSource = _rainfallMapSource; break; } } - Widget _getCustomTooltipWidget( - IndiaDataModel model, ThemeData themeData, bool isLightTheme) { + Widget _buildCustomTooltipWidget( + _Area model, ThemeData themeData, bool isLightTheme) { return Container( width: 300, padding: EdgeInsets.all(10), @@ -216,7 +216,7 @@ class _MapTooltipPageState extends SampleViewState { Text( model.state, textAlign: TextAlign.center, - style: themeData.textTheme.bodyText2.copyWith( + style: themeData.textTheme.bodyText2!.copyWith( color: isLightTheme ? Color.fromRGBO(0, 0, 0, 0.87) : Color.fromRGBO(255, 255, 255, 0.87), @@ -224,7 +224,7 @@ class _MapTooltipPageState extends SampleViewState { ), const SizedBox(height: 10), Text(_getTooltipText(model), - style: themeData.textTheme.caption.copyWith( + style: themeData.textTheme.caption!.copyWith( color: isLightTheme ? Color.fromRGBO(0, 0, 0, 0.87) : Color.fromRGBO(255, 255, 255, 0.87), @@ -245,32 +245,31 @@ class _MapTooltipPageState extends SampleViewState { ])); } - IndiaDataModel _getSelectedIndexModel(int index) { + _Area _getSelectedIndexModel(int index) { if (_currentDataTypeIndex == 0) { - return _forestData[index]; + return _forestArea[index]; } else if (_currentDataTypeIndex == 1) { - return _riverData[index]; + return _riverArea[index]; } else { - return _rainfallData[index]; + return _rainfallArea[index]; } } // ignore: missing_return - String _getTooltipText(IndiaDataModel model) { + String _getTooltipText(_Area model) { switch (_currentDataTypeIndex) { case 0: return '${model.areaInSqKm} sq. km of forest area, which is ${model.percent}% of the state’s geographical area.'; - break; case 1: - return 'More than ${model.riversCount.toInt()} rivers flow in this state.'; - break; + return 'More than ${model.riversCount!.toInt()} rivers flow in this state.'; case 2: - return 'Annual rainfall in this state is ${model.rainfallInMillimeter.toInt()} mm.'; - break; + return 'Annual rainfall in this state is ${model.rainfallInMillimeter!.toInt()} mm.'; } + + return ''; } - Widget _getChipWidget(int index, String text) { + Widget _buildChipWidget(int index, String text) { return Padding( padding: const EdgeInsets.all(5.0), child: ChoiceChip( @@ -296,94 +295,100 @@ class _MapTooltipPageState extends SampleViewState { Widget build(BuildContext context) { final ThemeData themeData = Theme.of(context); return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb - ? _getMapsWidget(themeData) + model.isWebFullView + ? _buildMapsWidget(themeData) : SingleChildScrollView( - child: Container(height: 400, child: _getMapsWidget(themeData)), + child: Container(height: 400, child: _buildMapsWidget(themeData)), ); } - Widget _getMapsWidget(ThemeData themeData) { + Widget _buildMapsWidget(ThemeData themeData) { final bool isLightTheme = themeData.brightness == Brightness.light; return Stack( children: [ Container( padding: MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? EdgeInsets.only( left: 15, top: MediaQuery.of(context).size.height * 0.05, bottom: MediaQuery.of(context).size.height * 0.15) : const EdgeInsets.only(bottom: 75.0), child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Colors.transparent, - shapeHoverStrokeWidth: 0, - shapeHoverStrokeColor: Colors.transparent, - bubbleHoverColor: _bubbleColor.withOpacity(0.4), - bubbleHoverStrokeColor: Colors.black, - bubbleHoverStrokeWidth: 1.0, - ), - child: SfMaps( - title: MapTitle( - _mapTitle, - padding: const EdgeInsets.only(top: 15, bottom: 30), + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + shapeHoverStrokeWidth: 0, + shapeHoverStrokeColor: Colors.transparent, + bubbleHoverColor: _bubbleColor.withOpacity(0.4), + bubbleHoverStrokeColor: Colors.black, + bubbleHoverStrokeWidth: 1.0, ), - layers: [ - MapShapeLayer( - loadingBuilder: (BuildContext context) { - return Container( - height: 25, - width: 25, - child: const CircularProgressIndicator( - strokeWidth: 3, + child: Column(children: [ + Padding( + padding: EdgeInsets.only(top: 15, bottom: 30), + child: Align( + alignment: Alignment.center, + child: Text(_title, + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( + layers: [ + MapShapeLayer( + loadingBuilder: (BuildContext context) { + return Container( + height: 25, + width: 25, + child: const CircularProgressIndicator( + strokeWidth: 3, + ), + ); + }, + source: _mapSource, + + /// This callback returns the custom widget to be shown + /// as the tooltip. The custom widget will be wrapped + /// inside the tooltip. Hence, the nose will still be + /// there. You can customize the stroke around the + /// tooltip if needed. + bubbleTooltipBuilder: (BuildContext context, int index) { + return _buildCustomTooltipWidget( + _getSelectedIndexModel(index), + themeData, + isLightTheme); + }, + color: isLightTheme + ? Color.fromRGBO(204, 204, 204, 1) + : Color.fromRGBO(103, 103, 103, 1), + strokeColor: isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(49, 49, 49, 1), + bubbleSettings: MapBubbleSettings( + minRadius: 15, + maxRadius: 30, + color: _bubbleColor, + strokeColor: Colors.black, + strokeWidth: 0.5, ), - ); - }, - source: _mapSource, - - /// This callback returns the custom widget to be shown - /// as the tooltip. The custom widget will be wrapped - /// inside the tooltip. Hence, the nose will still be - /// there. You can customize the stroke around the - /// tooltip if needed. - bubbleTooltipBuilder: (BuildContext context, int index) { - return _getCustomTooltipWidget( - _getSelectedIndexModel(index), themeData, isLightTheme); - }, - color: isLightTheme - ? Color.fromRGBO(204, 204, 204, 1) - : Color.fromRGBO(103, 103, 103, 1), - strokeColor: isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(49, 49, 49, 1), - bubbleSettings: MapBubbleSettings( - minRadius: 15, - maxRadius: 30, - color: _bubbleColor, - strokeColor: Colors.black, - strokeWidth: 0.5, - ), - tooltipSettings: MapTooltipSettings( - color: isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(66, 66, 66, 1), - strokeColor: Color.fromRGBO(153, 153, 153, 1), - strokeWidth: 0.5, - ), - ), - ], - ), - ), + tooltipSettings: MapTooltipSettings( + color: isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(66, 66, 66, 1), + strokeColor: Color.fromRGBO(153, 153, 153, 1), + strokeWidth: 0.5, + ), + ), + ], + )), + ])), ), Align( alignment: Alignment.bottomCenter, child: Row( mainAxisSize: MainAxisSize.min, children: [ - _getChipWidget(0, 'Forest'), - _getChipWidget(1, 'River'), - _getChipWidget(2, 'Rainfall'), + _buildChipWidget(0, 'Forest'), + _buildChipWidget(1, 'River'), + _buildChipWidget(2, 'Rainfall'), ], ), ) @@ -392,10 +397,10 @@ class _MapTooltipPageState extends SampleViewState { } } -class IndiaDataModel { - const IndiaDataModel( +class _Area { + const _Area( this.state, { - this.imageSource, + required this.imageSource, this.areaInSqKm, this.percent, this.riversCount, @@ -406,11 +411,11 @@ class IndiaDataModel { final String imageSource; - final int areaInSqKm; + final int? areaInSqKm; - final double percent; + final double? percent; - final double riversCount; + final double? riversCount; - final double rainfallInMillimeter; + final double? rainfallInMillimeter; } diff --git a/lib/samples/maps/shape_layer/zooming/zooming.dart b/lib/samples/maps/shape_layer/zooming/zooming.dart index 5dba3e6e..f1aff40e 100644 --- a/lib/samples/maps/shape_layer/zooming/zooming.dart +++ b/lib/samples/maps/shape_layer/zooming/zooming.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; + // ignore: unused_import import 'package:flutter/gestures.dart'; @@ -12,13 +13,17 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_core/theme.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import import '../../../../model/sample_view.dart'; +/// Renders the map zooming sample. class MapZoomingPage extends SampleView { + /// Creates the map zooming sample. const MapZoomingPage(Key key) : super(key: key); + @override _MapZoomingPageState createState() => _MapZoomingPageState(); } @@ -26,74 +31,79 @@ class MapZoomingPage extends SampleView { class _MapZoomingPageState extends SampleViewState { final double _markerSize = 24; - MapShapeSource _mapSource; + late MapShapeSource _mapSource; - List _dataSource; + late List<_CountryColor> _countryColors; - List _markerSource; + late List<_TouristPlaceDetails> _touristPlaces; - MapZoomPanBehavior _zoomPanBehavior; + late MapZoomPanBehavior _zoomPanBehavior; - Timer _tooltipTimer; + Timer? _tooltipTimer; @override void initState() { _zoomPanBehavior = MapZoomPanBehavior(); - _markerSource = [ - TouristPlaceModel( + _touristPlaces = <_TouristPlaceDetails>[ + _TouristPlaceDetails( MapLatLng(-25.6953, -54.4367), 'Iguazu Falls, Argentina'), - TouristPlaceModel(MapLatLng(-50.9423, -73.4068), + _TouristPlaceDetails(MapLatLng(-50.9423, -73.4068), 'Torres del Paine National Park, Patagonia, Chile'), - TouristPlaceModel( + _TouristPlaceDetails( MapLatLng(-15.9254, -69.3354), 'Lake Titicaca, Bolivia'), - TouristPlaceModel(MapLatLng(-13.1631, -72.5450), 'Machu Picchu, Peru'), - TouristPlaceModel( + _TouristPlaceDetails(MapLatLng(-13.1631, -72.5450), 'Machu Picchu, Peru'), + _TouristPlaceDetails( MapLatLng(-0.1862504, -78.5706247), 'The Amazon via Quito, Ecuador'), - TouristPlaceModel(MapLatLng(5.9701, -62.5362), 'Angel Falls, Venezuela'), - TouristPlaceModel(MapLatLng(-14.0875, -75.7626), 'Huacachina, Peru'), - TouristPlaceModel(MapLatLng(-25.2637, -57.5759), 'Asuncion, Paraguay'), - TouristPlaceModel(MapLatLng(-33.0472, -71.6127), 'Valparaiso, Chile'), - TouristPlaceModel( + _TouristPlaceDetails( + MapLatLng(5.9701, -62.5362), 'Angel Falls, Venezuela'), + _TouristPlaceDetails(MapLatLng(-14.0875, -75.7626), 'Huacachina, Peru'), + _TouristPlaceDetails(MapLatLng(-25.2637, -57.5759), 'Asuncion, Paraguay'), + _TouristPlaceDetails(MapLatLng(-33.0472, -71.6127), 'Valparaiso, Chile'), + _TouristPlaceDetails( MapLatLng(0.8056, -77.5858), 'Santuario de las lajas, Colombia'), - TouristPlaceModel(MapLatLng(-19.5723, -65.7550), 'Potosi, Bolivia'), - TouristPlaceModel(MapLatLng(-27.5986, -48.5187), 'Florianopolis, Brazil'), - TouristPlaceModel(MapLatLng(-22.7953, -67.8361), 'Laguna Verde, Bolivia'), - TouristPlaceModel( + _TouristPlaceDetails(MapLatLng(-19.5723, -65.7550), 'Potosi, Bolivia'), + _TouristPlaceDetails( + MapLatLng(-27.5986, -48.5187), 'Florianopolis, Brazil'), + _TouristPlaceDetails( + MapLatLng(-22.7953, -67.8361), 'Laguna Verde, Bolivia'), + _TouristPlaceDetails( MapLatLng(-50.5025092, -73.1997346), 'Perito Moreno, Venezuela'), - TouristPlaceModel( + _TouristPlaceDetails( MapLatLng(-22.9068, -43.1729), 'Rio de Janeiro, Brazil'), - TouristPlaceModel(MapLatLng(5.1765, -59.4808), 'Kaieteur Falls, Guyana'), - TouristPlaceModel(MapLatLng(-13.5320, -71.9675), 'Cusco, Peru'), - TouristPlaceModel( + _TouristPlaceDetails( + MapLatLng(5.1765, -59.4808), 'Kaieteur Falls, Guyana'), + _TouristPlaceDetails(MapLatLng(-13.5320, -71.9675), 'Cusco, Peru'), + _TouristPlaceDetails( MapLatLng(-34.6037, -58.3816), 'Buenos Aires, Argentina'), - TouristPlaceModel(MapLatLng(-23.5505, -46.6333), 'Sao Paulo, Brazil'), - TouristPlaceModel(MapLatLng(-2.7956, -40.5142), 'Jericoacoara, Brazil'), - TouristPlaceModel(MapLatLng(-33.4489, -70.6693), 'Santiago, Chile'), - TouristPlaceModel(MapLatLng(4.7110, -74.0721), 'Bogota, Colombia'), - TouristPlaceModel(MapLatLng(-1.3928, -78.4269), 'Banos, Ecuador'), + _TouristPlaceDetails(MapLatLng(-23.5505, -46.6333), 'Sao Paulo, Brazil'), + _TouristPlaceDetails( + MapLatLng(-2.7956, -40.5142), 'Jericoacoara, Brazil'), + _TouristPlaceDetails(MapLatLng(-33.4489, -70.6693), 'Santiago, Chile'), + _TouristPlaceDetails(MapLatLng(4.7110, -74.0721), 'Bogota, Colombia'), + _TouristPlaceDetails(MapLatLng(-1.3928, -78.4269), 'Banos, Ecuador'), ]; - _dataSource = [ - CountryModel('Argentina', Color.fromRGBO(227, 176, 130, 1)), - CountryModel('Bolivia', Color.fromRGBO(242, 214, 70, 1)), - CountryModel('Brazil', Color.fromRGBO(223, 147, 46, 1)), - CountryModel('Chile', Color.fromRGBO(141, 143, 166, 1)), - CountryModel('Colombia', Color.fromRGBO(179, 208, 251, 1)), - CountryModel('Ecuador', Color.fromRGBO(242, 223, 224, 1)), - CountryModel('Falkland Is.', Color.fromRGBO(198, 191, 147, 1)), - CountryModel('Guyana', Color.fromRGBO(211, 120, 120, 1)), - CountryModel('Peru', Color.fromRGBO(185, 244, 127, 1)), - CountryModel('Paraguay', Color.fromRGBO(179, 208, 251, 1)), - CountryModel('Venezuela', Color.fromRGBO(141, 208, 203, 1)), + _countryColors = <_CountryColor>[ + _CountryColor('Argentina', Color.fromRGBO(227, 176, 130, 1)), + _CountryColor('Bolivia', Color.fromRGBO(242, 214, 70, 1)), + _CountryColor('Brazil', Color.fromRGBO(223, 147, 46, 1)), + _CountryColor('Chile', Color.fromRGBO(141, 143, 166, 1)), + _CountryColor('Colombia', Color.fromRGBO(179, 208, 251, 1)), + _CountryColor('Ecuador', Color.fromRGBO(242, 223, 224, 1)), + _CountryColor('Falkland Is.', Color.fromRGBO(198, 191, 147, 1)), + _CountryColor('Guyana', Color.fromRGBO(211, 120, 120, 1)), + _CountryColor('Peru', Color.fromRGBO(185, 244, 127, 1)), + _CountryColor('Paraguay', Color.fromRGBO(179, 208, 251, 1)), + _CountryColor('Venezuela', Color.fromRGBO(141, 208, 203, 1)), ]; _mapSource = MapShapeSource.asset( 'assets/south_america.json', shapeDataField: 'name', - dataCount: _dataSource.length, - primaryValueMapper: (int index) => _dataSource[index].country, - shapeColorValueMapper: (int index) => _dataSource[index].color, + dataCount: _countryColors.length, + primaryValueMapper: (int index) => _countryColors[index].country, + shapeColorValueMapper: (int index) => _countryColors[index].color, ); super.initState(); @@ -101,8 +111,8 @@ class _MapZoomingPageState extends SampleViewState { @override void dispose() { - _markerSource?.clear(); - _dataSource?.clear(); + _touristPlaces.clear(); + _countryColors.clear(); _tooltipTimer?.cancel(); _tooltipTimer = null; super.dispose(); @@ -116,94 +126,98 @@ class _MapZoomingPageState extends SampleViewState { ? Color.fromRGBO(45, 45, 45, 1) : Color.fromRGBO(242, 242, 242, 1); return Container( - padding: - MediaQuery.of(context).orientation == Orientation.portrait || kIsWeb - ? EdgeInsets.only( - top: MediaQuery.of(context).size.height * 0.05, - bottom: MediaQuery.of(context).size.height * 0.05) - : const EdgeInsets.only(top: 10, bottom: 15), - child: SfMapsTheme( - data: SfMapsThemeData( - shapeHoverColor: Colors.transparent, - shapeHoverStrokeColor: Colors.grey[700], - shapeHoverStrokeWidth: 1.5, - ), - child: SfMaps( - title: MapTitle( - 'Tourist Places in South America', - padding: EdgeInsets.only(top: 15, bottom: 30), + padding: + MediaQuery.of(context).orientation == Orientation.portrait || kIsWeb + ? EdgeInsets.only( + top: MediaQuery.of(context).size.height * 0.05, + bottom: MediaQuery.of(context).size.height * 0.05) + : const EdgeInsets.only(top: 10, bottom: 15), + child: SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + shapeHoverStrokeColor: Colors.grey[700], + shapeHoverStrokeWidth: 1.5, ), - layers: [ - MapShapeLayer( - loadingBuilder: (BuildContext context) { - return Container( - height: 25, - width: 25, - child: const CircularProgressIndicator( - strokeWidth: 3, + child: Column(children: [ + Padding( + padding: EdgeInsets.only(top: 15, bottom: 30), + child: Align( + alignment: Alignment.center, + child: Text('Tourist Places in South America', + style: Theme.of(context).textTheme.subtitle1))), + Expanded( + child: SfMaps( + layers: [ + MapShapeLayer( + loadingBuilder: (BuildContext context) { + return Container( + height: 25, + width: 25, + child: const CircularProgressIndicator( + strokeWidth: 3, + ), + ); + }, + color: Colors.white, + strokeColor: Color.fromRGBO(242, 242, 242, 1), + strokeWidth: 1, + source: _mapSource, + showDataLabels: true, + dataLabelSettings: MapDataLabelSettings( + overflowMode: MapLabelOverflow.ellipsis, + textStyle: TextStyle( + color: Color.fromRGBO(45, 45, 45, 1), + ), ), - ); - }, - color: Colors.white, - strokeColor: Color.fromRGBO(242, 242, 242, 1), - strokeWidth: 1, - source: _mapSource, - showDataLabels: true, - dataLabelSettings: MapDataLabelSettings( - overflowMode: MapLabelOverflow.ellipsis, - textStyle: TextStyle( - color: Color.fromRGBO(45, 45, 45, 1), - ), - ), - tooltipSettings: MapTooltipSettings( - color: surfaceColor, - ), - initialMarkersCount: _markerSource.length, - markerTooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text(_markerSource[index].place, - style: themeData.textTheme.caption.copyWith( - color: isLightTheme - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(10, 10, 10, 1))), - ); - }, - markerBuilder: (BuildContext context, int index) { - return MapMarker( - latitude: _markerSource[index].latLng.latitude, - longitude: _markerSource[index].latLng.longitude, - size: Size(_markerSize, _markerSize * 2), - child: Icon( - Icons.location_on, - color: isLightTheme - ? Color.fromRGBO(45, 45, 45, 1) - : Color.fromRGBO(199, 42, 89, 1), + tooltipSettings: MapTooltipSettings( + color: surfaceColor, ), - ); - }, - - /// Adding `zoomPanBehavior` will enable the zooming and - /// panning in the shape layer. - zoomPanBehavior: _zoomPanBehavior, - ), - ], - ), - ), - ); + initialMarkersCount: _touristPlaces.length, + markerTooltipBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text(_touristPlaces[index].place, + style: themeData.textTheme.caption!.copyWith( + color: isLightTheme + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(10, 10, 10, 1))), + ); + }, + markerBuilder: (BuildContext context, int index) { + return MapMarker( + latitude: _touristPlaces[index].latLng.latitude, + longitude: _touristPlaces[index].latLng.longitude, + size: Size(_markerSize, _markerSize * 2), + child: Icon( + Icons.location_on, + color: isLightTheme + ? Color.fromRGBO(45, 45, 45, 1) + : Color.fromRGBO(199, 42, 89, 1), + ), + ); + }, + + /// Adding `zoomPanBehavior` will enable the zooming and + /// panning in the shape layer. + zoomPanBehavior: _zoomPanBehavior, + ), + ], + )), + ]), + )); } } -class TouristPlaceModel { - const TouristPlaceModel(this.latLng, this.place); +class _TouristPlaceDetails { + const _TouristPlaceDetails(this.latLng, this.place); final MapLatLng latLng; final String place; } -class CountryModel { - const CountryModel(this.country, this.color); +class _CountryColor { + const _CountryColor(this.country, this.color); final String country; diff --git a/lib/samples/maps/tile_layer/bing_map/bing_map.dart b/lib/samples/maps/tile_layer/bing_map/bing_map.dart index 6506a1d8..a7086184 100644 --- a/lib/samples/maps/tile_layer/bing_map/bing_map.dart +++ b/lib/samples/maps/tile_layer/bing_map/bing_map.dart @@ -1,31 +1,34 @@ ///Flutter package imports -import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; -///URL launcher import -import 'package:url_launcher/url_launcher.dart' show launch; - ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; +///URL launcher import +import 'package:url_launcher/url_launcher.dart' show launch; + ///Local import import '../../../../model/sample_view.dart'; +/// Renders the map widget with bing map. class MapBingPage extends SampleView { /// Creates the map widget with bing map. const MapBingPage(Key key) : super(key: key); + @override _BingMapState createState() => _BingMapState(); } class _BingMapState extends SampleViewState { - TextEditingController _textFieldController; + late TextEditingController _textFieldController; - MapZoomPanBehavior _zoomPanBehavior; + late MapZoomPanBehavior _zoomPanBehavior; - String _bingURL; - String _bingKey; + late String _bingURL; + late String _bingKey; int _selectedMapViewIndex = 0; @@ -40,14 +43,15 @@ class _BingMapState extends SampleViewState { _zoomPanBehavior = MapZoomPanBehavior( minZoomLevel: 3, maxZoomLevel: 10, - zoomLevel: model.isWeb ? 5 : 4, + zoomLevel: model.isWebFullView ? 5 : 4, focalLatLng: MapLatLng(27.1751, 78.0421), + enableDoubleTapZooming: true, ); } @override void dispose() { - _textFieldController?.dispose(); + _textFieldController.dispose(); super.dispose(); } @@ -64,30 +68,31 @@ class _BingMapState extends SampleViewState { return _hasBingMapKey ? FutureBuilder( future: getBingUrlTemplate(_bingURL), - builder: (BuildContext context, AsyncSnapshot snapshot) { + builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { - final String urlTemplate = snapshot.data; - return _getBingMap(urlTemplate); + final String urlTemplate = snapshot.data!; + return _buildBingMap(urlTemplate); } else { _hasBingMapKey = false; _showEmptyKeyError = false; _showKeyError = true; - return _getKeyValidationScreen(); + return _buildKeyValidationScreen(); } } else { return const Center(child: CircularProgressIndicator()); } }, ) - : _getKeyValidationScreen(); + : _buildKeyValidationScreen(); } /// Home screen with the `TextField` to get the subscription key. - Widget _getKeyValidationScreen() { + Widget _buildKeyValidationScreen() { return Center( child: Container( - width: MediaQuery.of(context).size.width * (model.isWeb ? 0.4 : 0.8), + width: MediaQuery.of(context).size.width * + (model.isWebFullView ? 0.4 : 0.8), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -187,7 +192,7 @@ class _BingMapState extends SampleViewState { ); } - Widget _getBingMap(String urlTemplate) { + Widget _buildBingMap(String urlTemplate) { return Stack( children: [ Positioned.fill( @@ -210,9 +215,9 @@ class _BingMapState extends SampleViewState { alignment: WrapAlignment.center, spacing: 10.0, children: [ - _getChip(0, 'Road View'), - _getChip(1, 'Aerial View'), - _getChip(2, 'Aerial View With Labels'), + _buildChip(0, 'Road View'), + _buildChip(1, 'Aerial View'), + _buildChip(2, 'Aerial View With Labels'), ], ), ), @@ -220,7 +225,7 @@ class _BingMapState extends SampleViewState { ); } - Widget _getChip(int index, String mapType) { + Widget _buildChip(int index, String mapType) { return ChoiceChip( label: Text(mapType), selected: _selectedMapViewIndex == index, @@ -232,6 +237,8 @@ class _BingMapState extends SampleViewState { if (_selectedMapViewIndex != index) { setState(() { _selectedMapViewIndex = index; + _zoomPanBehavior.zoomLevel = + _zoomPanBehavior.zoomLevel.floorToDouble(); _setBingMapView(_selectedMapViewIndex); }); } @@ -283,7 +290,7 @@ class _BingMapState extends SampleViewState { } } - String _getErrorMessage() { + String? _getErrorMessage() { if (_showEmptyKeyError) { return 'Key should not be empty.'; } else if (_showKeyError) { diff --git a/lib/samples/maps/tile_layer/osm/osm.dart b/lib/samples/maps/tile_layer/open_street_map/open_street_map.dart similarity index 76% rename from lib/samples/maps/tile_layer/osm/osm.dart rename to lib/samples/maps/tile_layer/open_street_map/open_street_map.dart index b375f807..d4db7f29 100644 --- a/lib/samples/maps/tile_layer/osm/osm.dart +++ b/lib/samples/maps/tile_layer/open_street_map/open_street_map.dart @@ -2,43 +2,49 @@ import 'package:flutter/material.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import import '../../../../model/sample_view.dart'; +/// Renders the map widget with OSM map. class MapOSMPage extends SampleView { /// Creates the map widget with OSM map. const MapOSMPage(Key key) : super(key: key); + + @override _TileLayerSampleState createState() => _TileLayerSampleState(); } class _TileLayerSampleState extends SampleViewState { - PageController _pageViewController; - MapTileLayerController _mapController; + late PageController _pageViewController; + late MapTileLayerController _mapController; - MapZoomPanBehavior _zoomPanBehavior; + late MapZoomPanBehavior _zoomPanBehavior; - List _data; + late List<_WonderDetails> _worldWonders; - int _currentSelectedIndex; - int _previousSelectedIndex; - int _tappedMarkerIndex; + late int _currentSelectedIndex; + late int _previousSelectedIndex; + late int _tappedMarkerIndex; - double _cardHeight; + late double _cardHeight; - bool _canUpdateFocalLatLng; - bool _isDesktop; + late bool _canUpdateFocalLatLng; + late bool _canUpdateZoomLevel; + late bool _isDesktop; @override void initState() { super.initState(); _currentSelectedIndex = 5; _canUpdateFocalLatLng = true; + _canUpdateZoomLevel = true; _mapController = MapTileLayerController(); - _data = []; + _worldWonders = <_WonderDetails>[]; - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Chichen Itza', state: 'Yucatan', country: 'Mexico', @@ -49,7 +55,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_chichen_itza.jpg', tooltipImagePath: 'images/maps-chichen-itza.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Machu Picchu', state: 'Cuzco', country: 'Peru', @@ -60,7 +66,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_machu_pichu.jpg', tooltipImagePath: 'images/maps-machu-picchu.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Christ the Redeemer', state: 'Rio de Janeiro', country: 'Brazil', @@ -71,7 +77,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_christ_redeemer.jpg', tooltipImagePath: 'images/maps-christ-the-redeemer.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Colosseum', state: 'Regio III Isis et Serapis', country: 'Rome', @@ -82,7 +88,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_colosseum.jpg', tooltipImagePath: 'images/maps-colosseum.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Petra', state: 'Ma\'an Governorate', country: 'Jordan', @@ -93,7 +99,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_petra.jpg', tooltipImagePath: 'images/maps-petra.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Taj Mahal', state: 'Uttar Pradesh', country: 'India', @@ -104,7 +110,7 @@ class _TileLayerSampleState extends SampleViewState { imagePath: 'images/maps_taj_mahal.jpg', tooltipImagePath: 'images/maps-tajmahal.jpg')); - _data.add(WorldWonderModel( + _worldWonders.add(_WonderDetails( place: 'Great Wall of China', state: 'Beijing', country: 'China', @@ -118,26 +124,31 @@ class _TileLayerSampleState extends SampleViewState { _zoomPanBehavior = MapZoomPanBehavior( minZoomLevel: 3, maxZoomLevel: 10, - focalLatLng: MapLatLng(_data[_currentSelectedIndex].latitude, - _data[_currentSelectedIndex].longitude), + focalLatLng: MapLatLng(_worldWonders[_currentSelectedIndex].latitude, + _worldWonders[_currentSelectedIndex].longitude), + enableDoubleTapZooming: true, ); } @override void dispose() { - _pageViewController?.dispose(); - _mapController?.dispose(); - _data?.clear(); + _pageViewController.dispose(); + _mapController.dispose(); + _worldWonders.clear(); super.dispose(); } @override Widget build(BuildContext context) { final ThemeData themeData = Theme.of(context); - _isDesktop = model.isWeb || + _isDesktop = model.isWebFullView || themeData.platform == TargetPlatform.macOS || - themeData.platform == TargetPlatform.windows; - _zoomPanBehavior.zoomLevel = _isDesktop ? 5 : 4; + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; + if (_canUpdateZoomLevel) { + _zoomPanBehavior.zoomLevel = _isDesktop ? 5 : 4; + _canUpdateZoomLevel = false; + } _cardHeight = (MediaQuery.of(context).orientation == Orientation.landscape) ? (_isDesktop ? 120 : 90) : 110; @@ -168,64 +179,61 @@ class _TileLayerSampleState extends SampleViewState { urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', zoomPanBehavior: _zoomPanBehavior, controller: _mapController, - initialMarkersCount: _data.length, + initialMarkersCount: _worldWonders.length, tooltipSettings: MapTooltipSettings( color: Colors.transparent, ), markerTooltipBuilder: (BuildContext context, int index) { if (_isDesktop) { - return Container( - width: 150, - height: 130, - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(8)), - child: Column(children: [ - Container( - width: 150, - height: 80, - child: Image.asset( - _data[index].tooltipImagePath, - fit: BoxFit.fill, - ), + return ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(8)), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Container( + width: 150, + height: 80, + color: Colors.grey, + child: Image.asset( + _worldWonders[index].tooltipImagePath, + fit: BoxFit.fill, ), - Container( - padding: const EdgeInsets.only( - left: 10.0, top: 5.0, bottom: 5.0), - width: 150, - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _data[index].place, + ), + Container( + padding: const EdgeInsets.only( + left: 10.0, top: 5.0, bottom: 5.0), + width: 150, + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _worldWonders[index].place, + style: TextStyle( + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.bold), + ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: Text( + _worldWonders[index].state + + ', ' + + _worldWonders[index].country, style: TextStyle( - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.bold), + fontSize: 10, color: Colors.black), ), - Padding( - padding: const EdgeInsets.only(top: 5.0), - child: Text( - _data[index].state + - ', ' + - _data[index].country, - style: TextStyle( - fontSize: 10, color: Colors.black), - ), - ) - ]), - ), - ]), - ), + ) + ]), + ), + ]), ); } - return null; + return SizedBox(); }, markerBuilder: (BuildContext context, int index) { return MapMarker( - latitude: _data[index].latitude, - longitude: _data[index].longitude, + latitude: _worldWonders[index].latitude, + longitude: _worldWonders[index].longitude, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -265,11 +273,11 @@ class _TileLayerSampleState extends SampleViewState { /// PageView which shows the world wonder details at the bottom. child: PageView.builder( - itemCount: _data.length, + itemCount: _worldWonders.length, onPageChanged: _handlePageChange, controller: _pageViewController, itemBuilder: (BuildContext context, int index) { - final WorldWonderModel item = _data[index]; + final _WonderDetails item = _worldWonders[index]; return Transform.scale( scale: index == _currentSelectedIndex ? 1 : 0.85, child: Stack( @@ -379,8 +387,8 @@ class _TileLayerSampleState extends SampleViewState { /// center and the marker itself should not move to the center of the maps. if (_canUpdateFocalLatLng) { _zoomPanBehavior.focalLatLng = MapLatLng( - _data[_currentSelectedIndex].latitude, - _data[_currentSelectedIndex].longitude); + _worldWonders[_currentSelectedIndex].latitude, + _worldWonders[_currentSelectedIndex].longitude); } /// Updating the design of the selected marker. Please check the @@ -391,16 +399,16 @@ class _TileLayerSampleState extends SampleViewState { } } -class WorldWonderModel { - const WorldWonderModel( - {this.place, - this.state, - this.country, - this.imagePath, - this.latitude, - this.longitude, - this.description, - this.tooltipImagePath}); +class _WonderDetails { + const _WonderDetails( + {required this.place, + required this.state, + required this.country, + required this.imagePath, + required this.latitude, + required this.longitude, + required this.description, + required this.tooltipImagePath}); final String place; final String state; diff --git a/lib/samples/maps/tile_layer/vector_layer/arcs.dart b/lib/samples/maps/tile_layer/vector_layer/arcs.dart index 4c25f9e2..b6145617 100644 --- a/lib/samples/maps/tile_layer/vector_layer/arcs.dart +++ b/lib/samples/maps/tile_layer/vector_layer/arcs.dart @@ -4,32 +4,40 @@ import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/rendering.dart'; ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + ///Local import import '../../../../model/sample_view.dart'; +/// Renders the map arc sample class MapArcsPage extends SampleView { + /// Creates the map arc sample const MapArcsPage(Key key) : super(key: key); + + @override _ArcsSampleState createState() => _ArcsSampleState(); } class _ArcsSampleState extends SampleViewState with SingleTickerProviderStateMixin { - List _airportData; - List _markerData; - MapZoomPanBehavior _zoomPanBehavior; - MapTileLayerController _mapController; - AnimationController _animationController; - Animation _animation; - int _selectedLineIndex; + late List<_AirRouteDetails> _airports; + late List<_MarkerData> _markerData; + late MapZoomPanBehavior _zoomPanBehavior; + late MapTileLayerController _mapController; + late AnimationController _animationController; + late Animation _animation; int _currentSelectedCityIndex = 0; bool _isDesktop = false; bool _enableDashArray = false; - bool _canUpdateZoomLevel; - List> _dropDownMenuItems; - String _currentSublayer; - Color _layerColor; + late bool _canUpdateZoomLevel; + late List> _dropDownMenuItems; + late String _currentSublayer; + late Color _layerColor; + late List _dashArray; @override void initState() { @@ -38,14 +46,19 @@ class _ArcsSampleState extends SampleViewState _zoomPanBehavior = MapZoomPanBehavior( focalLatLng: MapLatLng(40.7128, -74.0060), toolbarSettings: MapToolbarSettings( - direction: Axis.vertical, position: MapToolbarPosition.bottomRight), + direction: Axis.vertical, + position: MapToolbarPosition.bottomRight, + ), + enableDoubleTapZooming: true, + maxZoomLevel: 12, ); _setNavigationLineData(_currentSelectedCityIndex); _dropDownMenuItems = _getDropDownMenuItems(); - _currentSublayer = _dropDownMenuItems[0].value; + _currentSublayer = _dropDownMenuItems[0].value!; _canUpdateZoomLevel = true; + _dashArray = [0, 0]; _animationController = AnimationController( duration: Duration(seconds: 2), @@ -63,10 +76,10 @@ class _ArcsSampleState extends SampleViewState @override void dispose() { - _animationController?.dispose(); - _mapController?.dispose(); - _markerData?.clear(); - _airportData?.clear(); + _animationController.dispose(); + _mapController.dispose(); + _markerData.clear(); + _airports.clear(); super.dispose(); } @@ -74,37 +87,37 @@ class _ArcsSampleState extends SampleViewState switch (index) { case 0: _layerColor = Color.fromRGBO(167, 61, 233, 1.0); - _markerData = [ - MarkerData('New York', MapLatLng(40.7128, -74.0060)), - MarkerData('Denver', MapLatLng(39.7392, -104.9903)), - MarkerData('Bogata', MapLatLng(4.7110, -74.0721)), - MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), - MarkerData('Tashkent', MapLatLng(41.2995, 69.2401)), - MarkerData('Dakar', MapLatLng(14.7167, -17.4677)), - MarkerData('Casablanca', MapLatLng(33.3700, -7.5857)), - MarkerData('Houston', MapLatLng(29.7604, -95.3698)), - MarkerData('Edmonton', MapLatLng(53.5461, -113.4938)), - MarkerData('Panama City', MapLatLng(8.9824, -79.5199)), + _markerData = <_MarkerData>[ + _MarkerData('New York', MapLatLng(40.7128, -74.0060)), + _MarkerData('Denver', MapLatLng(39.7392, -104.9903)), + _MarkerData('Bogata', MapLatLng(4.7110, -74.0721)), + _MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), + _MarkerData('Tashkent', MapLatLng(41.2995, 69.2401)), + _MarkerData('Dakar', MapLatLng(14.7167, -17.4677)), + _MarkerData('Casablanca', MapLatLng(33.3700, -7.5857)), + _MarkerData('Houston', MapLatLng(29.7604, -95.3698)), + _MarkerData('Edmonton', MapLatLng(53.5461, -113.4938)), + _MarkerData('Panama City', MapLatLng(8.9824, -79.5199)), ]; - _airportData = [ - AirRouteModel(MapLatLng(40.7128, -74.0060), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(4.7110, -74.0721), 'New York - Bogata'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(51.0447, -114.0719), 'New York - Calgary'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(41.2995, 69.2401), 'New York - Tashkent'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(14.7167, -17.4677), 'New York - Dakar'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(33.3700, -7.5857), 'New York - Casablanca'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(29.7604, -95.3698), 'New York - Houston'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(53.5461, -113.4938), 'New York - Edmonton'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(8.9824, -79.5199), 'New York - Panama City'), - AirRouteModel(MapLatLng(40.7128, -74.0060), + _AirRouteDetails(MapLatLng(40.7128, -74.0060), MapLatLng(39.7392, -104.9903), 'New york - Denver'), ]; _updateMarkers(); @@ -112,25 +125,25 @@ class _ArcsSampleState extends SampleViewState case 1: _layerColor = Color.fromRGBO(65, 72, 22, 1.0); - _markerData = [ - MarkerData('Denver', MapLatLng(39.7392, -104.9903)), - MarkerData('New York', MapLatLng(40.7128, -74.0060)), - MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), - MarkerData('Edmonton', MapLatLng(53.5461, -113.4938)), - MarkerData('Paris', MapLatLng(48.8566, 2.3522)), - MarkerData('Panama City', MapLatLng(8.9824, -79.5199)), + _markerData = <_MarkerData>[ + _MarkerData('Denver', MapLatLng(39.7392, -104.9903)), + _MarkerData('New York', MapLatLng(40.7128, -74.0060)), + _MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), + _MarkerData('Edmonton', MapLatLng(53.5461, -113.4938)), + _MarkerData('Paris', MapLatLng(48.8566, 2.3522)), + _MarkerData('Panama City', MapLatLng(8.9824, -79.5199)), ]; - _airportData = [ - AirRouteModel(MapLatLng(39.7392, -104.9903), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(39.7392, -104.9903), MapLatLng(53.5461, -113.4938), 'Denver - Edmonton'), - AirRouteModel(MapLatLng(39.7392, -104.9903), + _AirRouteDetails(MapLatLng(39.7392, -104.9903), MapLatLng(51.0447, -114.0719), 'Denver - Calgary'), - AirRouteModel(MapLatLng(39.7392, -104.9903), + _AirRouteDetails(MapLatLng(39.7392, -104.9903), MapLatLng(40.7128, -74.0060), 'Denver - New York'), - AirRouteModel(MapLatLng(39.7392, -104.9903), + _AirRouteDetails(MapLatLng(39.7392, -104.9903), MapLatLng(48.8566, 2.3522), 'Denver - Paris'), - AirRouteModel(MapLatLng(39.7392, -104.9903), + _AirRouteDetails(MapLatLng(39.7392, -104.9903), MapLatLng(8.9824, -79.5199), 'Denver - Panama City'), ]; _updateMarkers(); @@ -138,25 +151,25 @@ class _ArcsSampleState extends SampleViewState case 2: _layerColor = Color.fromRGBO(12, 152, 34, 1.0); - _markerData = [ - MarkerData('London', MapLatLng(51.4700, 0.4543)), - MarkerData('Bogata', MapLatLng(4.7110, -74.0721)), - MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), - MarkerData('Moscow', MapLatLng(55.7558, 37.6173)), - MarkerData('Riyath', MapLatLng(24.7136, 46.6753)), - MarkerData('Seoul', MapLatLng(37.5665, 126.9780)), + _markerData = <_MarkerData>[ + _MarkerData('London', MapLatLng(51.4700, 0.4543)), + _MarkerData('Bogata', MapLatLng(4.7110, -74.0721)), + _MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), + _MarkerData('Moscow', MapLatLng(55.7558, 37.6173)), + _MarkerData('Riyath', MapLatLng(24.7136, 46.6753)), + _MarkerData('Seoul', MapLatLng(37.5665, 126.9780)), ]; - _airportData = [ - AirRouteModel(MapLatLng(51.4700, 0.4543), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(51.4700, 0.4543), MapLatLng(51.0447, -114.0719), 'London - Calgary'), - AirRouteModel(MapLatLng(51.4700, 0.4543), MapLatLng(4.7110, -74.0721), - 'London - Bogata'), - AirRouteModel(MapLatLng(51.4700, 0.4543), MapLatLng(55.7558, 37.6173), - 'London - Moscow'), - AirRouteModel(MapLatLng(51.4700, 0.4543), MapLatLng(24.7136, 46.6753), - 'London - Riyath'), - AirRouteModel(MapLatLng(51.4700, 0.4543), + _AirRouteDetails(MapLatLng(51.4700, 0.4543), + MapLatLng(4.7110, -74.0721), 'London - Bogata'), + _AirRouteDetails(MapLatLng(51.4700, 0.4543), + MapLatLng(55.7558, 37.6173), 'London - Moscow'), + _AirRouteDetails(MapLatLng(51.4700, 0.4543), + MapLatLng(24.7136, 46.6753), 'London - Riyath'), + _AirRouteDetails(MapLatLng(51.4700, 0.4543), MapLatLng(37.5665, 126.9780), 'London - Seoul'), ]; _updateMarkers(); @@ -164,25 +177,25 @@ class _ArcsSampleState extends SampleViewState case 3: _layerColor = Color.fromRGBO(226, 75, 65, 1.0); - _markerData = [ - MarkerData('Dublin', MapLatLng(53.3498, -6.2603)), - MarkerData('New York', MapLatLng(40.7128, -74.0060)), - MarkerData('Hong Kong', MapLatLng(22.3193, 114.1694)), - MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), - MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), - MarkerData('Helsinki', MapLatLng(60.1699, 24.9384)), + _markerData = <_MarkerData>[ + _MarkerData('Dublin', MapLatLng(53.3498, -6.2603)), + _MarkerData('New York', MapLatLng(40.7128, -74.0060)), + _MarkerData('Hong Kong', MapLatLng(22.3193, 114.1694)), + _MarkerData('Calgary', MapLatLng(51.0447, -114.0719)), + _MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), + _MarkerData('Helsinki', MapLatLng(60.1699, 24.9384)), ]; - _airportData = [ - AirRouteModel(MapLatLng(53.3498, -6.2603), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(53.3498, -6.2603), MapLatLng(22.3193, 114.1694), 'Dublin - Hong Kong'), - AirRouteModel(MapLatLng(53.3498, -6.2603), MapLatLng(8.9806, 38.7578), - 'Dublin - Addis Abada'), - AirRouteModel(MapLatLng(53.3498, -6.2603), + _AirRouteDetails(MapLatLng(53.3498, -6.2603), + MapLatLng(8.9806, 38.7578), 'Dublin - Addis Abada'), + _AirRouteDetails(MapLatLng(53.3498, -6.2603), MapLatLng(60.1699, 24.9384), 'Dublin - Helsinki'), - AirRouteModel(MapLatLng(53.3498, -6.2603), + _AirRouteDetails(MapLatLng(53.3498, -6.2603), MapLatLng(40.7128, -74.0060), 'Dublin - New York'), - AirRouteModel(MapLatLng(53.3498, -6.2603), + _AirRouteDetails(MapLatLng(53.3498, -6.2603), MapLatLng(51.0447, -114.0719), 'Dublin - Calgary'), ]; _updateMarkers(); @@ -190,84 +203,84 @@ class _ArcsSampleState extends SampleViewState case 4: _layerColor = Color.fromRGBO(108, 27, 212, 1.0); - _markerData = [ - MarkerData('Beijing', MapLatLng(39.9042, 116.4074)), - MarkerData('Seoul', MapLatLng(37.5665, 126.9780)), - MarkerData('Islamabad', MapLatLng(33.6844, 73.0479)), - MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), - MarkerData('Tokyo', MapLatLng(35.6762, 139.6503)), - MarkerData('Helsinki', MapLatLng(60.1699, 24.9384)), - MarkerData('Korla', MapLatLng(41.7259, 86.1746)), + _markerData = <_MarkerData>[ + _MarkerData('Beijing', MapLatLng(39.9042, 116.4074)), + _MarkerData('Seoul', MapLatLng(37.5665, 126.9780)), + _MarkerData('Islamabad', MapLatLng(33.6844, 73.0479)), + _MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), + _MarkerData('Tokyo', MapLatLng(35.6762, 139.6503)), + _MarkerData('Helsinki', MapLatLng(60.1699, 24.9384)), + _MarkerData('Korla', MapLatLng(41.7259, 86.1746)), ]; - _airportData = [ - AirRouteModel(MapLatLng(39.9042, 116.4074), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(33.6844, 73.0479), 'Beijing - Islamabad'), - AirRouteModel(MapLatLng(39.9042, 116.4074), + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(8.9806, 38.7578), 'Beijing - Addis Abada'), - AirRouteModel(MapLatLng(39.9042, 116.4074), + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(35.6762, 139.6503), 'Beijing - Tokyo'), - AirRouteModel(MapLatLng(39.9042, 116.4074), + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(60.1699, 24.9384), 'Beijing - Helsinki'), - AirRouteModel(MapLatLng(39.9042, 116.4074), + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(41.7259, 86.1746), 'Beijing - Korla'), - AirRouteModel(MapLatLng(39.9042, 116.4074), + _AirRouteDetails(MapLatLng(39.9042, 116.4074), MapLatLng(37.5665, 126.9780), 'Beijing - Seoul'), ]; _updateMarkers(); break; case 5: _layerColor = Color.fromRGBO(236, 40, 134, 1.0); - _markerData = [ - MarkerData('Delhi', MapLatLng(28.7041, 77.1025)), - MarkerData('London', MapLatLng(51.4700, 0.4543)), - MarkerData('Beijing', MapLatLng(39.9042, 116.4074)), - MarkerData('Chennai', MapLatLng(13.0827, 80.2707)), - MarkerData('New York', MapLatLng(40.7128, -74.0060)), - MarkerData('Sydney', MapLatLng(-33.8688, 151.2093)), - MarkerData('Mumbai', MapLatLng(19.0931, 72.8568)), + _markerData = <_MarkerData>[ + _MarkerData('Delhi', MapLatLng(28.7041, 77.1025)), + _MarkerData('London', MapLatLng(51.4700, 0.4543)), + _MarkerData('Beijing', MapLatLng(39.9042, 116.4074)), + _MarkerData('Chennai', MapLatLng(13.0827, 80.2707)), + _MarkerData('New York', MapLatLng(40.7128, -74.0060)), + _MarkerData('Sydney', MapLatLng(-33.8688, 151.2093)), + _MarkerData('Mumbai', MapLatLng(19.0931, 72.8568)), ]; - _airportData = [ - AirRouteModel(MapLatLng(28.7041, 77.1025), MapLatLng(51.4700, 0.4543), - 'Delhi - London'), - AirRouteModel(MapLatLng(28.7041, 77.1025), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(28.7041, 77.1025), + MapLatLng(51.4700, 0.4543), 'Delhi - London'), + _AirRouteDetails(MapLatLng(28.7041, 77.1025), MapLatLng(40.7128, -74.0060), 'Delhi - New York'), - AirRouteModel(MapLatLng(28.7041, 77.1025), + _AirRouteDetails(MapLatLng(28.7041, 77.1025), MapLatLng(-33.8688, 151.2093), 'Delhi - Sydney'), - AirRouteModel(MapLatLng(28.7041, 77.1025), + _AirRouteDetails(MapLatLng(28.7041, 77.1025), MapLatLng(39.9042, 116.4074), 'Delhi - Beijing'), - AirRouteModel(MapLatLng(28.7041, 77.1025), + _AirRouteDetails(MapLatLng(28.7041, 77.1025), MapLatLng(13.0827, 80.2707), 'Delhi - Chennai'), - AirRouteModel(MapLatLng(28.7041, 77.1025), + _AirRouteDetails(MapLatLng(28.7041, 77.1025), MapLatLng(19.0931, 72.8568), 'Delhi - Mumbai'), ]; _updateMarkers(); break; case 6: _layerColor = Color.fromRGBO(2, 130, 122, 1.0); - _markerData = [ - MarkerData('Chennai', MapLatLng(13.0827, 80.2707)), - MarkerData('London', MapLatLng(51.4700, 0.4543)), - MarkerData('Delhi', MapLatLng(28.7041, 77.1025)), - MarkerData('Riyath', MapLatLng(24.7136, 46.6753)), - MarkerData('Tokyo', MapLatLng(35.6762, 139.6503)), - MarkerData('Singapore', MapLatLng(1.3521, 103.8198)), - MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), + _markerData = <_MarkerData>[ + _MarkerData('Chennai', MapLatLng(13.0827, 80.2707)), + _MarkerData('London', MapLatLng(51.4700, 0.4543)), + _MarkerData('Delhi', MapLatLng(28.7041, 77.1025)), + _MarkerData('Riyath', MapLatLng(24.7136, 46.6753)), + _MarkerData('Tokyo', MapLatLng(35.6762, 139.6503)), + _MarkerData('Singapore', MapLatLng(1.3521, 103.8198)), + _MarkerData('Addis Abada', MapLatLng(8.9806, 38.7578)), ]; - _airportData = [ - AirRouteModel(MapLatLng(13.0827, 80.2707), + _airports = <_AirRouteDetails>[ + _AirRouteDetails(MapLatLng(13.0827, 80.2707), MapLatLng(51.507351, -0.127758), 'Chennai - London'), - AirRouteModel(MapLatLng(13.0827, 80.2707), + _AirRouteDetails(MapLatLng(13.0827, 80.2707), MapLatLng(35.6762, 139.6503), 'Chennai - Tokyo'), - AirRouteModel(MapLatLng(13.0827, 80.2707), MapLatLng(8.9806, 38.7578), - 'Chennai - Addis Abada'), - AirRouteModel(MapLatLng(13.0827, 80.2707), + _AirRouteDetails(MapLatLng(13.0827, 80.2707), + MapLatLng(8.9806, 38.7578), 'Chennai - Addis Abada'), + _AirRouteDetails(MapLatLng(13.0827, 80.2707), MapLatLng(24.7136, 46.6753), 'Chennai - Riyath'), - AirRouteModel(MapLatLng(13.0827, 80.2707), + _AirRouteDetails(MapLatLng(13.0827, 80.2707), MapLatLng(1.3521, 103.8198), 'Chennai - Singapore'), - AirRouteModel(MapLatLng(13.0827, 80.2707), + _AirRouteDetails(MapLatLng(13.0827, 80.2707), MapLatLng(28.7041, 77.1025), 'Chennai - Delhi'), ]; _updateMarkers(); @@ -283,9 +296,10 @@ class _ArcsSampleState extends SampleViewState } List> _getDropDownMenuItems() { - List> sublayerItems = List() - ..add(DropdownMenuItem(value: 'Arcs', child: Text('Arcs'))) - ..add(DropdownMenuItem(value: 'Lines', child: Text('Lines'))); + final List> sublayerItems = [ + DropdownMenuItem(value: 'Arcs', child: Text('Arcs')), + DropdownMenuItem(value: 'Lines', child: Text('Lines')) + ]; return sublayerItems; } @@ -293,25 +307,18 @@ class _ArcsSampleState extends SampleViewState if (_currentLegend == 'Arcs') { return MapArcLayer( arcs: List.generate( - _airportData.length, + _airports.length, (int index) { - bool isSelected = _selectedLineIndex == index; return MapArc( - from: _airportData[index].from, - to: _airportData[index].to, - dashArray: _enableDashArray ? [8, 3] : [0, 0], + from: _airports[index].from, + to: _airports[index].to, + dashArray: _dashArray, heightFactor: index == 5 && - _airportData[index].to == MapLatLng(13.0827, 80.2707) + _airports[index].to == MapLatLng(13.0827, 80.2707) ? 0.5 : 0.2, - color: isSelected ? Colors.blue : _layerColor, + color: _layerColor, width: 2.0, - onTap: () { - setState(() { - _selectedLineIndex = index; - _canUpdateZoomLevel = false; - }); - }, ); }, ).toSet(), @@ -321,21 +328,14 @@ class _ArcsSampleState extends SampleViewState } else { return MapLineLayer( lines: List.generate( - _airportData.length, + _airports.length, (int index) { - bool isSelected = _selectedLineIndex == index; return MapLine( - from: _airportData[index].from, - to: _airportData[index].to, - dashArray: _enableDashArray ? [8, 3] : [0, 0], - color: isSelected ? Colors.blue : _layerColor, + from: _airports[index].from, + to: _airports[index].to, + dashArray: _dashArray, + color: _layerColor, width: 2.0, - onTap: () { - setState(() { - _selectedLineIndex = index; - _canUpdateZoomLevel = false; - }); - }, ); }, ).toSet(), @@ -353,15 +353,15 @@ class _ArcsSampleState extends SampleViewState child: Column( children: [ Text('Route', - style: Theme.of(context).textTheme.caption.copyWith( + style: Theme.of(context).textTheme.caption!.copyWith( fontWeight: FontWeight.bold, color: Color.fromRGBO(255, 255, 255, 1))), Padding( padding: EdgeInsets.only(top: 5.0), - child: Text(_airportData[index].destination, + child: Text(_airports[index].destination, style: Theme.of(context) .textTheme - .caption + .caption! .copyWith(color: Color.fromRGBO(255, 255, 255, 1))), ), ], @@ -375,7 +375,8 @@ class _ArcsSampleState extends SampleViewState final ThemeData themeData = Theme.of(context); _isDesktop = kIsWeb || themeData.platform == TargetPlatform.macOS || - themeData.platform == TargetPlatform.windows; + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; if (_canUpdateZoomLevel) { _zoomPanBehavior.zoomLevel = _isDesktop ? 4 : 3; _zoomPanBehavior.minZoomLevel = _isDesktop ? 4 : 3; @@ -388,36 +389,41 @@ class _ArcsSampleState extends SampleViewState repeat: ImageRepeat.repeat, ), ), - SfMaps( - layers: [ - MapTileLayer( - urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - initialMarkersCount: _markerData.length, - zoomPanBehavior: _zoomPanBehavior, - controller: _mapController, - markerBuilder: (BuildContext context, int index) { - return MapMarker( - latitude: _markerData[index].latLan.latitude, - longitude: _markerData[index].latLan.longitude, - child: index == 0 - ? BlowingCircle(color: _layerColor) - : Icon(Icons.circle, color: _layerColor, size: 15), - ); - }, - markerTooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text(_markerData[index].country, - style: model.themeData.textTheme.caption - .copyWith(color: Color.fromRGBO(255, 255, 255, 1))), - ); - }, - tooltipSettings: MapTooltipSettings( - color: Color.fromRGBO(45, 45, 45, 1), + SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + ), + child: SfMaps( + layers: [ + MapTileLayer( + urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + initialMarkersCount: _markerData.length, + zoomPanBehavior: _zoomPanBehavior, + controller: _mapController, + markerBuilder: (BuildContext context, int index) { + return MapMarker( + latitude: _markerData[index].latLng.latitude, + longitude: _markerData[index].latLng.longitude, + child: index == 0 + ? BlowingCircle(color: _layerColor) + : Icon(Icons.circle, color: _layerColor, size: 15), + ); + }, + markerTooltipBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text(_markerData[index].country, + style: model.themeData.textTheme.caption! + .copyWith(color: Color.fromRGBO(255, 255, 255, 1))), + ); + }, + tooltipSettings: MapTooltipSettings( + color: Color.fromRGBO(45, 45, 45, 1), + ), + sublayers: [_getCurrentSublayer(_currentSublayer)], ), - sublayers: [_getCurrentSublayer(_currentSublayer)], - ), - ], + ], + ), ), Align( alignment: Alignment.topCenter, @@ -426,13 +432,13 @@ class _ArcsSampleState extends SampleViewState child: Row( mainAxisSize: MainAxisSize.min, children: [ - _getChipWidget(0, 'New York'), - _getChipWidget(1, 'Denver'), - _getChipWidget(2, 'London'), - _getChipWidget(3, 'Dublin'), - _getChipWidget(4, 'Beijing'), - _getChipWidget(5, 'Delhi'), - _getChipWidget(6, 'Chennai'), + _buildChipWidget(0, 'New York'), + _buildChipWidget(1, 'Denver'), + _buildChipWidget(2, 'London'), + _buildChipWidget(3, 'Dublin'), + _buildChipWidget(4, 'Beijing'), + _buildChipWidget(5, 'Delhi'), + _buildChipWidget(6, 'Chennai'), ], ), ), @@ -440,13 +446,13 @@ class _ArcsSampleState extends SampleViewState ]); } - Widget _getChipWidget(int index, String city) { + Widget _buildChipWidget(int index, String city) { return Padding( padding: _isDesktop ? const EdgeInsets.only(left: 8.0, top: 8.0) : const EdgeInsets.only(left: 8.0), child: ChoiceChip( - backgroundColor: model?.themeData?.brightness == Brightness.light + backgroundColor: model.themeData.brightness == Brightness.light ? Colors.white : Colors.black, elevation: 3.0, @@ -462,8 +468,7 @@ class _ArcsSampleState extends SampleViewState setState(() { _currentSelectedCityIndex = index; _setNavigationLineData(_currentSelectedCityIndex); - _zoomPanBehavior.focalLatLng = _markerData[0].latLan; - _selectedLineIndex = null; + _zoomPanBehavior.focalLatLng = _markerData[0].latLng; _canUpdateZoomLevel = false; _animationController.forward(from: 0); }); @@ -478,84 +483,88 @@ class _ArcsSampleState extends SampleViewState return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return SingleChildScrollView( - child: Container( - height: 110, - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Layer type", - style: TextStyle( - color: model.textColor, - fontSize: 16, - ), - ), - Padding( - padding: EdgeInsets.only(right: 15.0), - child: DropdownButton( - value: _currentSublayer, - items: _dropDownMenuItems, - onChanged: (String value) { - setState(() { - _currentSublayer = value; - _canUpdateZoomLevel = false; - }); - stateSetter(() {}); - }, - )) - ], + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Layer type', + style: TextStyle( + color: model.textColor, + fontSize: 16, ), - Row( - children: [ - Expanded( - child: Text( - 'Show dashes', - style: TextStyle( - color: model.textColor, - fontSize: 16, - ), - ), - ), - Container( - width: 90, - child: CheckboxListTile( - activeColor: model.backgroundColor, - value: _enableDashArray, - onChanged: (bool value) { - setState(() { - _enableDashArray = value; - _canUpdateZoomLevel = false; - }); - stateSetter(() {}); - })), - ], + ), + Padding( + padding: EdgeInsets.only(right: 15.0), + child: DropdownButton( + value: _currentSublayer, + items: _dropDownMenuItems, + onChanged: (String? value) { + setState(() { + _currentSublayer = value!; + _canUpdateZoomLevel = false; + }); + stateSetter(() {}); + }, + )) + ], + ), + Row( + children: [ + Expanded( + child: Text( + 'Show dashes', + style: TextStyle( + color: model.textColor, + fontSize: 16, + ), ), - ], - ))); + ), + Container( + width: 90, + child: CheckboxListTile( + activeColor: model.backgroundColor, + value: _enableDashArray, + onChanged: (bool? value) { + setState(() { + _enableDashArray = value!; + _dashArray = + _enableDashArray ? [8, 2, 2, 2] : [0, 0]; + _canUpdateZoomLevel = false; + }); + stateSetter(() {}); + })), + ], + ), + ], + ), + ); }); } } -class MarkerData { - MarkerData(this.country, this.latLan); +class _MarkerData { + _MarkerData(this.country, this.latLng); String country; - MapLatLng latLan; + MapLatLng latLng; } -class AirRouteModel { - AirRouteModel(this.from, this.to, this.destination); +class _AirRouteDetails { + _AirRouteDetails(this.from, this.to, this.destination); MapLatLng from; MapLatLng to; String destination; } -class BlowingCircleCustomPaint extends CustomPainter { - BlowingCircleCustomPaint( - {this.iconColor, this.iconSize, this.animationValue}); +class _BlowingCircleCustomPaint extends CustomPainter { + _BlowingCircleCustomPaint( + {required this.iconColor, + required this.iconSize, + required this.animationValue}); final Color iconColor; @@ -576,24 +585,28 @@ class BlowingCircleCustomPaint extends CustomPainter { } @override - bool shouldRepaint(BlowingCircleCustomPaint oldDelegate) => true; + bool shouldRepaint(_BlowingCircleCustomPaint oldDelegate) => true; } +/// Renders the blowing circle sample class BlowingCircle extends StatefulWidget { + /// Creates the blowing circle sample const BlowingCircle({ - Key key, - this.color, + Key? key, + required this.color, }) : super(key: key); + /// Color value final Color color; + @override _BlowingCircleState createState() => _BlowingCircleState(); } class _BlowingCircleState extends State with SingleTickerProviderStateMixin { - AnimationController _controller; - Animation _animation; + late AnimationController _controller; + late Animation _animation; @override void initState() { @@ -625,7 +638,7 @@ class _BlowingCircleState extends State @override Widget build(BuildContext context) { return CustomPaint( - painter: BlowingCircleCustomPaint( + painter: _BlowingCircleCustomPaint( iconColor: widget.color, iconSize: Size(15.0, 15.0), animationValue: _animation.value), diff --git a/lib/samples/maps/tile_layer/vector_layer/polygon.dart b/lib/samples/maps/tile_layer/vector_layer/polygon.dart new file mode 100644 index 00000000..d21901ac --- /dev/null +++ b/lib/samples/maps/tile_layer/vector_layer/polygon.dart @@ -0,0 +1,530 @@ +import 'dart:convert'; + +/// Flutter package imports +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; + +/// Map import +// ignore: import_of_legacy_library_into_null_safe +import 'package:syncfusion_flutter_maps/maps.dart'; + +/// Local import +import '../../../../model/sample_view.dart'; + +/// Renders the polygon map sample +class MapPolygonPage extends SampleView { + /// Creates the polygon map sample + const MapPolygonPage(Key key) : super(key: key); + + @override + _MapPolygonPageState createState() => _MapPolygonPageState(); +} + +class _MapPolygonPageState extends SampleViewState { + late MapZoomPanBehavior _zoomPanBehavior; + late List _polygonData; + late String _boundaryJson; + bool _isDesktop = false; + int _selectedIndex = 1; + bool _isInvertedPolygon = true; + late bool _isLightTheme; + + Widget get _expandableAnimatedButton => Padding( + padding: EdgeInsets.all(_isDesktop ? 8.0 : 10.0), + child: ExpandableAnimatedButton( + dataCount: _polygonData.length, + alignment: Alignment.bottomRight, + builder: (int index, BuildContext context) { + return _ExpandedButton( + text: _polygonData[index].name, + color: _polygonData[index].color, + textStyle: TextStyle(color: Colors.white), + size: 35, + isSelected: index == _selectedIndex, + opacity: 1.0, + onSelectionChanged: (bool isSelected) { + setState(() { + _selectedIndex = index; + if (index == 0) { + _boundaryJson = 'assets/maps_france_boundary.json'; + // France coordinate. + _zoomPanBehavior + ..zoomLevel = 4 + ..focalLatLng = MapLatLng(46.2276, 2.2137); + } else if (index == 1) { + _boundaryJson = 'assets/maps_brazil_boundary.json'; + // Brazil coordinate. + _zoomPanBehavior + ..zoomLevel = 3 + ..focalLatLng = MapLatLng(-14.2350, -51.9253); + } else if (index == 2) { + _boundaryJson = 'assets/maps_uk_boundary.json'; + // UK coordinate. + _zoomPanBehavior + ..zoomLevel = 4 + ..focalLatLng = MapLatLng(55.3781, -3.4360); + } + }); + }, + child: + Image.asset(_polygonData[index].imagePath, fit: BoxFit.cover), + ); + }, + ), + ); + + Widget _toggleButtons(ThemeData themeData) { + _isLightTheme = themeData.brightness == Brightness.light; + return Padding( + padding: const EdgeInsets.only(left: 10, top: 10), + child: DecoratedBox( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.24), + spreadRadius: 0, + blurRadius: 6, + offset: Offset(0, 2), + ) + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Tooltip( + message: 'Inverted polygon', + child: SizedBox( + height: 32, + width: 32, + child: TextButton( + style: _getButtonStyle(!_isInvertedPolygon), + onPressed: () { + setState(() { + _isInvertedPolygon = true; + }); + }, + child: _isLightTheme + ? _buildButtonIcons( + 'images/maps_inverted_polygon_light.png') + : _buildButtonIcons( + 'images/maps_inverted_polygon_dark.png'), + ), + ), + ), + Tooltip( + message: 'Default polygon', + child: SizedBox( + height: 32, + width: 32, + child: TextButton( + style: _getButtonStyle(_isInvertedPolygon), + onPressed: () { + setState(() { + _isInvertedPolygon = false; + }); + }, + child: _isLightTheme + ? _buildButtonIcons( + 'images/maps_default_polygon_light.png') + : _buildButtonIcons( + 'images/maps_default_polygon_dark.png'), + ), + ), + ), + ], + ), + ), + ); + } + + ButtonStyle _getButtonStyle(bool isSelected) { + return ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.hovered)) { + return _isLightTheme + ? const Color.fromRGBO(217, 217, 217, 1.0) + : const Color.fromRGBO(102, 102, 102, 1.0); + } + return isSelected + ? (_isLightTheme + ? const Color.fromRGBO(250, 250, 250, 1.0) + : const Color.fromRGBO(66, 66, 66, 1.0)) + : (_isLightTheme + ? const Color.fromRGBO(230, 230, 230, 1.0) + : const Color.fromRGBO( + 88, 88, 88, 1.0)); // Use the component's default. + }, + ), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(0.0)), + side: BorderSide(color: Colors.transparent), + ), + ), + padding: MaterialStateProperty.all( + EdgeInsets.all(0.0), + ), + ); + } + + Widget _buildButtonIcons(String imagePath) { + return Center( + child: Image.asset( + imagePath, + height: 20, + width: 20, + )); + } + + Future> _getPolygonPoints() async { + List polygonGeometryData; + int multipolygonGeometryLength; + final List> polygons = >[]; + final String data = await rootBundle.loadString(_boundaryJson); + final dynamic jsonData = json.decode(data); + final String key = 'features'; + final int jsonLength = jsonData[key].length; + for (int i = 0; i < jsonLength; i++) { + final dynamic features = jsonData[key][i]; + final Map geometry = features['geometry']; + + if (geometry['type'] == 'Polygon') { + polygonGeometryData = geometry['coordinates'][0]; + polygons.add(_getLatLngPoints(polygonGeometryData)); + } else { + multipolygonGeometryLength = geometry['coordinates'].length; + for (int j = 0; j < multipolygonGeometryLength; j++) { + polygonGeometryData = geometry['coordinates'][j][0]; + polygons.add(_getLatLngPoints(polygonGeometryData)); + } + } + } + return _getPolygons(polygons); + } + + List _getLatLngPoints(List polygonPoints) { + final List polygon = []; + for (int i = 0; i < polygonPoints.length; i++) { + polygon.add(MapLatLng(polygonPoints[i][1], polygonPoints[i][0])); + } + return polygon; + } + + Set _getPolygons(List> polygonPoints) { + return List.generate( + polygonPoints.length, + (int index) { + return MapPolygon(points: polygonPoints[index]); + }, + ).toSet(); + } + + MapSublayer _getPolygonLayer(Set polygons) { + if (_isInvertedPolygon) { + return MapPolygonLayer.inverted( + polygons: polygons, + color: Colors.black.withOpacity(0.3), + strokeColor: Colors.red, + ); + } else { + return MapPolygonLayer( + polygons: polygons, + color: Colors.grey.withOpacity(0.5), + strokeColor: Colors.red, + ); + } + } + + @override + void initState() { + _polygonData = [ + PolygonDataModel('France', 'images/maps_france.png', + color: Color.fromRGBO(237, 41, 57, 1.0)), + PolygonDataModel('Brazil', 'images/maps_brazil.png', + color: Color.fromRGBO(7, 154, 73, 1.0)), + PolygonDataModel('United Kingdom', 'images/maps_UK.png', + color: Color.fromRGBO(1, 33, 105, 1.0)), + ]; + _zoomPanBehavior = MapZoomPanBehavior( + zoomLevel: 3, + // Brazil coordinate. + focalLatLng: MapLatLng(-14.2350, -51.9253), + minZoomLevel: 3, + maxZoomLevel: 10, + enableDoubleTapZooming: true, + ); + _boundaryJson = 'assets/maps_brazil_boundary.json'; + super.initState(); + } + + @override + void dispose() { + _polygonData.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; + return FutureBuilder( + future: _getPolygonPoints(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Stack( + children: [ + Positioned.fill( + child: Image.asset( + 'images/maps_grid.png', + repeat: ImageRepeat.repeat, + ), + ), + MapTileLayer( + urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + sublayers: [_getPolygonLayer(snapshot.data)], + zoomPanBehavior: _zoomPanBehavior, + ), + _expandableAnimatedButton, + _toggleButtons(themeData), + ], + ); + } else { + // Showing empty container when the snapshot data is empty. + return Container(); + } + }, + ); + } +} + +/// Builder for expanded button +typedef ExpandableButtonWidgetBuilder = _ExpandedButton Function( + int index, BuildContext context); + +/// Renders the expandable animated button +class ExpandableAnimatedButton extends StatefulWidget { + /// Creates the expandable animated button + ExpandableAnimatedButton({ + Key? key, + required this.dataCount, + required this.builder, + this.spacing = 10.0, + this.alignment = Alignment.bottomRight, + }) : super(key: key); + + /// Data count value + final int dataCount; + + /// expandable button widget builder + final ExpandableButtonWidgetBuilder builder; + + /// sapcing value + final double spacing; + + /// Alignment value + final AlignmentGeometry alignment; + + @override + _ExpandableAnimatedButtonState createState() => + _ExpandableAnimatedButtonState(); +} + +class _ExpandableAnimatedButtonState extends State { + WrapCrossAlignment _getCrossAxisAlignment(BuildContext context) { + final Alignment alignment = + widget.alignment.resolve(Directionality.of(context)); + return alignment.x == -1 + ? WrapCrossAlignment.start + : WrapCrossAlignment.end; + } + + @override + Widget build(BuildContext context) { + final WrapCrossAlignment alignment = _getCrossAxisAlignment(context); + return _InheritedExpandableAnimatedButton( + alignment: alignment, + child: Align( + alignment: widget.alignment, + child: Wrap( + spacing: widget.spacing, + direction: Axis.vertical, + crossAxisAlignment: alignment, + children: List.generate( + widget.dataCount, + (int index) => widget.builder(index, context), + ), + ), + ), + ); + } +} + +class _InheritedExpandableAnimatedButton extends InheritedWidget { + const _InheritedExpandableAnimatedButton( + {required Widget child, required this.alignment}) + : super(child: child); + + final WrapCrossAlignment alignment; + + @override + bool updateShouldNotify(_InheritedExpandableAnimatedButton oldWidget) { + return oldWidget.alignment != alignment; + } +} + +class _ExpandedButton extends StatefulWidget { + const _ExpandedButton({ + required this.text, + required this.child, + required this.color, + this.padding = const EdgeInsets.symmetric(horizontal: 10.0), + this.size = 45.0, + this.opacity = 0.5, + required this.textStyle, + required this.isSelected, + required this.onSelectionChanged, + }); + + final String text; + final Widget child; + final Color color; + final EdgeInsetsGeometry padding; + final double size; + final double opacity; + final TextStyle textStyle; + final bool isSelected; + final ValueChanged onSelectionChanged; + + @override + _ExpandedButtonState createState() => _ExpandedButtonState(); +} + +class _ExpandedButtonState extends State<_ExpandedButton> + with SingleTickerProviderStateMixin { + static Duration duration = Duration(milliseconds: 550); + late AnimationController _controller; + late Animation _animation; + late _InheritedExpandableAnimatedButton _ancestor; + + Widget get _text => SizeTransition( + sizeFactor: _animation, + axis: Axis.horizontal, + axisAlignment: -1.0, + child: Center( + child: Padding( + padding: widget.padding, + child: Text(widget.text, style: widget.textStyle), + ), + ), + ); + + Widget get _image => ClipRRect( + borderRadius: BorderRadius.circular(widget.size / 2), + child: SizedBox( + width: widget.size, + height: widget.size, + child: widget.child, + ), + ); + + void _forward() { + if (!widget.isSelected) { + _controller.forward(); + } + } + + void _reverse() { + if (!widget.isSelected) { + _controller.reverse(); + } + } + + @override + void initState() { + _controller = AnimationController(vsync: this, duration: duration); + _animation = CurvedAnimation(parent: _controller, curve: Curves.easeOut); + if (widget.isSelected) { + _controller.value = 1; + } + super.initState(); + } + + @override + void didChangeDependencies() { + _ancestor = context.dependOnInheritedWidgetOfExactType< + _InheritedExpandableAnimatedButton>()!; + super.didChangeDependencies(); + } + + @override + void didUpdateWidget(_ExpandedButton oldWidget) { + if (!oldWidget.isSelected && widget.isSelected) { + _controller.forward(); + } else if (oldWidget.isSelected && !widget.isSelected) { + _controller.reverse(); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedOpacity( + duration: duration, + opacity: widget.opacity, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (PointerEnterEvent event) => _forward(), + onExit: (PointerExitEvent event) => _reverse(), + child: GestureDetector( + onTapUp: (TapUpDetails details) { + widget.onSelectionChanged(!widget.isSelected); + }, + onLongPressStart: (LongPressStartDetails details) => _forward(), + onLongPressEnd: (LongPressEndDetails details) => _reverse(), + child: ClipRRect( + borderRadius: BorderRadius.circular(widget.size / 2), + child: Container( + color: widget.color, + height: widget.size, + child: Row( + mainAxisSize: MainAxisSize.min, + children: _ancestor.alignment == WrapCrossAlignment.end + ? [_text, _image] + : [_image, _text], + ), + ), + ), + ), + ), + ); + } +} + +/// Classs for polygon data model +class PolygonDataModel { + /// Holds the polygon data model data values + PolygonDataModel(this.name, this.imagePath, {required this.color}); + + /// Holds the string value + final String name; + + /// Path of image + final String imagePath; + + /// color value + final Color color; +} diff --git a/lib/samples/maps/tile_layer/vector_layer/polylines.dart b/lib/samples/maps/tile_layer/vector_layer/polylines.dart index dffcaafa..752d5ce6 100644 --- a/lib/samples/maps/tile_layer/vector_layer/polylines.dart +++ b/lib/samples/maps/tile_layer/vector_layer/polylines.dart @@ -1,50 +1,61 @@ /// Flutter package imports import 'dart:convert'; -import 'package:flutter/material.dart'; + import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + ///Map import +// ignore: import_of_legacy_library_into_null_safe import 'package:syncfusion_flutter_maps/maps.dart'; ///Local import import '../../../../model/sample_view.dart'; +/// Renders the polygon lines map sample class MapPolylinesPage extends SampleView { + /// Creates the polygon lines map sample const MapPolylinesPage(Key key) : super(key: key); + + @override _PolylinesSampleState createState() => _PolylinesSampleState(); } class _PolylinesSampleState extends SampleViewState with SingleTickerProviderStateMixin { - MapZoomPanBehavior _zoomPanBehavior; - MapTileLayerController _mapController; - AnimationController _animationController; - Animation _animation; - bool _isDesktop; - List _markerData; + late MapZoomPanBehavior _zoomPanBehavior; + MapTileLayerController? _mapController; + AnimationController? _animationController; + late Animation _animation; + late bool _isDesktop; + late List<_RouteDetails> _routes; int _currentSelectedCityIndex = 0; - String _routeJson; + late String _routeJson; @override void initState() { _routeJson = 'assets/london_to_british.json'; - _markerData = [ - MarkerData(MapLatLng(51.4700, -0.4543), null, 'London Heathrow'), - MarkerData( + _routes = <_RouteDetails>[ + _RouteDetails(MapLatLng(51.4700, -0.4543), null, 'London Heathrow'), + _RouteDetails( MapLatLng(51.5194, -0.1270), Icon(Icons.location_on, color: Colors.red[600], size: 30), 'The British Museum'), ]; _mapController = MapTileLayerController(); _zoomPanBehavior = MapZoomPanBehavior( - minZoomLevel: 3, - zoomLevel: 10, - focalLatLng: MapLatLng(51.4700, -0.2843), - toolbarSettings: MapToolbarSettings( - direction: Axis.vertical, position: MapToolbarPosition.bottomRight), - maxZoomLevel: 15); + minZoomLevel: 3, + zoomLevel: 10, + focalLatLng: MapLatLng(51.4700, -0.2843), + toolbarSettings: MapToolbarSettings( + direction: Axis.vertical, position: MapToolbarPosition.bottomRight), + maxZoomLevel: 15, + enableDoubleTapZooming: true, + ); _animationController = AnimationController( duration: Duration(seconds: 3), @@ -52,7 +63,7 @@ class _PolylinesSampleState extends SampleViewState ); _animation = CurvedAnimation( - parent: _animationController, + parent: _animationController!, curve: Curves.easeInOut, ); super.initState(); @@ -61,21 +72,24 @@ class _PolylinesSampleState extends SampleViewState @override void dispose() { _animationController?.dispose(); + _animationController = null; _mapController?.dispose(); - _markerData?.clear(); + _mapController = null; + _routes.clear(); super.dispose(); } Future getJsonData() async { - List polyline = []; - String data = await rootBundle.loadString(_routeJson); - dynamic jsonData = json.decode(data); - List polylinePoints = + final List polyline = []; + final String data = await rootBundle.loadString(_routeJson); + final dynamic jsonData = json.decode(data); + final List polylinePoints = jsonData['features'][0]['geometry']['coordinates']; for (int i = 0; i < polylinePoints.length; i++) { polyline.add(MapLatLng(polylinePoints[i][1], polylinePoints[i][0])); } - _animationController.forward(from: 0); + // ignore: unawaited_futures + _animationController?.forward(from: 0); return polyline; } @@ -85,7 +99,8 @@ class _PolylinesSampleState extends SampleViewState final ThemeData themeData = Theme.of(context); _isDesktop = kIsWeb || themeData.platform == TargetPlatform.macOS || - themeData.platform == TargetPlatform.windows; + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; return FutureBuilder( future: getJsonData(), builder: (BuildContext context, AsyncSnapshot snapdata) { @@ -98,72 +113,76 @@ class _PolylinesSampleState extends SampleViewState repeat: ImageRepeat.repeat, ), ), - SfMaps( - layers: [ - MapTileLayer( - urlTemplate: - 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - initialMarkersCount: _markerData.length, - controller: _mapController, - markerBuilder: (BuildContext context, int index) { - if (_markerData[index].icon != null) { - return MapMarker( - key: UniqueKey(), - latitude: _markerData[index].latLan.latitude, - longitude: _markerData[index].latLan.longitude, - child: _markerData[index].icon, - ); - } else { - return MapMarker( - key: UniqueKey(), - latitude: _markerData[index].latLan.latitude, - longitude: _markerData[index].latLan.longitude, - iconType: MapIconType.circle, - iconColor: Colors.white, - iconStrokeWidth: 2.0, - size: Size(15, 15), - iconStrokeColor: Colors.black, + SfMapsTheme( + data: SfMapsThemeData( + shapeHoverColor: Colors.transparent, + ), + child: SfMaps( + layers: [ + MapTileLayer( + urlTemplate: + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + initialMarkersCount: _routes.length, + controller: _mapController, + markerBuilder: (BuildContext context, int index) { + if (_routes[index].icon != null) { + return MapMarker( + key: UniqueKey(), + latitude: _routes[index].latLan.latitude, + longitude: _routes[index].latLan.longitude, + child: _routes[index].icon, + ); + } else { + return MapMarker( + key: UniqueKey(), + latitude: _routes[index].latLan.latitude, + longitude: _routes[index].latLan.longitude, + iconType: MapIconType.circle, + iconColor: Colors.white, + iconStrokeWidth: 2.0, + size: Size(15, 15), + iconStrokeColor: Colors.black, + ); + } + }, + tooltipSettings: MapTooltipSettings( + color: Color.fromRGBO(45, 45, 45, 1), + ), + markerTooltipBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text(_routes[index].city, + style: model.themeData.textTheme.caption! + .copyWith( + color: Color.fromRGBO(255, 255, 255, 1))), ); - } - }, - tooltipSettings: MapTooltipSettings( - color: Color.fromRGBO(45, 45, 45, 1), + }, + sublayers: [ + MapPolylineLayer( + polylines: { + MapPolyline( + points: polylinePoints, + color: Color.fromRGBO(0, 102, 255, 1.0), + width: 6.0, + ) + }, + animation: _animation, + tooltipBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + _routes[0].city + ' - ' + _routes[1].city, + style: model.themeData.textTheme.caption! + .copyWith( + color: Color.fromRGBO( + 255, 255, 255, 1))), + ); + }), + ], + zoomPanBehavior: _zoomPanBehavior, ), - markerTooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text(_markerData[index].city, - style: model.themeData.textTheme.caption.copyWith( - color: Color.fromRGBO(255, 255, 255, 1))), - ); - }, - sublayers: [ - MapPolylineLayer( - polylines: [ - MapPolyline( - points: polylinePoints, - color: Color.fromRGBO(0, 102, 255, 1.0), - width: 6.0, - ) - ].toSet(), - animation: _animation, - tooltipBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - _markerData[0].city + - ' - ' + - _markerData[1].city, - style: model.themeData.textTheme.caption - .copyWith( - color: Color.fromRGBO( - 255, 255, 255, 1))), - ); - }), - ], - zoomPanBehavior: _zoomPanBehavior, - ), - ], + ], + ), ), Align( alignment: Alignment.topCenter, @@ -172,11 +191,11 @@ class _PolylinesSampleState extends SampleViewState child: Row( mainAxisSize: MainAxisSize.min, children: [ - _getChipWidget(0, 'The British Museum'), - _getChipWidget(1, 'The Windsor Castle'), - _getChipWidget(2, 'Twickenham Stadium'), - _getChipWidget(3, 'Chessington World of Adventures'), - _getChipWidget(4, 'Hampton Court Palace'), + _buildChipWidget(0, 'The British Museum'), + _buildChipWidget(1, 'The Windsor Castle'), + _buildChipWidget(2, 'Twickenham Stadium'), + _buildChipWidget(3, 'Chessington World of Adventures'), + _buildChipWidget(4, 'Hampton Court Palace'), ], ), ), @@ -188,13 +207,13 @@ class _PolylinesSampleState extends SampleViewState }); } - Widget _getChipWidget(int index, String city) { + Widget _buildChipWidget(int index, String city) { return Padding( padding: _isDesktop ? const EdgeInsets.only(left: 8.0, top: 8.0) : const EdgeInsets.only(left: 8.0), child: ChoiceChip( - backgroundColor: model?.themeData?.brightness == Brightness.light + backgroundColor: model.themeData.brightness == Brightness.light ? Colors.white : Colors.black, elevation: 3.0, @@ -224,9 +243,9 @@ class _PolylinesSampleState extends SampleViewState _routeJson = 'assets/london_to_british.json'; _zoomPanBehavior.focalLatLng = MapLatLng(51.4700, -0.2843); _zoomPanBehavior.zoomLevel = 10; - _markerData[1] = MarkerData(MapLatLng(51.5194, -0.1270), + _routes[1] = _RouteDetails(MapLatLng(51.5194, -0.1270), Icon(Icons.location_on, color: Colors.red[600], size: 30), city); - _mapController.updateMarkers([1]); + _mapController!.updateMarkers([1]); }); break; case 1: @@ -234,9 +253,9 @@ class _PolylinesSampleState extends SampleViewState _routeJson = 'assets/london_to_windsor_castle.json'; _zoomPanBehavior.focalLatLng = MapLatLng(51.4700, -0.5443); _zoomPanBehavior.zoomLevel = 11; - _markerData[1] = MarkerData(MapLatLng(51.4839, -0.6044), + _routes[1] = _RouteDetails(MapLatLng(51.4839, -0.6044), Icon(Icons.location_on, color: Colors.red[600], size: 30), city); - _mapController.updateMarkers([1]); + _mapController!.updateMarkers([1]); }); break; case 2: @@ -244,9 +263,9 @@ class _PolylinesSampleState extends SampleViewState _routeJson = 'assets/london_to_twickenham_stadium.json'; _zoomPanBehavior.focalLatLng = MapLatLng(51.4700, -0.3843); _zoomPanBehavior.zoomLevel = 11; - _markerData[1] = MarkerData(MapLatLng(51.4560, -0.3415), + _routes[1] = _RouteDetails(MapLatLng(51.4560, -0.3415), Icon(Icons.location_on, color: Colors.red[600], size: 30), city); - _mapController.updateMarkers([1]); + _mapController!.updateMarkers([1]); }); break; case 3: @@ -254,9 +273,9 @@ class _PolylinesSampleState extends SampleViewState _routeJson = 'assets/london_to_chessington.json'; _zoomPanBehavior.focalLatLng = MapLatLng(51.4050, -0.4300); _zoomPanBehavior.zoomLevel = 10; - _markerData[1] = MarkerData(MapLatLng(51.3472, -0.3192), + _routes[1] = _RouteDetails(MapLatLng(51.3472, -0.3192), Icon(Icons.location_on, color: Colors.red[600], size: 30), city); - _mapController.updateMarkers([1]); + _mapController!.updateMarkers([1]); }); break; case 4: @@ -264,19 +283,19 @@ class _PolylinesSampleState extends SampleViewState _routeJson = 'assets/london_to_hampton_court_palace.json'; _zoomPanBehavior.focalLatLng = MapLatLng(51.4500, -0.4393); _zoomPanBehavior.zoomLevel = 11; - _markerData[1] = MarkerData(MapLatLng(51.4036, -0.3378), + _routes[1] = _RouteDetails(MapLatLng(51.4036, -0.3378), Icon(Icons.location_on, color: Colors.red[600], size: 30), city); - _mapController.updateMarkers([1]); + _mapController!.updateMarkers([1]); }); break; } } } -class MarkerData { - MarkerData(this.latLan, this.icon, this.city); +class _RouteDetails { + _RouteDetails(this.latLan, this.icon, this.city); MapLatLng latLan; - Widget icon; + Widget? icon; String city; } diff --git a/lib/samples/pdf/annotations.dart b/lib/samples/pdf/annotations.dart index 4f73e4af..0448ed74 100644 --- a/lib/samples/pdf/annotations.dart +++ b/lib/samples/pdf/annotations.dart @@ -44,9 +44,9 @@ class _AnnotationsPdfState extends SampleViewState { Checkbox( value: flatten, activeColor: model.backgroundColor, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - flatten = value; + flatten = value!; }); }), Text('Flatten Annotation', @@ -56,11 +56,19 @@ class _AnnotationsPdfState extends SampleViewState { const SizedBox(height: 10, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate PDF', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generatePDF)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generatePDF, + child: const Text('Generate PDF', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -119,7 +127,7 @@ class _AnnotationsPdfState extends SampleViewState { if (flatten) { //Flatten all the annotations. - page.annotations.flatten = true; + page.annotations.flattenAllAnnotations(); } //Save and dispose the document. diff --git a/lib/samples/pdf/certificate.dart b/lib/samples/pdf/certificate.dart index dcdf65ff..d421632e 100644 --- a/lib/samples/pdf/certificate.dart +++ b/lib/samples/pdf/certificate.dart @@ -41,7 +41,7 @@ class _CertificatePdfState extends SampleViewState { TextEditingController(text: 'Getting Started with PDF Development'); DateTime selectedDate = DateTime.now(); Future _selectDate(BuildContext context) async { - final DateTime picked = await showDatePicker( + final DateTime? picked = await showDatePicker( context: context, initialDate: selectedDate, firstDate: DateTime(2000), @@ -98,13 +98,20 @@ class _CertificatePdfState extends SampleViewState { _selectDate(context); }), const SizedBox(height: 20, width: 30), - FlatButton( + TextButton( + onPressed: _createCertificate, + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric(vertical: 15, horizontal: 15)), + ), child: const Text( 'Generate PDF', style: TextStyle(color: Colors.white), ), - onPressed: _createCertificate, - color: model.backgroundColor, ) ], ), diff --git a/lib/samples/pdf/conformance.dart b/lib/samples/pdf/conformance.dart index ac4d5f9b..3b5896c7 100644 --- a/lib/samples/pdf/conformance.dart +++ b/lib/samples/pdf/conformance.dart @@ -23,9 +23,9 @@ class ConformancePdf extends SampleView { class _ConformancePdfState extends SampleViewState { _ConformancePdfState(); int _groupValue = 0; - void _changed(int value) { + void _changed(int? value) { setState(() { - _groupValue = value; + _groupValue = value!; }); } @@ -58,11 +58,20 @@ class _ConformancePdfState extends SampleViewState { const SizedBox(height: 10, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate PDF', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _conformance)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _conformance, + child: const Text('Generate PDF', + style: TextStyle(color: Colors.white)), + )) ]), ), )), @@ -97,7 +106,7 @@ class _ConformancePdfState extends SampleViewState { } else { //Create document with PDF/A-3B standard. document = PdfDocument(conformanceLevel: PdfConformanceLevel.a3b); - String text = + final String text = 'Adventure Works Cycles, the fictitious company on which the AdventureWorks sample databases are based, is a large, multinational manufacturing company. The company manufactures and sells metal and composite bicycles to North American, European and Asian commercial markets. While its base operation is located in Bothell, Washington with 290 employees, several regional sales teams are located throughout their market base.'; document.attachments.add(PdfAttachment( 'AdventureCycle.txt', utf8.encode(text), @@ -112,11 +121,11 @@ class _ConformancePdfState extends SampleViewState { bounds: Rect.fromLTWH(0, 0, pageSize.width, pageSize.height), pen: PdfPen(PdfColor(142, 170, 219, 255))); //Read font file. - List fontData = await _readData('Roboto-Regular.ttf'); + final List fontData = await _readData('Roboto-Regular.ttf'); //Create a PDF true type font. - PdfFont contentFont = PdfTrueTypeFont(fontData, 9); - PdfFont headerFont = PdfTrueTypeFont(fontData, 30); - PdfFont footerFont = PdfTrueTypeFont(fontData, 18); + final PdfFont contentFont = PdfTrueTypeFont(fontData, 9); + final PdfFont headerFont = PdfTrueTypeFont(fontData, 30); + final PdfFont footerFont = PdfTrueTypeFont(fontData, 18); //Generate PDF grid. final PdfGrid grid = _getGrid(contentFont); //Draw the header section by creating text element @@ -181,17 +190,17 @@ class _ConformancePdfState extends SampleViewState { return PdfTextElement(text: address, font: contentFont).draw( page: page, bounds: Rect.fromLTWH(30, 120, - pageSize.width - (contentSize.width + 30), pageSize.height - 120)); + pageSize.width - (contentSize.width + 30), pageSize.height - 120))!; } //Draws the grid void _drawGrid( PdfPage page, PdfGrid grid, PdfLayoutResult result, PdfFont contentFont) { - Rect totalPriceCellBounds; - Rect quantityCellBounds; + Rect? totalPriceCellBounds; + Rect? quantityCellBounds; //Invoke the beginCellLayout event. grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - final PdfGrid grid = sender; + final PdfGrid grid = sender as PdfGrid; if (args.cellIndex == grid.columns.count - 1) { totalPriceCellBounds = args.bounds; } else if (args.cellIndex == grid.columns.count - 2) { @@ -200,20 +209,20 @@ class _ConformancePdfState extends SampleViewState { }; //Draw the PDF grid and get the result. result = grid.draw( - page: page, bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0)); + page: page, bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0))!; //Draw grand total. page.graphics.drawString('Grand Total', contentFont, bounds: Rect.fromLTWH( - quantityCellBounds.left, + quantityCellBounds!.left, result.bounds.bottom + 10, - quantityCellBounds.width, - quantityCellBounds.height)); + quantityCellBounds!.width, + quantityCellBounds!.height)); page.graphics.drawString(_getTotalAmount(grid).toString(), contentFont, bounds: Rect.fromLTWH( - totalPriceCellBounds.left, + totalPriceCellBounds!.left, result.bounds.bottom + 10, - totalPriceCellBounds.width, - totalPriceCellBounds.height)); + totalPriceCellBounds!.width, + totalPriceCellBounds!.height)); } //Draw the invoice footer data. @@ -258,9 +267,8 @@ class _ConformancePdfState extends SampleViewState { _addProducts('FK-5136', 'ML Fork', 175.49, 6, 1052.94, grid); _addProducts('HL-U509', 'Sports-100 Helmet,Black', 34.99, 1, 34.99, grid); final PdfPen whitePen = PdfPen(PdfColor.empty, width: 0.5); - PdfBorders borders = PdfBorders(); + final PdfBorders borders = PdfBorders(); borders.all = PdfPen(PdfColor(142, 179, 219), width: 0.5); - ; grid.rows.applyStyle(PdfGridCellStyle(borders: borders)); grid.columns[1].width = 200; for (int i = 0; i < headerRow.cells.count; i++) { diff --git a/lib/samples/pdf/digital_signature.dart b/lib/samples/pdf/digital_signature.dart new file mode 100644 index 00000000..b40e24c2 --- /dev/null +++ b/lib/samples/pdf/digital_signature.dart @@ -0,0 +1,213 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +///Pdf import +import 'package:syncfusion_flutter_pdf/pdf.dart'; + +///Local imports +import '../../model/sample_view.dart'; +import 'helper/save_file_mobile.dart' + if (dart.library.html) 'helper/save_file_web.dart'; + +/// Encrypt PDF document +class SignPdf extends SampleView { + /// Encrypt the PDF document + const SignPdf(Key key) : super(key: key); + @override + _SignPdfState createState() => _SignPdfState(); +} + +class _SignPdfState extends SampleViewState { + _SignPdfState(); + int _groupValue = 1; + int _cryptoGroupValue = 1; + void _digestChanged(int? value) { + setState(() { + _groupValue = value!; + }); + } + + void _cryptoChanged(int? value) { + setState(() { + _cryptoGroupValue = value!; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: model.cardThemeColor, + body: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'This sample shows how to digitally sign the PDF document with .pfx certificates. It also supports various digest algorithms and cryptographic standards.', + style: + TextStyle(fontSize: 16, color: model.textColor)), + const SizedBox(height: 20, width: 30), + Text('Cryptographic Standard', + style: TextStyle( + fontSize: 16, + color: model.textColor, + fontWeight: FontWeight.bold)), + const SizedBox(height: 10, width: 30), + (MediaQuery.of(context).size.width > 800) + ? Row(children: getCryptographicChildWidgets(context)) + : Column( + children: getCryptographicChildWidgets(context)), + const SizedBox(height: 20, width: 30), + Text('Digest Algorithm', + style: TextStyle( + fontSize: 16, + color: model.textColor, + fontWeight: FontWeight.bold)), + const SizedBox(height: 10, width: 30), + (MediaQuery.of(context).size.width > 800) + ? Row(children: getDigestChildWidgets(context)) + : Column(children: getDigestChildWidgets(context)), + const SizedBox(height: 10, width: 30), + Align( + alignment: Alignment.center, + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _signPDF, + child: const Text('Sign PDF', + style: TextStyle(color: Colors.white)), + )) + ]), + ), + ))); + } + + List getDigestChildWidgets(BuildContext context) { + return [ + Row(children: [ + Radio(value: 0, groupValue: _groupValue, onChanged: _digestChanged), + Text('SHA1', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio(value: 1, groupValue: _groupValue, onChanged: _digestChanged), + Text('SHA256', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio(value: 2, groupValue: _groupValue, onChanged: _digestChanged), + Text('SHA384', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio(value: 3, groupValue: _groupValue, onChanged: _digestChanged), + Text('SHA512', style: TextStyle(fontSize: 16, color: model.textColor)), + ]) + ]; + } + + List getCryptographicChildWidgets(BuildContext context) { + return [ + Row(children: [ + Radio( + value: 0, groupValue: _cryptoGroupValue, onChanged: _cryptoChanged), + Text('CMS', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio( + value: 1, groupValue: _cryptoGroupValue, onChanged: _cryptoChanged), + Text('CAdES', style: TextStyle(fontSize: 16, color: model.textColor)), + ]) + ]; + } + + Future _signPDF() async { + //Load the PDF document. + final PdfDocument document = PdfDocument( + inputBytes: await _readDocumentData('digital_signature_template.pdf')); + + //Get the signature field. + final PdfSignatureField signatureField = + document.form.fields[6] as PdfSignatureField; + + //Create Pdf certificate. + final PdfCertificate certificate = PdfCertificate( + await _readDocumentData('certificate.pfx'), 'password123'); + + //Get signature field and sign. + signatureField.signature = PdfSignature( + certificate: certificate, + contactInfo: 'johndoe@owned.us', + locationInfo: 'Honolulu, Hawaii', + reason: 'I am author of this document.', + digestAlgorithm: _getDigestAlgorithm(), + cryptographicStandard: _cryptoGroupValue == 1 + ? CryptographicStandard.cades + : CryptographicStandard.cms); + + //Get the signatue field bounds. + final Rect bounds = signatureField.bounds; + + //Draw appearance. + //Get the signature field appearance graphics. + final PdfGraphics? graphics = signatureField.appearance.normal.graphics; + if (graphics != null) { + graphics.drawRectangle( + pen: PdfPens.black, + bounds: Rect.fromLTWH(0, 0, bounds.width, bounds.height)); + graphics.drawImage( + PdfBitmap(await _readDocumentData('signature.png', true)), + Rect.fromLTWH(2, 1, 30, 30)); + //Get certificate subject name. + final String subject = certificate.subjectName; + graphics.drawString( + 'Digitally signed by $subject \r\nReason: Testing signature \r\nLocation: USA', + PdfStandardFont(PdfFontFamily.helvetica, 7), + bounds: Rect.fromLTWH(45, 0, bounds.width - 45, bounds.height), + brush: PdfBrushes.black, + format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle)); + } + + //Save the PDF document + final List bytes = document.save(); + //Dispose the document. + document.dispose(); + //Save and launch file. + await FileSaveHelper.saveAndLaunchFile(bytes, 'SignedPdf.pdf'); + } + + Future> _readDocumentData(String name, + [bool isImage = false]) async { + final ByteData data = await rootBundle + .load(isImage ? 'images/pdf/$name' : 'assets/pdf/$name'); + return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + } + + DigestAlgorithm _getDigestAlgorithm() { + DigestAlgorithm algorithm; + switch (_groupValue) { + case 0: + algorithm = DigestAlgorithm.sha1; + break; + case 2: + algorithm = DigestAlgorithm.sha384; + break; + case 3: + algorithm = DigestAlgorithm.sha512; + break; + default: + algorithm = DigestAlgorithm.sha256; + break; + } + return algorithm; + } +} diff --git a/lib/samples/pdf/encryption.dart b/lib/samples/pdf/encryption.dart index a14d65af..72c313e3 100644 --- a/lib/samples/pdf/encryption.dart +++ b/lib/samples/pdf/encryption.dart @@ -21,9 +21,9 @@ class EncryptPdf extends SampleView { class _EncryptPdfState extends SampleViewState { _EncryptPdfState(); int _groupValue = 3; - void _changed(int value) { + void _changed(int? value) { setState(() { - _groupValue = value; + _groupValue = value!; }); } @@ -79,11 +79,20 @@ class _EncryptPdfState extends SampleViewState { const SizedBox(height: 15, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Encrypt PDF', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _encryptPDF)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _encryptPDF, + child: const Text('Encrypt PDF', + style: TextStyle(color: Colors.white)), + )) ]), ), ))); @@ -125,7 +134,7 @@ class _EncryptPdfState extends SampleViewState { inputBytes: await _readDocumentData('credit_card_statement.pdf')); // Get the PDF security. - PdfSecurity security = document.security; + final PdfSecurity security = document.security; //Set passwords security.userPassword = 'password@123'; diff --git a/lib/samples/pdf/find_text.dart b/lib/samples/pdf/find_text.dart index 57038a08..e4a317cf 100644 --- a/lib/samples/pdf/find_text.dart +++ b/lib/samples/pdf/find_text.dart @@ -39,39 +39,56 @@ class _FindTextPdfState extends SampleViewState { const SizedBox(height: 20, width: 30), Center( child: SizedBox( - child: TextFormField( - decoration: InputDecoration( - labelText: 'Enter the text to find', - labelStyle: TextStyle( - color: model.themeData.brightness == - Brightness.light - ? Colors.grey - : Colors.lightBlue)), - controller: _nameController, - style: TextStyle(color: model.textColor)), - height: 60, - width: 300)), + height: 60, + width: 300, + child: TextFormField( + decoration: InputDecoration( + labelText: 'Enter the text to find', + labelStyle: TextStyle( + color: + model.themeData.brightness == Brightness.light + ? Colors.grey + : Colors.lightBlue)), + controller: _nameController, + style: TextStyle(color: model.textColor)), + )), const SizedBox(height: 20, width: 30), Container( child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - FlatButton( - child: Text('View Template', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _viewTemplate), + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _viewTemplate, + child: Text('View Template', + style: TextStyle(color: Colors.white)), + ), SizedBox( height: 10, width: 20, ), - FlatButton( - child: const Text('Find and Highlight', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generatePDF) + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generatePDF, + child: const Text('Find and Highlight', + style: TextStyle(color: Colors.white)), + ) ], - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, ), ) ], @@ -82,9 +99,9 @@ class _FindTextPdfState extends SampleViewState { } Future _viewTemplate() async { - List documentBytes = + final List documentBytes = await _readDocumentData('pdf_succinctly_template.pdf'); - await FileSaveHelper.saveAndLaunchFile(documentBytes, 'PDF Succinctly.pdf'); + await FileSaveHelper.saveAndLaunchFile(documentBytes, 'pdf_succinctly.pdf'); } Future _generatePDF() async { @@ -93,21 +110,21 @@ class _FindTextPdfState extends SampleViewState { inputBytes: await _readDocumentData('pdf_succinctly_template.pdf')); //Create PDF text extractor to find text. - PdfTextExtractor extractor = PdfTextExtractor(document); + final PdfTextExtractor extractor = PdfTextExtractor(document); //Find the text - List result = extractor.findText([_nameController.text]); + final List result = extractor.findText([_nameController.text]); - if (result.length == 0) { + if (result.isEmpty) { document.dispose(); _showDialog(_nameController.text); } else { //Highlight the searched text from the document. for (int i = 0; i < result.length; i++) { - MatchedItem item = result[i]; + final MatchedItem item = result[i]; //Get page. - PdfPage page = document.pages[item.pageIndex]; + final PdfPage page = document.pages[item.pageIndex]; //Set transparency to the page graphics. page.graphics.save(); @@ -120,11 +137,11 @@ class _FindTextPdfState extends SampleViewState { } //Save and dispose the document. - List bytes = document.save(); + final List bytes = document.save(); document.dispose(); //Launch file. - await FileSaveHelper.saveAndLaunchFile(bytes, 'Find Text.pdf'); + await FileSaveHelper.saveAndLaunchFile(bytes, 'find_text.pdf'); } } @@ -145,11 +162,11 @@ class _FindTextPdfState extends SampleViewState { Text(' is not found.') ]), actions: [ - FlatButton( - child: Text('Close'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: Text('Close'), ) ], ); diff --git a/lib/samples/pdf/form.dart b/lib/samples/pdf/form.dart new file mode 100644 index 00000000..7417d9b7 --- /dev/null +++ b/lib/samples/pdf/form.dart @@ -0,0 +1,373 @@ +///Dart import +import 'dart:typed_data'; + +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; + +///Pdf import +import 'package:syncfusion_flutter_pdf/pdf.dart'; + +///Local imports +import '../../model/sample_view.dart'; +import 'helper/save_file_mobile.dart' + if (dart.library.html) 'helper/save_file_web.dart'; + +/// Render pdf of course completion certificate +class FormFillingPdf extends SampleView { + /// Creates pdf of course completion certificate + const FormFillingPdf(Key key) : super(key: key); + @override + _FormFillingPdfState createState() => _FormFillingPdfState(); +} + +class _FormFillingPdfState extends SampleViewState { + _FormFillingPdfState(); + + @override + void dispose() { + _dateController.dispose(); + _nameController.dispose(); + _emailController.dispose(); + super.dispose(); + } + + final TextEditingController _dateController = TextEditingController( + text: DateFormat('MMMM d, yyyy').format(DateTime(2000, 5, 12))); + final TextEditingController _nameController = + TextEditingController(text: 'John Milton'); + final TextEditingController _emailController = + TextEditingController(text: 'john.milton@example.com'); + int _groupValue = 0; + String _dropdownValue = 'Alabama'; + bool _newsletter = true; + DateTime selectedDate = DateTime.now(); + Future _selectDate(BuildContext context) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: selectedDate, + firstDate: DateTime(2000), + lastDate: DateTime(2100)); + if (picked != null && picked != selectedDate) { + setState(() { + selectedDate = picked; + _dateController.text = DateFormat('MMMM d, yyyy').format(selectedDate); + }); + } + } + + void _changed(int? value) { + setState(() { + _groupValue = value!; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: model.cardThemeColor, + body: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Center( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'This sample shows how to fill the existing form fields in a PDF document. It also supports flattening the form fields.', + style: TextStyle(fontSize: 16, color: model.textColor)), + const SizedBox(height: 20, width: 30), + TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Name', + labelStyle: TextStyle( + color: model.themeData.brightness == + Brightness.light + ? Colors.grey + : Colors.lightBlue)), + controller: _nameController, + style: TextStyle(color: model.textColor)), + const SizedBox(height: 20, width: 30), + TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Email', + labelStyle: TextStyle( + color: model.themeData.brightness == + Brightness.light + ? Colors.grey + : Colors.lightBlue)), + controller: _emailController, + style: TextStyle(color: model.textColor)), + const SizedBox(height: 20, width: 30), + InputDecorator( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Gender', + labelStyle: TextStyle( + color: + model.themeData.brightness == Brightness.light + ? Colors.grey + : Colors.lightBlue)), + child: SizedBox( + height: 25, + child: Row(children: _getGenderWidgets(context)), + ), + ), + const SizedBox(height: 20, width: 30), + TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Date Of Birth', + labelStyle: TextStyle( + color: model.themeData.brightness == + Brightness.light + ? Colors.grey + : Colors.lightBlue)), + controller: _dateController, + style: TextStyle(color: model.textColor), + onTap: () { + _selectDate(context); + }), + const SizedBox(height: 20, width: 30), + DropdownButtonFormField( + value: _dropdownValue, + onChanged: (String? newValue) { + setState(() { + _dropdownValue = newValue!; + }); + }, + items: [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'Florida', + 'Georgia', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming' + ] + .map>((e) => + DropdownMenuItem( + value: e, child: Text(e))) + .toList(), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Coming from', + labelStyle: TextStyle( + color: + model.themeData.brightness == Brightness.light + ? Colors.grey + : Colors.lightBlue)), + ), + const SizedBox(height: 5, width: 30), + Row(children: [ + Checkbox( + value: _newsletter, + onChanged: (bool? value) { + setState(() { + _newsletter = value!; + }); + }), + Text('Would you like to receive our Newsletter?') + ]), + const SizedBox(height: 10, width: 30), + Center( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: _getButtonWidgets(context), + )), + ], + ), + ), + ))); + } + + Widget _getButtonWidgets(BuildContext context) { + return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + TextButton( + onPressed: _viewTemplate, + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric(vertical: 15, horizontal: 15)), + ), + child: const Text( + 'View Template', + style: TextStyle(color: Colors.white), + ), + ), + const SizedBox(height: 0, width: 12), + TextButton( + onPressed: () => _fillFormFields(false), + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric(vertical: 15, horizontal: 15)), + ), + child: const Text( + 'Fill Form', + style: TextStyle(color: Colors.white), + ), + ), + const SizedBox(height: 0, width: 12), + TextButton( + onPressed: () => _fillFormFields(true), + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all( + EdgeInsets.symmetric(vertical: 15, horizontal: 15)), + ), + child: const Text( + 'Fill And Flatten', + style: TextStyle(color: Colors.white), + ), + ) + ]); + } + + List _getGenderWidgets(BuildContext context) { + return [ + Row(children: [ + Radio( + value: 0, + groupValue: _groupValue, + onChanged: _changed, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + Text('Male', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio( + value: 2, + groupValue: _groupValue, + onChanged: _changed, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + Text('Female', style: TextStyle(fontSize: 16, color: model.textColor)), + ]), + Row(children: [ + Radio( + value: 1, + groupValue: _groupValue, + onChanged: _changed, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + Text('Unspecified', + style: TextStyle(fontSize: 16, color: model.textColor)), + ]) + ]; + } + + Future _fillFormFields(bool isFlatten) async { + //Load the existing PDF document + final PdfDocument document = + PdfDocument(inputBytes: await _readData('form_template.pdf')); + + //Get the form + final PdfForm form = document.form; + + //Get text box and fill value + final PdfTextBoxField name = document.form.fields[1] as PdfTextBoxField; + name.text = _nameController.text; + + final PdfTextBoxField email = document.form.fields[2] as PdfTextBoxField; + email.text = _emailController.text; + + //Get the radio button and select + final PdfRadioButtonListField gender = + form.fields[3] as PdfRadioButtonListField; + gender.selectedIndex = _groupValue; + + final PdfTextBoxField dob = form.fields[0] as PdfTextBoxField; + dob.text = _dateController.text; + + //Get the combo box field and select + final PdfComboBoxField country = form.fields[4] as PdfComboBoxField; + country.selectedValue = _dropdownValue; + + //Get the checkbox field + final PdfCheckBoxField newsletter = form.fields[5] as PdfCheckBoxField; + newsletter.isChecked = _newsletter; + + //Disable to view the form field values properly in mobile viewers + form.setDefaultAppearance(false); + + // Set flatten + if (isFlatten) { + form.flattenAllFields(); + } + + //Save and launch the document + final List bytes = document.save(); + //Dispose the document. + document.dispose(); + + //Save and launch file. + await FileSaveHelper.saveAndLaunchFile( + bytes, isFlatten ? 'Flatten.pdf' : 'Form.pdf'); + } + + Future _viewTemplate() async { + final List documentBytes = await _readData('form_template.pdf'); + await FileSaveHelper.saveAndLaunchFile(documentBytes, 'form_template.pdf'); + } + + Future> _readData(String name) async { + final ByteData data = await rootBundle.load('assets/pdf/$name'); + return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + } +} diff --git a/lib/samples/pdf/header_and_footer.dart b/lib/samples/pdf/header_and_footer.dart index 1e8bc0ca..104e5dfd 100644 --- a/lib/samples/pdf/header_and_footer.dart +++ b/lib/samples/pdf/header_and_footer.dart @@ -38,11 +38,19 @@ class _HeaderAndFooterPdfState extends SampleViewState { const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate PDF', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generatePDF)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generatePDF, + child: const Text('Generate PDF', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -80,7 +88,7 @@ class _HeaderAndFooterPdfState extends SampleViewState { titlePage.getClientSize().height), format: format); //Add new Section - final PdfSection section = document.sections.add(); + final PdfSection section = document.sections!.add(); final PdfPage contentPage = section.pages.add(); _addParagraph(contentPage, 'Table of Contents', Rect.fromLTWH(20, 60, 495, contentPage.getClientSize().height), true, @@ -327,20 +335,20 @@ class _HeaderAndFooterPdfState extends SampleViewState { .draw( page: page, bounds: Rect.fromLTWH( - bounds.left, bounds.top, bounds.width, bounds.height)); + bounds.left, bounds.top, bounds.width, bounds.height))!; } PdfBookmark _addBookmark(PdfPage page, String text, Offset point, - {PdfDocument doc, PdfBookmark bookmark, PdfColor color}) { + {PdfDocument? doc, PdfBookmark? bookmark, PdfColor? color}) { PdfBookmark book; if (doc != null) { book = doc.bookmarks.add(text); book.destination = PdfDestination(page, point); - } else if (bookmark != null) { - book = bookmark.add(text); + } else { + book = bookmark!.add(text); book.destination = PdfDestination(page, point); } - book.color = color; + book.color = color ?? PdfColor(0, 0, 0); return book; } @@ -368,7 +376,7 @@ class _HeaderAndFooterPdfState extends SampleViewState { return PdfTextElement(text: str, font: font).draw( page: page, bounds: Rect.fromLTWH(isTitle ? bounds.left : bounds.left + 20, - bounds.top + 5, bounds.width, bounds.height)); + bounds.top + 5, bounds.width, bounds.height))!; } Future> _readImageData(String name) async { diff --git a/lib/samples/pdf/helper/save_file_mobile.dart b/lib/samples/pdf/helper/save_file_mobile.dart index cfdc7c8b..d418d290 100644 --- a/lib/samples/pdf/helper/save_file_mobile.dart +++ b/lib/samples/pdf/helper/save_file_mobile.dart @@ -4,6 +4,7 @@ import 'dart:io'; ///Package imports import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; ///To save the pdf file in the device class FileSaveHelper { @@ -12,19 +13,36 @@ class FileSaveHelper { ///To save the pdf file in the device static Future saveAndLaunchFile( List bytes, String fileName) async { - final Directory directory = await getApplicationDocumentsDirectory(); - final String path = directory.path; - final File file = File('$path/$fileName'); + String? path; + if (Platform.isAndroid || + Platform.isIOS || + Platform.isLinux || + Platform.isWindows) { + final Directory directory = await getApplicationSupportDirectory(); + path = directory.path; + } else { + path = await PathProviderPlatform.instance.getApplicationSupportPath(); + } + final File file = + File(Platform.isWindows ? '$path\\$fileName' : '$path/$fileName'); await file.writeAsBytes(bytes, flush: true); - final Map argument = { - 'file_path': '$path/$fileName' - }; - try { - //ignore: unused_local_variable - final Future> result = - _platformCall.invokeMethod('viewPdf', argument); - } catch (e) { - throw Exception(e); + if (Platform.isAndroid || Platform.isIOS) { + final Map argument = { + 'file_path': '$path/$fileName' + }; + try { + //ignore: unused_local_variable + final Future?> result = + _platformCall.invokeMethod('viewPdf', argument); + } catch (e) { + throw Exception(e); + } + } else if (Platform.isWindows) { + await Process.run('start', ['$path\\$fileName'], runInShell: true); + } else if (Platform.isMacOS) { + await Process.run('open', ['$path/$fileName'], runInShell: true); + } else if (Platform.isLinux) { + await Process.run('xdg-open', ['$path/$fileName'], runInShell: true); } } } diff --git a/lib/samples/pdf/helper/save_file_web.dart b/lib/samples/pdf/helper/save_file_web.dart index c68ffc30..d975d697 100644 --- a/lib/samples/pdf/helper/save_file_web.dart +++ b/lib/samples/pdf/helper/save_file_web.dart @@ -1,18 +1,18 @@ ///Dart imports import 'dart:async'; import 'dart:convert'; -//ignore: avoid_web_libraries_in_flutter -import 'dart:js' as js; +// ignore: avoid_web_libraries_in_flutter +import 'dart:html'; ///To save the pdf file in the device class FileSaveHelper { ///To save the pdf file in the device static Future saveAndLaunchFile( List bytes, String fileName) async { - js.context['pdfdata'] = base64.encode(bytes); - js.context['filename'] = fileName; - Timer.run(() { - js.context.callMethod('download'); - }); + AnchorElement( + href: + 'data:application/octet-stream;charset=utf-16le;base64,${base64.encode(bytes)}') + ..setAttribute('download', fileName) + ..click(); } } diff --git a/lib/samples/pdf/invoice.dart b/lib/samples/pdf/invoice.dart index a02a2599..04653982 100644 --- a/lib/samples/pdf/invoice.dart +++ b/lib/samples/pdf/invoice.dart @@ -38,11 +38,19 @@ class _InvoicePdfState extends SampleViewState { const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate PDF', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generatePDF)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generatePDF, + child: const Text('Generate PDF', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -120,16 +128,16 @@ class _InvoicePdfState extends SampleViewState { return PdfTextElement(text: address, font: contentFont).draw( page: page, bounds: Rect.fromLTWH(30, 120, - pageSize.width - (contentSize.width + 30), pageSize.height - 120)); + pageSize.width - (contentSize.width + 30), pageSize.height - 120))!; } //Draws the grid void _drawGrid(PdfPage page, PdfGrid grid, PdfLayoutResult result) { - Rect totalPriceCellBounds; - Rect quantityCellBounds; + Rect? totalPriceCellBounds; + Rect? quantityCellBounds; //Invoke the beginCellLayout event. grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - final PdfGrid grid = sender; + final PdfGrid grid = sender as PdfGrid; if (args.cellIndex == grid.columns.count - 1) { totalPriceCellBounds = args.bounds; } else if (args.cellIndex == grid.columns.count - 2) { @@ -138,22 +146,22 @@ class _InvoicePdfState extends SampleViewState { }; //Draw the PDF grid and get the result. result = grid.draw( - page: page, bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0)); + page: page, bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0))!; //Draw grand total. page.graphics.drawString('Grand Total', PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), bounds: Rect.fromLTWH( - quantityCellBounds.left, + quantityCellBounds!.left, result.bounds.bottom + 10, - quantityCellBounds.width, - quantityCellBounds.height)); + quantityCellBounds!.width, + quantityCellBounds!.height)); page.graphics.drawString(_getTotalAmount(grid).toString(), PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), bounds: Rect.fromLTWH( - totalPriceCellBounds.left, + totalPriceCellBounds!.left, result.bounds.bottom + 10, - totalPriceCellBounds.width, - totalPriceCellBounds.height)); + totalPriceCellBounds!.width, + totalPriceCellBounds!.height)); } //Draw the invoice footer data. diff --git a/lib/samples/pdf/text_extraction.dart b/lib/samples/pdf/text_extraction.dart index 008a4227..5bab50cb 100644 --- a/lib/samples/pdf/text_extraction.dart +++ b/lib/samples/pdf/text_extraction.dart @@ -38,24 +38,40 @@ class _TextExtractionPdfState extends SampleViewState { const SizedBox(height: 20, width: 30), Container( child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - FlatButton( - child: Text('View Template', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _viewTemplate), + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _viewTemplate, + child: Text('View Template', + style: TextStyle(color: Colors.white)), + ), SizedBox( height: 10, width: 20, ), - FlatButton( - child: const Text('Extract Text', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generatePDF) + TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generatePDF, + child: const Text('Extract Text', + style: TextStyle(color: Colors.white)), + ) ], - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, ), ) ], @@ -66,9 +82,9 @@ class _TextExtractionPdfState extends SampleViewState { } Future _viewTemplate() async { - List documentBytes = + final List documentBytes = await _readDocumentData('pdf_succinctly_template.pdf'); - await FileSaveHelper.saveAndLaunchFile(documentBytes, 'PDF Succinctly.pdf'); + await FileSaveHelper.saveAndLaunchFile(documentBytes, 'pdf_succinctly.pdf'); } Future _generatePDF() async { @@ -77,10 +93,11 @@ class _TextExtractionPdfState extends SampleViewState { inputBytes: await _readDocumentData('pdf_succinctly_template.pdf')); //Create PDF text extractor to extract text. - PdfTextExtractor extractor = PdfTextExtractor(document); + final PdfTextExtractor extractor = PdfTextExtractor(document); //Extract text. - String text = extractor.extractText(startPageIndex: 0, endPageIndex: 4); + final String text = + extractor.extractText(startPageIndex: 0, endPageIndex: 4); //Dispose the document. document.dispose(); @@ -101,17 +118,17 @@ class _TextExtractionPdfState extends SampleViewState { title: Text('Extracted text'), content: Scrollbar( child: SingleChildScrollView( - child: Text(text), physics: BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics()), + child: Text(text), ), ), actions: [ - FlatButton( - child: Text('Close'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: Text('Close'), ) ], ); diff --git a/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart b/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart index 0c376b3c..b5a97b3f 100644 --- a/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart +++ b/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart @@ -1,9 +1,12 @@ /// Package import +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart'; /// PDF Viewer import import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart'; +import 'package:syncfusion_flutter_pdf/pdf.dart'; /// Core theme import import 'package:syncfusion_flutter_core/theme.dart'; @@ -11,6 +14,9 @@ import 'package:syncfusion_flutter_core/theme.dart'; /// Local import import '../../model/sample_view.dart'; +import './shared/mobile_helper.dart' + if (dart.library.html) './shared/web_helper.dart' as helper; + /// Widget of [SfPdfViewer] with custom toolbar. class CustomToolbarPdfViewer extends SampleView { /// Creates a [SfPdfViewer] with custom toolbar. @@ -22,22 +28,32 @@ class CustomToolbarPdfViewer extends SampleView { /// State for the [SfPdfViewer] widget with custom toolbar class _CustomToolbarPdfViewerState extends SampleViewState { - String _documentPath; - final GlobalKey _pdfViewerKey = GlobalKey(); + bool _showPdf = false; + bool _showToolbar = false; + bool _showToast = false; + bool _showScrollHead = false; + OverlayEntry? _selectionOverlayEntry; + PdfTextSelectionChangedDetails? _textSelectionDetails; + Color? _contextMenuColor; + Color? _copyColor; + double _contextMenuWidth = 0.0; + double _contextMenuHeight = 0.0; + OverlayEntry? _textSearchOverlayEntry; + OverlayEntry? _chooseFileOverlayEntry; + LocalHistoryEntry? _historyEntry; + bool _isNeedToMaximize = false; + String? _documentPath; + PdfInteractionMode _interactionMode = PdfInteractionMode.selection; + final FocusNode _focusNode = FocusNode()..requestFocus(); + final GlobalKey? _toolbarKey = GlobalKey(); + final GlobalKey? _pdfViewerKey = GlobalKey(); final PdfViewerController _pdfViewerController = PdfViewerController(); - final GlobalKey _textSearchKey = GlobalKey(); - bool _showPdf; - bool _showToolbar; - bool _showToast; - bool _showScrollHead; - OverlayEntry _overlayEntry; - Color _contextMenuColor; - Color _copyColor; - double _contextMenuWidth; - double _contextMenuHeight; + final GlobalKey? _textSearchKey = GlobalKey(); + final GlobalKey<_TextSearchOverlayState>? _textSearchOverlayKey = GlobalKey(); @override void initState() { + super.initState(); _documentPath = 'assets/pdf/gis_succinctly.pdf'; _showPdf = false; _showToolbar = true; @@ -45,7 +61,11 @@ class _CustomToolbarPdfViewerState extends SampleViewState { _showScrollHead = true; _contextMenuHeight = 48; _contextMenuWidth = 100; - super.initState(); + if (kIsWeb && + model.isMobileResolution != null && + !model.isMobileResolution) { + helper.preventDefaultMenu(); + } } @override @@ -57,163 +77,423 @@ class _CustomToolbarPdfViewerState extends SampleViewState { _copyColor = model.themeData.brightness == Brightness.light ? Color(0xFF000000) : Color(0xFFFFFFFF); + if (_isNeedToMaximize != model.needToMaximize) { + _closeOverlay(); + _isNeedToMaximize = model.needToMaximize; + } super.didChangeDependencies(); } + @override + void dispose() { + _closeOverlay(); + super.dispose(); + } + + // Closes all overlay entry when drawer is opened. + void _closeOverlay() { + _closeChooseFileMenu(); + _toolbarKey?.currentState?.closeZoomPercentageMenu(); + _textSearchKey?.currentState?._pdfTextSearchResult.clear(); + _handleSearchMenuClose(); + _checkAndCloseContextMenu(); + } + /// Show Context menu for Text Selection. - void _showContextMenu( - BuildContext context, PdfTextSelectionChangedDetails details) { - final RenderBox renderBoxContainer = - context.findRenderObject() as RenderBox; - final Offset containerOffset = renderBoxContainer.localToGlobal( - renderBoxContainer.paintBounds.topLeft, - ); - if (containerOffset.dy < details.globalSelectedRegion.topLeft.dy - 55 || - (containerOffset.dy < - details.globalSelectedRegion.center.dy - - (_contextMenuHeight / 2) && - details.globalSelectedRegion.height > _contextMenuWidth)) { - double top = details.globalSelectedRegion.height > _contextMenuWidth - ? details.globalSelectedRegion.center.dy - (_contextMenuHeight / 2) - : details.globalSelectedRegion.topLeft.dy - 55; - double left = details.globalSelectedRegion.height > _contextMenuWidth - ? details.globalSelectedRegion.center.dx - (_contextMenuWidth / 2) - : details.globalSelectedRegion.bottomLeft.dx; - if ((details.globalSelectedRegion.top) > - MediaQuery.of(context).size.height / 2) { - top = details.globalSelectedRegion.topLeft.dy - 55; - left = details.globalSelectedRegion.bottomLeft.dx; - } - final OverlayState _overlayState = Overlay.of(context); - _overlayEntry = OverlayEntry( - builder: (context) => Positioned( - top: top, - left: left, - child: Container( - decoration: BoxDecoration( - color: _contextMenuColor, - boxShadow: [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.14), - blurRadius: 2, - offset: Offset(0, 0), - ), - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.12), - blurRadius: 2, - offset: Offset(0, 2), - ), - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.2), - blurRadius: 3, - offset: Offset(0, 1), - ), - ], - ), - constraints: BoxConstraints.tightFor( - width: _contextMenuWidth, height: _contextMenuHeight), - child: FlatButton( - child: Text( - 'Copy', - style: TextStyle(fontSize: 17, color: _copyColor), + void _showContextMenu(BuildContext context, Offset? offset) { + _contextMenuHeight = (kIsWeb && + model.isMobileResolution != null && + !model.isMobileResolution) + ? 32 + : 48; + final PdfTextSelectionChangedDetails? details = _textSelectionDetails; + final RenderBox? renderBoxContainer = + // ignore: avoid_as + context.findRenderObject()! as RenderBox; + if (renderBoxContainer != null) { + final Offset containerOffset = renderBoxContainer.localToGlobal( + renderBoxContainer.paintBounds.topLeft, + ); + if (details != null && + containerOffset.dy < + details.globalSelectedRegion!.topLeft.dy - 55 || + (containerOffset.dy < + details!.globalSelectedRegion!.center.dy - + (_contextMenuHeight / 2) && + details.globalSelectedRegion!.height > _contextMenuWidth)) { + double top = details.globalSelectedRegion!.height > _contextMenuWidth + ? details.globalSelectedRegion!.center.dy - (_contextMenuHeight / 2) + : details.globalSelectedRegion!.topLeft.dy - 55; + double left = details.globalSelectedRegion!.height > _contextMenuWidth + ? details.globalSelectedRegion!.center.dx - (_contextMenuWidth / 2) + : details.globalSelectedRegion!.bottomLeft.dx; + if ((details.globalSelectedRegion!.top) > + MediaQuery.of(context).size.height / 2) { + top = details.globalSelectedRegion!.topLeft.dy - 55; + left = details.globalSelectedRegion!.bottomLeft.dx; + } + if (offset != null) { + top = offset.dy; + left = offset.dx; + } + final OverlayState? _overlayState = + Overlay.of(context, rootOverlay: true); + _selectionOverlayEntry = OverlayEntry( + builder: (context) => Positioned( + top: top, + left: left, + child: Container( + decoration: BoxDecoration( + color: _contextMenuColor, + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.14), + blurRadius: 2, + offset: Offset(0, 0), + ), + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.12), + blurRadius: 2, + offset: Offset(0, 2), + ), + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.2), + blurRadius: 3, + offset: Offset(0, 1), + ), + ], ), - onPressed: () async { - _checkAndCloseContextMenu(); - _pdfViewerController.clearSelection(); - if (_textSearchKey.currentState?._pdfTextSearchResult != null && - _textSearchKey - .currentState._pdfTextSearchResult.hasResult) { + constraints: BoxConstraints.tightFor( + width: _contextMenuWidth, height: _contextMenuHeight), + child: TextButton( + onPressed: () async { + _checkAndCloseContextMenu(); + _pdfViewerController.clearSelection(); + if (!kIsWeb && + _textSearchKey?.currentState?._pdfTextSearchResult != + null && + _textSearchKey! + .currentState!._pdfTextSearchResult.hasResult || + (kIsWeb && + model.isMobileResolution != null && + model.isMobileResolution) && + _textSearchKey?.currentState?._pdfTextSearchResult != + null && + _textSearchKey! + .currentState!._pdfTextSearchResult.hasResult) { + setState(() { + _showToolbar = false; + }); + } + await Clipboard.setData( + ClipboardData(text: details.selectedText)); setState(() { - _showToolbar = false; + _showToast = true; }); - } - await Clipboard.setData( - ClipboardData(text: details.selectedText)); - setState(() { - _showToast = true; - }); - await Future.delayed(Duration(seconds: 1)); - setState(() { - _showToast = false; - }); - }, + await Future.delayed(Duration(seconds: 1)); + setState(() { + _showToast = false; + }); + }, + child: Text( + 'Copy', + style: (kIsWeb && + model.isMobileResolution != null && + !model.isMobileResolution) + ? TextStyle( + color: _copyColor, + fontSize: 16, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400) + : TextStyle(fontSize: 17, color: _copyColor), + ), + ), ), ), - ), - ); - _overlayState.insert(_overlayEntry); + ); + _overlayState?.insert(_selectionOverlayEntry!); + } + } + } + + /// Check and close the text selection context menu. + void _checkAndCloseContextMenu() { + if (_selectionOverlayEntry != null) { + _selectionOverlayEntry?.remove(); + _selectionOverlayEntry = null; } } - /// Ensure the entry history of Text search. - LocalHistoryEntry _historyEntry; + /// Ensure the entry history of text search. void _ensureHistoryEntry() { if (_historyEntry == null) { - final ModalRoute route = ModalRoute.of(context); + final ModalRoute? route = ModalRoute.of(context); if (route != null) { _historyEntry = LocalHistoryEntry(onRemove: _handleHistoryEntryRemoved); - route.addLocalHistoryEntry(_historyEntry); + route.addLocalHistoryEntry(_historyEntry!); } } } + /// Remove history entry for text search. void _handleHistoryEntryRemoved() { _textSearchKey?.currentState?.clearSearch(); _historyEntry = null; + _showScrollHead = true; + } + + /// Show text search menu for web platform. + void _showTextSearchMenu() { + if (_textSearchOverlayEntry == null) { + _toolbarKey?.currentState?._focusToolbarButton('Search'); + final RenderBox? searchRenderBox = + _toolbarKey?.currentState?._searchKey.currentContext + // ignore: avoid_as + ?.findRenderObject() as RenderBox; + if (searchRenderBox != null) { + final Offset position = searchRenderBox.localToGlobal(Offset.zero); + final OverlayState? overlayState = + Overlay.of(context, rootOverlay: true); + overlayState?.insert(_textSearchOverlayEntry = OverlayEntry( + builder: (BuildContext context) { + return Positioned( + top: position.dy + 40.0, // y position of search menu + left: (MediaQuery.of(context).size.width - 8) - + 412, // x position of search menu + child: TextSearchOverlay( + key: _textSearchOverlayKey!, + controller: _pdfViewerController, + textSearchOverlayEntry: _textSearchOverlayEntry!, + onClose: _handleSearchMenuClose, + brightness: model.themeData.brightness, + primaryColor: model.backgroundColor, + ), + ); + }, + )); + } + } + } + + /// Close search menu for web platform. + void _handleSearchMenuClose() { + if (_textSearchOverlayEntry != null) { + _toolbarKey?.currentState?._unFocusToolbarButton('Search'); + _textSearchOverlayKey?.currentState?._pdfTextSearchResult.clear(); + _textSearchOverlayEntry?.remove(); + _textSearchOverlayEntry = null; + } + } + + /// Get choose file list to change pdf for web platform. + Widget _getChooseFileList(String fileName, String path) { + return Container( + height: 32, // height of each file list + width: 202, // width of each file list + child: RawMaterialButton( + onPressed: () { + _closeChooseFileMenu(); + setState(() { + _documentPath = path; + }); + }, + child: Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only(left: 16.0, top: 8.01), + child: Text( + fileName, + style: TextStyle( + color: model.themeData.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.87) + : Color(0x00ffffff).withOpacity(0.87), + fontSize: 14, + fontFamily: 'Roboto', + fontWeight: FontWeight.w400), + ), + ), + ), + ), + ); + } + + /// Shows choose file menu for selecting PDF file to be loaded in SfPdfViewer Widget. + /// This is for web platform. + void _showChooseFileMenu(BuildContext context) { + _toolbarKey?.currentState?._focusToolbarButton('ChooseFile'); + final RenderBox? chooseFileRenderBox = + _toolbarKey?.currentState?._chooseFileKey.currentContext + // ignore: avoid_as + ?.findRenderObject() as RenderBox; + if (chooseFileRenderBox != null) { + final Offset position = chooseFileRenderBox.localToGlobal(Offset.zero); + final OverlayState? overlayState = Overlay.of(context, rootOverlay: true); + _chooseFileOverlayEntry = OverlayEntry( + builder: (context) => Positioned( + top: position.dy + 40.0, // y position of choose file overlay + left: position.dx, // x position of choose file overlay + child: Container( + decoration: BoxDecoration( + color: _contextMenuColor, + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.26), + blurRadius: 8, + offset: Offset(0, 3), + ), + ], + ), + constraints: BoxConstraints.tightFor(width: 202, height: 171), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _getChooseFileList( + 'GIS Succinctly', 'assets/pdf/gis_succinctly.pdf'), + _getChooseFileList( + 'HTTP Succinctly', 'assets/pdf/http_succinctly.pdf'), + _getChooseFileList('JavaScript Succinctly', + 'assets/pdf/javascript_succinctly.pdf'), + _getChooseFileList('Single Page Document', + 'assets/pdf/single_page_document.pdf'), + _getChooseFileList( + 'Corrupted Document', 'assets/pdf/corrupted_document.pdf'), + ], + ), + ), + ), + ); + overlayState?.insert(_chooseFileOverlayEntry!); + } + } + + /// Close choose file menu for web platform. + void _closeChooseFileMenu() { + if (_chooseFileOverlayEntry != null) { + _toolbarKey?.currentState?._unFocusToolbarButton('ChooseFile'); + _chooseFileOverlayEntry?.remove(); + _chooseFileOverlayEntry = null; + } } @override Widget build(BuildContext context) { - return Scaffold( - appBar: _showToolbar - ? AppBar( - flexibleSpace: Toolbar( - showTooltip: true, - controller: _pdfViewerController, - onTap: (Object toolbarItem) { - if (toolbarItem.toString() != 'Bookmarks') { - _checkAndCloseContextMenu(); + if (kIsWeb) { + final bool? isDrawerOpened = model.webOutputContainerState.widget + .webLayoutPageState?.scaffoldKey.currentState?.isEndDrawerOpen; + if (isDrawerOpened != null && isDrawerOpened) { + _closeOverlay(); + } + } + + PreferredSizeWidget appBar = AppBar( + flexibleSpace: RawKeyboardListener( + focusNode: _focusNode, + onKey: (event) { + if (event.isControlPressed && + event.logicalKey == LogicalKeyboardKey.keyF) { + _showTextSearchMenu(); + } + }, + child: Toolbar( + key: _toolbarKey!, + showTooltip: true, + controller: _pdfViewerController, + onTap: (Object toolbarItem) { + if (kIsWeb && !model.isMobileResolution) { + if (toolbarItem == 'Pan mode') { + setState(() { + if (_interactionMode == PdfInteractionMode.selection) { _pdfViewerController.clearSelection(); + _interactionMode = PdfInteractionMode.pan; + } else { + _interactionMode = PdfInteractionMode.selection; } - if (_pdfViewerKey.currentState.isBookmarkViewOpen) { - Navigator.pop(context); - } - if (toolbarItem != 'Jump to the page') { - final currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus) { - currentFocus.requestFocus(FocusNode()); - } - } - if (toolbarItem is Document) { - setState(() { - _documentPath = toolbarItem.path; - }); - } - if (toolbarItem.toString() == 'Bookmarks') { - setState(() { - _showToolbar = false; - }); - _pdfViewerKey.currentState?.openBookmarkView(); - } else if (toolbarItem.toString() == 'Search') { - setState(() { - _showToolbar = false; - _showScrollHead = false; - _ensureHistoryEntry(); - }); - } - }, - ), - automaticallyImplyLeading: false, - backgroundColor: - SfPdfViewerTheme.of(context).bookmarkViewStyle.headerBarColor, - ) - : !_pdfViewerKey.currentState.isBookmarkViewOpen + }); + } + if (toolbarItem == 'Choose file') { + _handleSearchMenuClose(); + if (_chooseFileOverlayEntry == null) { + _showChooseFileMenu(context); + } else { + _closeChooseFileMenu(); + } + } else { + _closeChooseFileMenu(); + } + if (toolbarItem != 'Zoom Percentage') { + _toolbarKey?.currentState?.closeZoomPercentageMenu(); + } + if (toolbarItem.toString() == 'Bookmarks') { + _handleSearchMenuClose(); + _pdfViewerKey?.currentState?.openBookmarkView(); + } + if (toolbarItem.toString() != 'Bookmarks' && + _pdfViewerKey!.currentState!.isBookmarkViewOpen) { + Navigator.pop(context); + } + if (toolbarItem == 'Search') { + _showTextSearchMenu(); + } + } else { + if (_pdfViewerKey!.currentState!.isBookmarkViewOpen) { + Navigator.pop(context); + } + if (toolbarItem is Document) { + setState(() { + _documentPath = toolbarItem.path; + }); + } + if (toolbarItem.toString() == 'Bookmarks') { + setState(() { + _showToolbar = false; + }); + _pdfViewerKey?.currentState?.openBookmarkView(); + } else if (toolbarItem.toString() == 'Search') { + setState(() { + _showToolbar = false; + _showScrollHead = false; + _ensureHistoryEntry(); + }); + } + } + if (toolbarItem.toString() != 'Bookmarks') { + _checkAndCloseContextMenu(); + } + if (toolbarItem != 'Jump to the page') { + final currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + if (!kIsWeb || + (kIsWeb && + model.isMobileResolution != null && + model.isMobileResolution)) { + currentFocus.requestFocus(FocusNode()); + } + } + } + }, + ), + ), + automaticallyImplyLeading: false, + backgroundColor: + SfPdfViewerTheme.of(context)!.bookmarkViewStyle.headerBarColor, + ); + if (kIsWeb && + model.isMobileResolution != null && + !model.isMobileResolution) { + appBar = appBar; + } else { + appBar = _showToolbar + ? appBar + : !_pdfViewerKey!.currentState!.isBookmarkViewOpen ? AppBar( flexibleSpace: SearchToolbar( - key: _textSearchKey, + key: _textSearchKey!, showTooltip: true, controller: _pdfViewerController, - onTap: (Object toolbarItem) { + brightness: model.themeData.brightness, + primaryColor: model.backgroundColor, + onTap: (Object toolbarItem) async { if (toolbarItem.toString() == 'Cancel Search') { setState(() { _showToolbar = true; @@ -238,23 +518,126 @@ class _CustomToolbarPdfViewerState extends SampleViewState { _showToolbar = false; }); } + if (toolbarItem.toString() == 'noResultFound') { + setState(() { + _textSearchKey?.currentState?._showToast = true; + }); + await Future.delayed(Duration(seconds: 1)); + setState(() { + _textSearchKey?.currentState?._showToast = false; + }); + } }, ), automaticallyImplyLeading: false, - backgroundColor: SfPdfViewerTheme.of(context) + backgroundColor: SfPdfViewerTheme.of(context)! .bookmarkViewStyle .headerBarColor, ) : PreferredSize( - child: Container(), preferredSize: Size.zero, - ), + child: Container(), + ); + } + return Scaffold( + appBar: appBar, body: FutureBuilder( future: Future.delayed(Duration(milliseconds: 200)).then((value) { _showPdf = true; }), builder: (context, snapshot) { + final Widget pdfViewer = SfPdfViewer.asset( + _documentPath!, + key: _pdfViewerKey, + controller: _pdfViewerController, + interactionMode: _interactionMode, + canShowScrollHead: (kIsWeb) ? false : _showScrollHead, + onTextSelectionChanged: + (PdfTextSelectionChangedDetails details) async { + if (details.selectedText == null && + _selectionOverlayEntry != null) { + _textSelectionDetails = null; + _checkAndCloseContextMenu(); + } else if (details.selectedText != null && + _selectionOverlayEntry == null) { + _textSelectionDetails = details; + _showContextMenu(context, null); + } + }, + onDocumentLoadFailed: (PdfDocumentLoadFailedDetails details) { + showErrorDialog(context, details.error, details.description); + }, + ); + final Widget copyToast = Visibility( + visible: _showToast, + child: Positioned.fill( + bottom: 25.0, + child: Align( + alignment: Alignment.bottomCenter, + child: Flex( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only( + left: 16, top: 6, right: 16, bottom: 6), + decoration: BoxDecoration( + color: Colors.grey[600], + borderRadius: BorderRadius.all( + Radius.circular(16.0), + ), + ), + child: Text( + 'Copied', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Roboto', + fontSize: 16, + color: Colors.white), + ), + ), + ], + ), + ), + ), + ); if (_showPdf) { + if (kIsWeb && + model.isMobileResolution != null && + !model.isMobileResolution) { + return Stack(children: [ + Listener( + onPointerDown: (details) { + _closeChooseFileMenu(); + _toolbarKey?.currentState?.closeZoomPercentageMenu(); + }, + child: RawKeyboardListener( + focusNode: _focusNode, + onKey: (event) { + if (event.isControlPressed && + event.logicalKey == LogicalKeyboardKey.keyF) { + _showTextSearchMenu(); + } + }, + child: GestureDetector( + onSecondaryTapDown: (details) { + if (_textSelectionDetails != null && + _textSelectionDetails!.globalSelectedRegion! + .contains(details.globalPosition)) { + if (_selectionOverlayEntry != null) { + _checkAndCloseContextMenu(); + _showContextMenu(context, details.globalPosition); + } else if (_selectionOverlayEntry == null) { + _showContextMenu(context, details.globalPosition); + } + } + }, + child: pdfViewer), + ), + ), + copyToast, + ]); + } return SfPdfViewerTheme( data: SfPdfViewerThemeData(brightness: model.themeData.brightness), @@ -266,27 +649,7 @@ class _CustomToolbarPdfViewerState extends SampleViewState { return true; }, child: Stack(children: [ - SfPdfViewer.asset( - _documentPath, - key: _pdfViewerKey, - controller: _pdfViewerController, - onTextSelectionChanged: - (PdfTextSelectionChangedDetails details) async { - if (details.selectedText == null && - _overlayEntry != null) { - _checkAndCloseContextMenu(); - } else if (details.selectedText != null && - _overlayEntry == null) { - _showContextMenu(context, details); - } - }, - onDocumentLoadFailed: - (PdfDocumentLoadFailedDetails details) { - showErrorDialog( - context, details.error, details.description); - }, - canShowScrollHead: _showScrollHead, - ), + pdfViewer, Visibility( visible: _textSearchKey?.currentState?._showToast ?? false, child: Align( @@ -317,58 +680,19 @@ class _CustomToolbarPdfViewerState extends SampleViewState { ), ), ), - Visibility( - visible: _showToast, - child: Positioned.fill( - bottom: 25.0, - child: Align( - alignment: Alignment.bottomCenter, - child: Flex( - direction: Axis.horizontal, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only( - left: 16, top: 6, right: 16, bottom: 6), - decoration: BoxDecoration( - color: Colors.grey[500], - borderRadius: BorderRadius.all( - Radius.circular(16.0), - ), - ), - child: Text( - 'Copied', - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: 'Roboto', - fontSize: 16, - color: Colors.white), - ), - ), - ], - ), - ), - ), - ), + copyToast, ]), ), ); } else { return Container( - color: SfPdfViewerTheme.of(context).backgroundColor, + color: SfPdfViewerTheme.of(context)!.backgroundColor, ); } }, ), ); } - - void _checkAndCloseContextMenu() { - if (_overlayEntry != null) { - _overlayEntry.remove(); - _overlayEntry = null; - } - } } /// Represents PDF document. @@ -389,13 +713,13 @@ typedef PdfDocumentTapCallback = void Function(Document document); /// File Explorer widget class FileExplorer extends StatefulWidget { /// Creates a File Explorer - FileExplorer({Key key, this.brightness, this.onDocumentTap}); + FileExplorer({Key? key, this.brightness, this.onDocumentTap}); /// Brightness theme for the file explorer. - final Brightness brightness; + final Brightness? brightness; /// Called when the document is selected. - final PdfDocumentTapCallback onDocumentTap; + final PdfDocumentTapCallback? onDocumentTap; @override FileExplorerState createState() => FileExplorerState(); @@ -403,9 +727,9 @@ class FileExplorer extends StatefulWidget { /// State for the File Explorer widget class FileExplorerState extends State { - Color _foregroundColor; - Color _backgroundColor; - List _documents = [ + Color? _foregroundColor; + Color? _backgroundColor; + final List _documents = [ Document('GIS Succinctly', 'assets/pdf/gis_succinctly.pdf'), Document('HTTP Succinctly', 'assets/pdf/http_succinctly.pdf'), Document('JavaScript Succinctly', 'assets/pdf/javascript_succinctly.pdf'), @@ -444,7 +768,7 @@ class FileExplorerState extends State { style: TextStyle(color: _foregroundColor, fontSize: 14)), leading: Icon(Icons.picture_as_pdf, color: _foregroundColor), onTap: () { - widget.onDocumentTap(document); + widget.onDocumentTap!(document); }, ); }), @@ -462,17 +786,17 @@ class Toolbar extends StatefulWidget { this.controller, this.onTap, this.showTooltip = true, - Key key, + Key? key, }) : super(key: key); /// Indicates whether tooltip for the toolbar items need to be shown or not.. final bool showTooltip; /// An object that is used to control the [SfPdfViewer]. - final PdfViewerController controller; + final PdfViewerController? controller; /// Called when the toolbar item is selected. - final TapCallback onTap; + final TapCallback? onTap; @override ToolbarState createState() => ToolbarState(); @@ -480,40 +804,58 @@ class Toolbar extends StatefulWidget { /// State for the Toolbar widget class ToolbarState extends State { - SfPdfViewerThemeData _pdfViewerThemeData; - Color _color; - Color _disabledColor; - int _pageCount; + SfPdfViewerThemeData? _pdfViewerThemeData; + Color? _color; + Color? _disabledColor; + Color? _textColor; + Color? _fillColor; + Color? _panFillColor; + Color? _chooseFileFillColor; + Color? _zoomFillColor; + Color? _searchFillColor; + int _pageCount = 0; + double _zoomLevel = 1; + OverlayEntry? _zoomPercentageOverlay; + final GlobalKey _searchKey = GlobalKey(); + final GlobalKey _chooseFileKey = GlobalKey(); + final GlobalKey _zoomPercentageKey = GlobalKey(); + final FocusNode? _focusNode = FocusNode(); /// An object that is used to control the Text Field. - TextEditingController _textEditingController; + TextEditingController? _textEditingController; @override void initState() { widget.controller?.addListener(_pageChanged); _textEditingController = - TextEditingController(text: widget.controller.pageNumber.toString()); - _pageCount = widget.controller.pageCount; + TextEditingController(text: widget.controller!.pageNumber.toString()); + _pageCount = widget.controller!.pageCount; super.initState(); } @override void dispose() { + closeZoomPercentageMenu(); widget.controller?.removeListener(_pageChanged); super.dispose(); } /// Called when the page changes and updates the page number text field. - void _pageChanged({String property}) { + void _pageChanged({String? property}) { + if (kIsWeb && !_isMobile && _zoomLevel != widget.controller!.zoomLevel) { + setState(() { + _zoomLevel = widget.controller!.zoomLevel; + }); + } if (widget.controller?.pageCount != null && - _pageCount != widget.controller.pageCount) { - _pageCount = widget.controller.pageCount; + _pageCount != widget.controller!.pageCount) { + _pageCount = widget.controller!.pageCount; setState(() {}); } if (widget.controller?.pageNumber != null && - _textEditingController.text != - widget.controller.pageNumber.toString()) { - _textEditingController.text = widget.controller.pageNumber.toString(); + _textEditingController!.text != + widget.controller!.pageNumber.toString()) { + _textEditingController!.text = widget.controller!.pageNumber.toString(); setState(() {}); } } @@ -521,49 +863,600 @@ class ToolbarState extends State { @override void didChangeDependencies() { _pdfViewerThemeData = SfPdfViewerTheme.of(context); - _color = _pdfViewerThemeData.brightness == Brightness.light + _color = _pdfViewerThemeData!.brightness == Brightness.light ? Colors.black.withOpacity(0.54) : Colors.white.withOpacity(0.65); - _disabledColor = _pdfViewerThemeData.brightness == Brightness.light + _disabledColor = _pdfViewerThemeData!.brightness == Brightness.light ? Colors.black12 : Colors.white12; + _textColor = _pdfViewerThemeData!.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.87) + : Color(0x00ffffff).withOpacity(0.87); + _fillColor = _pdfViewerThemeData!.brightness == Brightness.light + ? Color(0xFFD2D2D2) + : Color(0xFF525252); super.didChangeDependencies(); } - @override - Widget build(BuildContext context) { - final canJumpToPreviousPage = widget.controller.pageNumber > 1; - final canJumpToNextPage = - widget.controller.pageNumber < widget.controller.pageCount; - return GestureDetector( - onTap: () { - widget.onTap?.call('Toolbar'); - }, - child: Container( - padding: EdgeInsets.only(left: 16.0, right: 16.0), - height: 56, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ToolbarItem( - height: 40, - width: 40, - child: Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.folder_open, - color: _color, - size: 24, + /// Get zoom percentage list for web platform. + Widget _getZoomPercentageList(String percentage, double zoomLevel) { + return Container( + height: 32, // height of each percentage list + width: 120, // width of each percentage list + child: RawMaterialButton( + onPressed: () { + closeZoomPercentageMenu(); + setState(() { + _zoomLevel = zoomLevel; + widget.controller!.zoomLevel = _zoomLevel; + }); + }, + child: Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only(left: 16.0, top: 8.0), + child: Text( + percentage, + style: TextStyle( + color: _textColor, + fontSize: 14, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400), + ), + ), + ), + ), + ); + } + + /// Shows drop down list of zoom levels for web platform. + void _showZoomPercentageMenu(BuildContext context) { + _focusToolbarButton('Zoom'); + final RenderBox? zoomPercentageRenderBox = + // ignore: avoid_as + _zoomPercentageKey.currentContext?.findRenderObject() as RenderBox; + if (zoomPercentageRenderBox != null) { + final Offset position = + zoomPercentageRenderBox.localToGlobal(Offset.zero); + final OverlayState? overlayState = Overlay.of(context, rootOverlay: true); + _zoomPercentageOverlay = OverlayEntry( + builder: (context) => Positioned( + top: position.dy + 40.0, // y position of zoom percentage menu + left: position.dx, // x position of zoom percentage menu + child: Container( + decoration: BoxDecoration( + color: _pdfViewerThemeData!.brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xFF424242), + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.26), + blurRadius: 8, + offset: Offset(0, 3), + ), + ], + ), + constraints: BoxConstraints.tightFor(width: 120, height: 160), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _getZoomPercentageList('100%', 1), + _getZoomPercentageList('125%', 1.25), + _getZoomPercentageList('150%', 1.50), + _getZoomPercentageList('200%', 2), + _getZoomPercentageList('300%', 3), + ], + ), + ), + ), + ); + overlayState?.insert(_zoomPercentageOverlay!); + } + } + + /// Close zoom percentage menu for web platform. + void closeZoomPercentageMenu() { + if (_zoomPercentageOverlay != null) { + _unFocusToolbarButton('Zoom'); + _zoomPercentageOverlay?.remove(); + _zoomPercentageOverlay = null; + } + } + + void _focusToolbarButton(String toolbarItem) { + setState(() { + if (toolbarItem == 'ChooseFile') { + _chooseFileFillColor = _fillColor; + } else if (toolbarItem == 'Zoom') { + _zoomFillColor = _fillColor; + } else if (toolbarItem == 'Search') { + _searchFillColor = _fillColor; + } + }); + } + + void _unFocusToolbarButton(String toolbarItem) { + setState(() { + if (toolbarItem == 'ChooseFile') { + _chooseFileFillColor = null; + } else if (toolbarItem == 'Zoom') { + _zoomFillColor = null; + } else if (toolbarItem == 'Search') { + _searchFillColor = null; + } + }); + } + + /// Get custom toolbar for web platform. + Widget _getToolbarForWeb(bool canJumpToPreviousPage, bool canJumpToNextPage) { + return Container( + height: 56, // height of toolbar for web + width: 1200, // width of toolbar for web + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Tooltip( + message: 'Choose file', + child: Container( + key: _chooseFileKey, + height: 36, // height of choose file menu + width: 50, // width of choose file menu + child: RawMaterialButton( + fillColor: _chooseFileFillColor, + elevation: 0.0, + hoverElevation: 0.0, + onPressed: () { + widget.onTap?.call('Choose file'); + }, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Icon( + Icons.folder_open, + color: _color, + size: 20, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon( + Icons.keyboard_arrow_down, + color: _color, + size: 18, + ), + ), + ], + ), ), - onPressed: () async { - widget.onTap?.call('File Explorer'); - widget.controller.clearSelection(); - await Future.delayed(Duration(milliseconds: 50)); - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => FileExplorer( - brightness: _pdfViewerThemeData.brightness, - onDocumentTap: (document) { + ), + ), + ), + ], + ), + Row( + children: [ + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Container( + height: 20, // height of text field + width: 48, // width of text field + child: paginationTextField(context), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 6.0), + child: Text( + 'of ${widget.controller!.pageCount}', + style: TextStyle( + color: _textColor, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + fontFamily: 'Roboto', + fontSize: 14), + )), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Container( + height: 36, // height of previous page button + width: 36, // width of previous page button + child: Tooltip( + message: 'Previous page', + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: canJumpToPreviousPage + ? () { + widget.onTap?.call('Previous Page'); + widget.controller?.previousPage(); + } + : null, + child: Icon( + Icons.keyboard_arrow_left, + color: + canJumpToPreviousPage ? _color : _disabledColor, + size: 20, + ), + ), + ), + )), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Container( + height: 36, // height of next page button + width: 36, // width of next page button + child: Tooltip( + message: 'Next page', + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: canJumpToNextPage + ? () { + widget.onTap?.call('Next Page'); + widget.controller?.nextPage(); + } + : null, + child: Icon( + Icons.keyboard_arrow_right, + color: canJumpToNextPage ? _color : _disabledColor, + size: 21, + ), + ), + ), + )), + Padding( + padding: const EdgeInsets.only(left: 8), + child: VerticalDivider( + width: 1.0, + // width of vertical divider + thickness: 1.0, + // thickness of vertical divider + indent: 12.0, + // top indent of vertical divider + endIndent: 12.0, + // bottom indent of vertical divider + color: _pdfViewerThemeData!.brightness == Brightness.light + ? Colors.black.withOpacity(0.24) + : Color.fromRGBO(255, 255, 255, 0.26), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Container( + key: _zoomPercentageKey, + height: 36, // height of zoom percentage menu + width: 72, // width of zoom percentage menu + child: RawMaterialButton( + fillColor: _zoomFillColor, + elevation: 0.0, + hoverElevation: 0.0, + onPressed: widget.controller!.pageNumber != 0 + ? () { + widget.onTap?.call('Zoom Percentage'); + if (_zoomPercentageOverlay == null) { + _showZoomPercentageMenu(context); + } else if (_zoomPercentageOverlay != null) { + closeZoomPercentageMenu(); + } + } + : null, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text( + widget.controller!.pageNumber == 0 + ? '0%' + : '${(_zoomLevel * 100).floorToDouble()}%', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + color: _textColor, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Icon( + Icons.keyboard_arrow_down, + color: widget.controller!.pageNumber != 0 + ? _color + : _disabledColor, + size: 18, + ), + ), + ], + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Container( + height: 36, // height of zoom out button + width: 36, // width of zoom out button + child: Tooltip( + message: 'Zoom out', + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: widget.controller!.pageCount != 0 && + _zoomLevel > 1 + ? () { + widget.onTap?.call('Zoom Out'); + setState(() { + if (_zoomLevel > 1.0 && + _zoomLevel <= 1.25) { + _zoomLevel = 1.0; + } else if (_zoomLevel > 1.25 && + _zoomLevel <= 1.50) { + _zoomLevel = 1.25; + } else if (_zoomLevel > 1.50 && + _zoomLevel <= 2.0) { + _zoomLevel = 1.50; + } else { + _zoomLevel = 2.0; + } + widget.controller!.zoomLevel = _zoomLevel; + }); + } + : null, + child: Icon( + Icons.remove_circle_outline, + color: widget.controller!.pageCount != 0 && + _zoomLevel > 1 + ? _color + : _disabledColor, + size: 20, + ), + ), + ), + )), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Container( + height: 36, // height of zoom in button + width: 36, // width of zoom in button + child: Tooltip( + message: 'Zoom in', + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: widget.controller!.pageCount != 0 && + _zoomLevel < 3 + ? () { + widget.onTap?.call('Zoom In'); + setState(() { + if (_zoomLevel >= 1.0 && + _zoomLevel < 1.25) { + _zoomLevel = 1.25; + } else if (_zoomLevel >= 1.25 && + _zoomLevel < 1.50) { + _zoomLevel = 1.50; + } else if (_zoomLevel >= 1.50 && + _zoomLevel < 2.0) { + _zoomLevel = 2.0; + } else { + _zoomLevel = 3.0; + } + + widget.controller!.zoomLevel = _zoomLevel; + }); + } + : null, + child: Icon( + Icons.add_circle_outline, + color: widget.controller!.pageCount != 0 && + _zoomLevel < 3 + ? _color + : _disabledColor, + size: 20, + ), + ), + ), + )), + Padding( + padding: const EdgeInsets.only(left: 8), + child: VerticalDivider( + width: 1.0, + // width of vertical divider + thickness: 1.0, + // thickness of vertical divider + indent: 12.0, + // top indent of vertical divider + endIndent: 12.0, + // bottom indent of vertical divider + color: _pdfViewerThemeData!.brightness == Brightness.light + ? Colors.black.withOpacity(0.24) + : Color.fromRGBO(255, 255, 255, 0.26), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8), + child: Container( + height: 36, // height of pan mode button + width: 36, // width of pan mode button + child: Tooltip( + message: 'Pan mode', + child: RawMaterialButton( + fillColor: _panFillColor, + elevation: 0.0, + hoverElevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: widget.controller!.pageNumber != 0 + ? () { + setState(() { + if (_panFillColor == Color(0xFFD2D2D2) || + _panFillColor == Color(0xFF525252)) { + _panFillColor = null; + } else { + _panFillColor = _fillColor; + } + }); + + widget.onTap?.call('Pan mode'); + } + : null, + child: Icon( + Icons.pan_tool_rounded, + color: widget.controller!.pageCount != 0 + ? _color + : _disabledColor, + size: 20, + ), + ), + ), + ), + ), + ], + ), + Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: Container( + height: 36, // height of bookmark button + width: 36, // width of bookmark button + child: Tooltip( + message: 'Bookmark', + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: widget.controller!.pageNumber != 0 + ? () { + widget.onTap?.call('Bookmarks'); + } + : null, + child: Icon( + Icons.bookmark_border, + color: widget.controller!.pageCount != 0 + ? _color + : _disabledColor, + size: 20, + ), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(right: 8), + child: VerticalDivider( + width: 1.0, + // width of vertical divider + thickness: 1.0, + // thickness of vertical divider + indent: 12.0, + // top indent of vertical divider + endIndent: 12.0, + // bottom indent of vertical divider + color: _pdfViewerThemeData!.brightness == Brightness.light + ? Colors.black.withOpacity(0.24) + : Color.fromRGBO(255, 255, 255, 0.26), + ), + ), + Padding( + padding: const EdgeInsets.only(right: 8), + child: Container( + key: _searchKey, + height: 36, // height of search button + width: 36, // width of search button + child: Tooltip( + message: 'Search', + child: RawMaterialButton( + fillColor: _searchFillColor, + elevation: 0.0, + hoverElevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: widget.controller!.pageNumber != 0 + ? () { + widget.controller!.clearSelection(); + widget.onTap?.call('Search'); + } + : null, + child: Icon( + Icons.search, + color: widget.controller!.pageCount != 0 + ? _color + : _disabledColor, + size: 20, + ), + ), + ), + ), + ), + ], + ), + ], + )); + } + + /// Find whether device is mobile or tablet. + void _findDevice(BuildContext context) { + /// Standard diagonal offset of tablet. + const double _kPdfStandardDiagonalOffset = 1100.0; + final Size size = MediaQuery.of(context).size; + final double diagonal = + sqrt((size.width * size.width) + (size.height * size.height)); + _isMobile = diagonal < _kPdfStandardDiagonalOffset; + } + + /// If true,MobileBrowserView is enabled.Default value is false. + bool _isMobile = false; + + @override + Widget build(BuildContext context) { + final canJumpToPreviousPage = widget.controller!.pageNumber > 1; + final canJumpToNextPage = + widget.controller!.pageNumber < widget.controller!.pageCount; + _findDevice(context); + if (kIsWeb && !_isMobile) { + return _getToolbarForWeb(canJumpToPreviousPage, canJumpToNextPage); + } + return GestureDetector( + onTap: () { + widget.onTap?.call('Toolbar'); + }, + child: Container( + padding: EdgeInsets.only(left: 16.0, right: 16.0), + height: 56, // height of toolbar for mobile platform + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ToolbarItem( + height: 40, // height of file explorer button + width: 40, // width of file explorer button + child: Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.folder_open, + color: _color, + size: 24, + ), + onPressed: () async { + widget.onTap?.call('File Explorer'); + widget.controller!.clearSelection(); + await Future.delayed(Duration(milliseconds: 50)); + await Navigator.of(context).push(MaterialPageRoute( + builder: (context) => FileExplorer( + brightness: _pdfViewerThemeData!.brightness, + onDocumentTap: (document) { widget.onTap?.call(document); Navigator.of(context, rootNavigator: true) .pop(context); @@ -575,8 +1468,8 @@ class ToolbarState extends State { ), Row(children: [ ToolbarItem( - height: 25, - width: 75, + height: 25, // height of pagination fields + width: 75, // width of pagination fields child: Row(children: [ Flexible( child: paginationTextField(context), @@ -595,8 +1488,8 @@ class ToolbarState extends State { Padding( padding: const EdgeInsets.only(left: 24), child: ToolbarItem( - height: 40, - width: 40, + height: 40, // height of previous page button + width: 40, // width of previous page button child: Material( color: Colors.transparent, child: IconButton( @@ -620,8 +1513,8 @@ class ToolbarState extends State { Padding( padding: const EdgeInsets.only(left: 24), child: ToolbarItem( - height: 40, - width: 40, + height: 40, // height of next page button + width: 40, // width of next page button child: Material( color: Colors.transparent, child: IconButton( @@ -641,102 +1534,125 @@ class ToolbarState extends State { )), )) ]), - Row(children: [ - ToolbarItem( - height: 40, - width: 40, - child: Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.bookmark, - color: widget.controller.pageNumber == 0 - ? Colors.black12 - : _color, - size: 24, - ), - onPressed: widget.controller.pageNumber == 0 - ? null - : () { - _textEditingController.selection = - TextSelection( - baseOffset: -1, extentOffset: -1); - widget.onTap?.call('Bookmarks'); - }, - tooltip: widget.showTooltip ? 'Bookmarks' : null, + ToolbarItem( + height: 40, // height of bookmark button + width: 40, // width of bookmark button + child: Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.bookmark, + color: widget.controller!.pageNumber == 0 + ? Colors.black12 + : _color, + size: 24, ), - )), - ToolbarItem( - height: 40, - width: 40, - child: Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.search, - color: widget.controller.pageNumber == 0 - ? Colors.black12 - : _color, - size: 24, - ), - onPressed: widget.controller.pageNumber == 0 - ? null - : () { - widget.controller.clearSelection(); - widget.onTap?.call('Search'); - }, - tooltip: widget.showTooltip ? 'Search' : null, + onPressed: widget.controller!.pageNumber == 0 + ? null + : () { + _textEditingController!.selection = TextSelection( + baseOffset: -1, extentOffset: -1); + widget.onTap?.call('Bookmarks'); + }, + tooltip: widget.showTooltip ? 'Bookmarks' : null, + ), + )), + ToolbarItem( + height: 40, // height of search button + width: 40, // width of search button + child: Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.search, + color: widget.controller!.pageNumber == 0 + ? Colors.black12 + : _color, + size: 24, ), - )) - ]), + onPressed: widget.controller!.pageNumber == 0 + ? null + : () { + widget.controller!.clearSelection(); + widget.onTap?.call('Search'); + }, + tooltip: widget.showTooltip ? 'Search' : null, + ), + )) ], )), ); } - /// Pagination text field widget + /// Pagination text field widget. Widget paginationTextField(BuildContext context) { return TextField( - style: TextStyle(color: _color), + autofocus: false, + style: (kIsWeb && !_isMobile) + ? TextStyle( + color: _textColor, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + fontFamily: 'Roboto', + fontSize: 14) + : TextStyle(color: _color), enableInteractiveSelection: false, keyboardType: TextInputType.number, controller: _textEditingController, textAlign: TextAlign.center, - maxLength: 3, + maxLength: (kIsWeb && !_isMobile) ? 4 : 3, + focusNode: _focusNode, maxLines: 1, decoration: InputDecoration( counterText: '', + contentPadding: (kIsWeb && !_isMobile) + ? EdgeInsets.only(bottom: 22) + : (kIsWeb) + ? (EdgeInsets.only(bottom: 20)) + : null, border: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.grey), + borderSide: BorderSide(width: 1.0), + ), + focusedBorder: UnderlineInputBorder( + borderSide: + BorderSide(color: Theme.of(context).primaryColor, width: 2.0), ), ), - enabled: widget.controller.pageCount == 0 ? false : true, - onTap: widget.controller.pageCount == 0 + enabled: widget.controller!.pageCount == 0 ? false : true, + onTap: widget.controller!.pageCount == 0 ? null : () { - _textEditingController.selection = TextSelection( + _textEditingController!.selection = TextSelection( baseOffset: 0, - extentOffset: _textEditingController.value.text.length); + extentOffset: _textEditingController!.value.text.length); + _focusNode?.requestFocus(); widget.onTap?.call('Jump to the page'); }, + onSubmitted: (String text) { + _focusNode?.unfocus(); + }, onEditingComplete: () { - final str = _textEditingController.text; - if (str != widget.controller.pageNumber.toString()) { + final str = _textEditingController!.text; + if (str != widget.controller!.pageNumber.toString()) { try { final int index = int.parse(str); - if (index > 0 && index <= widget.controller.pageCount) { + if (index > 0 && index <= widget.controller!.pageCount) { widget.controller?.jumpToPage(index); FocusScope.of(context).requestFocus(FocusNode()); widget.onTap?.call('Navigated'); } else { - _textEditingController.text = - widget.controller.pageNumber.toString(); - showErrorDialog( - context, 'Error', 'Please enter a valid page number.'); + _textEditingController!.text = + widget.controller!.pageNumber.toString(); + if (!kIsWeb || (kIsWeb && _isMobile)) { + showErrorDialog( + context, 'Error', 'Please enter a valid page number.'); + } } } catch (exception) { - return showErrorDialog( - context, 'Error', 'Please enter a valid page number.'); + if (!kIsWeb || (kIsWeb && _isMobile)) { + return showErrorDialog( + context, 'Error', 'Please enter a valid page number.'); + } } } widget.onTap?.call('Navigated'); @@ -755,17 +1671,25 @@ class SearchToolbar extends StatefulWidget { this.controller, this.onTap, this.showTooltip = true, - Key key, + this.brightness, + this.primaryColor, + Key? key, }) : super(key: key); /// Indicates whether tooltip for the search toolbar items need to be shown or not. final bool showTooltip; /// An object that is used to control the [SfPdfViewer]. - final PdfViewerController controller; + final PdfViewerController? controller; /// Called when the search toolbar item is selected. - final SearchTapCallback onTap; + final SearchTapCallback? onTap; + + /// Brightness theme for text search overlay. + final Brightness? brightness; + + /// Palette color for text search overlay. + final Color? primaryColor; @override SearchToolbarState createState() => SearchToolbarState(); @@ -773,107 +1697,151 @@ class SearchToolbar extends StatefulWidget { /// State for the SearchToolbar widget class SearchToolbarState extends State { - SfPdfViewerThemeData _pdfViewerThemeData; - Color _color; + int _searchTextLength = 0; + Color? _color; + Color? _textColor; + + /// Indicates whether search toolbar items need to be shown or not. bool _showItem = false; + + /// Indicates whether search toast need to be shown or not. bool _showToast = false; - int _totalTextValue = 0; - /// An object that is used to control the Text Field. + ///An object that is used to retrieve the current value of the TextField. final TextEditingController _editingController = TextEditingController(); - /// An object that is used retrieve the text search result. + /// An object that is used to retrieve the text search result. PdfTextSearchResult _pdfTextSearchResult = PdfTextSearchResult(); - /// Define the focus node. To manage the lifecycle, create the FocusNode in - /// the initState method, and clean it up in the dispose method. - - FocusNode myFocusNode; + ///An object that is used to obtain keyboard focus and to handle keyboard events. + FocusNode? focusNode; @override void initState() { super.initState(); - myFocusNode = FocusNode(); + focusNode = FocusNode(); + focusNode?.requestFocus(); } @override void dispose() { - // Clean up the focus node when the Form is disposed. - myFocusNode?.dispose(); + focusNode?.dispose(); super.dispose(); } - ///clear the text search result + ///Clear the text search result void clearSearch() { _pdfTextSearchResult.clear(); } @override void didChangeDependencies() { - _pdfViewerThemeData = SfPdfViewerTheme.of(context); - _color = _pdfViewerThemeData.brightness == Brightness.light - ? Colors.black.withOpacity(0.54) - : Colors.white.withOpacity(0.65); + _color = widget.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.87) + : Color(0x00ffffff).withOpacity(0.87); + _textColor = widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54).withOpacity(0.87) + : Color(0x00ffffff).withOpacity(0.54); super.didChangeDependencies(); } - ///Display the Alert Dialog to search from the beginning - void _showDialog(BuildContext context) { + /// Display the Alert Dialog to search from the beginning + void _showSearchAlertDialog(BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( - title: Text('Search Result'), - content: Text( - 'No more occurrences found. Would you like to continue to search from the beginning?'), + insetPadding: EdgeInsets.zero, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Search Result', + style: TextStyle( + color: _color, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w500, + fontSize: 20, + decoration: TextDecoration.none), + ), + Container( + height: 36, // height of close search menu button + width: 36, // width of close search menu button + child: RawMaterialButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Icon( + Icons.clear, + color: widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.65), + size: 20, + ), + ), + ), + ], + ), + backgroundColor: widget.brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xFF424242), + content: Container( + width: 328, + child: Text( + 'No more occurrences found. Would you like to continue to search from the beginning?', + style: TextStyle( + color: _color, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + fontSize: 15, + decoration: TextDecoration.none), + )), actions: [ - FlatButton( - child: Text('YES'), - onPressed: () { - _pdfTextSearchResult?.nextInstance(); - Navigator.of(context).pop(); - }, - ), - FlatButton( - child: Text('NO'), + TextButton( onPressed: () { - _pdfTextSearchResult?.clear(); + _pdfTextSearchResult.clear(); _editingController.clear(); + _showItem = false; + focusNode?.requestFocus(); Navigator.of(context).pop(); }, + style: TextButton.styleFrom( + primary: Colors.transparent, + ), + child: Text( + 'NO', + style: TextStyle( + color: widget.primaryColor, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + fontSize: 14, + decoration: TextDecoration.none), + ), ), - ], - ); - }, - ); - } - - ///Display the Alert Dialog to search from the ending - void _showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text('Search Result'), - content: Text( - 'No more occurrences found. Would you like to continue to search from the ending?'), - actions: [ - FlatButton( - child: Text('YES'), - onPressed: () { - _pdfTextSearchResult?.previousInstance(); - Navigator.of(context).pop(); - }, - ), - FlatButton( - child: Text('NO'), + TextButton( onPressed: () { - _pdfTextSearchResult?.clear(); - _editingController.clear(); + _pdfTextSearchResult.nextInstance(); Navigator.of(context).pop(); }, + style: TextButton.styleFrom( + primary: Colors.transparent, + ), + child: Text( + 'YES', + style: TextStyle( + color: widget.primaryColor, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + fontSize: 14, + decoration: TextDecoration.none), + ), ), ], + actionsPadding: EdgeInsets.only(bottom: 10), ); }, ); @@ -882,165 +1850,179 @@ class SearchToolbarState extends State { @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.only(left: 16.0, right: 16.0), - height: 56, + height: 56, // height of search toolbar child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SearchToolbarItem( - height: 40, - width: 40, + Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.arrow_back, + color: widget.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.54) + : Color(0x00ffffff).withOpacity(0.54), + size: 24, + ), + onPressed: () { + widget.onTap?.call('Cancel Search'); + _editingController.clear(); + _pdfTextSearchResult.clear(); + }, + ), + ), + Flexible( + child: TextFormField( + style: TextStyle( + color: _color, + fontWeight: FontWeight.normal, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontSize: 16), + enableInteractiveSelection: false, + focusNode: focusNode, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.search, + controller: _editingController, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Find...', + hintStyle: TextStyle( + color: widget.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.34) + : Color(0x00ffffff).withOpacity(0.54), + fontWeight: FontWeight.normal, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontSize: 16), + ), + onChanged: (text) { + if (_searchTextLength < _editingController.value.text.length) { + setState(() {}); + _searchTextLength = _editingController.value.text.length; + } + if (_editingController.value.text.length < _searchTextLength) { + setState(() { + _showItem = false; + }); + } + }, + onFieldSubmitted: (String value) async { + _pdfTextSearchResult = await widget.controller! + .searchText(_editingController.text); + if (_pdfTextSearchResult.totalInstanceCount == 0) { + widget.onTap?.call('noResultFound'); + } else { + _showItem = true; + } + }, + ), + ), + Visibility( + visible: _editingController.text.isNotEmpty, child: Material( color: Colors.transparent, child: IconButton( icon: Icon( - Icons.arrow_back, - color: _color, + Icons.clear, size: 24, + color: widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.65), ), onPressed: () { - widget.onTap?.call('Cancel Search'); - _editingController.clear(); - _pdfTextSearchResult?.clear(); + setState(() { + _editingController.clear(); + _pdfTextSearchResult.clear(); + widget.controller!.clearSelection(); + _showItem = false; + focusNode?.requestFocus(); + }); + widget.onTap?.call('Clear Text'); }, + tooltip: widget.showTooltip ? 'Clear Text' : null, ), ), ), - SearchToolbarItem( - child: Flexible( - child: TextFormField( - style: TextStyle(color: _color), - enableInteractiveSelection: false, - autofocus: true, - focusNode: myFocusNode, - keyboardType: TextInputType.text, - textInputAction: TextInputAction.search, - controller: _editingController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'Find...', + Visibility( + visible: _showItem, + child: Row( + children: [ + Text( + '${_pdfTextSearchResult.currentInstanceIndex}', + style: TextStyle( + color: _textColor, + fontWeight: FontWeight.normal, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontSize: 12), ), - onChanged: (text) { - if (_totalTextValue < _editingController.value.text.length) { - _totalTextValue = _editingController.value.text.length; - } - if (_editingController.value.text.length < _totalTextValue) { - setState(() { - _showItem = false; - }); - } - }, - onFieldSubmitted: (String value) async { - _pdfTextSearchResult = await widget.controller - .searchText(_editingController.text); - if (_pdfTextSearchResult.totalInstanceCount == 0) { - _showToast = true; - await Future.delayed(Duration(seconds: 2), () { + Text( + ' of ', + style: TextStyle( + color: _textColor, + fontWeight: FontWeight.normal, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontSize: 12), + ), + Text( + '${_pdfTextSearchResult.totalInstanceCount}', + style: TextStyle( + color: _textColor, + fontWeight: FontWeight.normal, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontSize: 12), + ), + Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.navigate_before, + color: widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.65), + size: 24, + ), + onPressed: () { setState(() { - _showToast = false; + _pdfTextSearchResult.previousInstance(); }); - }); - } else { - _showItem = true; - } - }, - ), - ), - ), - SearchToolbarItem( - child: Visibility( - visible: _editingController.text.isNotEmpty, - child: Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.clear, - color: _color, - size: 24, + widget.onTap?.call('Previous Instance'); + }, + tooltip: widget.showTooltip ? 'Previous' : null, ), - onPressed: () { - setState(() { - _editingController.clear(); - _pdfTextSearchResult?.clear(); - widget.controller.clearSelection(); - _showItem = false; - myFocusNode.requestFocus(); - }); - widget.onTap?.call('Clear Text'); - }, - tooltip: widget.showTooltip ? 'Clear Text' : null, ), - ), - ), - ), - SearchToolbarItem( - child: Visibility( - visible: _showItem, - child: Row( - children: [ - Text( - '${_pdfTextSearchResult?.currentInstanceIndex}', - style: TextStyle(color: _color, fontSize: 16), - ), - Text( - ' of ', - style: TextStyle(color: _color, fontSize: 16), - ), - Text( - '${_pdfTextSearchResult?.totalInstanceCount}', - style: TextStyle(color: _color, fontSize: 16), - ), - Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.navigate_before, - color: _color, - size: 24, - ), - onPressed: () { - setState(() { - if (_pdfTextSearchResult?.totalInstanceCount != 0 && - _pdfTextSearchResult.currentInstanceIndex <= 1) { - _showAlertDialog(context); - } else { - _pdfTextSearchResult?.previousInstance(); - } - }); - widget.onTap?.call('Previous Instance'); - }, - tooltip: widget.showTooltip ? 'Previous' : null, - ), - ), - Material( - color: Colors.transparent, - child: IconButton( - icon: Icon( - Icons.navigate_next, - color: _color, - size: 24, - ), - onPressed: () { - setState(() { - if (_pdfTextSearchResult?.currentInstanceIndex == - _pdfTextSearchResult?.totalInstanceCount && - _pdfTextSearchResult?.currentInstanceIndex != 0 && - _pdfTextSearchResult?.totalInstanceCount != 0) { - _showDialog(context); - } else { - widget.controller.clearSelection(); - _pdfTextSearchResult?.nextInstance(); - } - }); - widget.onTap?.call('Next Instance'); - }, - tooltip: widget.showTooltip ? 'Next' : null, + Material( + color: Colors.transparent, + child: IconButton( + icon: Icon( + Icons.navigate_next, + size: 24, + color: widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.65), ), + onPressed: () { + setState(() { + if (_pdfTextSearchResult.currentInstanceIndex == + _pdfTextSearchResult.totalInstanceCount && + _pdfTextSearchResult.currentInstanceIndex != 0 && + _pdfTextSearchResult.totalInstanceCount != 0) { + _showSearchAlertDialog(context); + } else { + widget.controller!.clearSelection(); + _pdfTextSearchResult.nextInstance(); + } + }); + widget.onTap?.call('Next Instance'); + }, + tooltip: widget.showTooltip ? 'Next' : null, ), - ], - ), + ), + ], ), - ) + ), ], ), ); @@ -1057,41 +2039,13 @@ class ToolbarItem extends StatelessWidget { }); /// Height of the toolbar item - final double height; + final double? height; /// Width of the toolbar item - final double width; + final double? width; /// Child widget of the toolbar item - final Widget child; - - @override - Widget build(BuildContext context) { - return Container( - height: height, - width: width, - child: child, - ); - } -} - -/// SearchToolbar item widget -class SearchToolbarItem extends StatelessWidget { - ///Creates a search toolbar item - SearchToolbarItem({ - this.height, - this.width, - @required this.child, - }); - - /// Height of the search toolbar item - final double height; - - /// Width of the search toolbar item - final double width; - - /// Child widget of the search toolbar item - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { @@ -1109,17 +2063,531 @@ void showErrorDialog(BuildContext context, String error, String description) { context: context, builder: (BuildContext context) { return AlertDialog( - title: Text(error), - content: Text(description), + insetPadding: EdgeInsets.all(0), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(error), + Container( + height: 36, // height of close search menu button + width: 36, // width of close search menu button + child: RawMaterialButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Icon( + Icons.clear, + size: 20, + ), + ), + ), + ], + ), + content: Container(width: 328.0, child: Text(description)), actions: [ - FlatButton( - child: Text('OK'), + TextButton( onPressed: () { Navigator.of(context, rootNavigator: true).pop(); }, + child: Text('OK'), ) ], + actionsPadding: EdgeInsets.only(bottom: 10), ); }, ); } + +/// TextSearchOverlay widget for search operation.This is for web platform. +class TextSearchOverlay extends StatefulWidget { + /// Constructor for TextSearchOverlay. + TextSearchOverlay( + {Key? key, + this.controller, + this.textSearchOverlayEntry, + this.onClose, + this.brightness, + this.primaryColor}) + : super(key: key); + + /// An object that is used to control the [SfPdfViewer]. + final PdfViewerController? controller; + + /// An object that is used to insert text search overlay. + final OverlayEntry? textSearchOverlayEntry; + + /// Callback which triggers when closing the search overlay. + final VoidCallback? onClose; + + /// Brightness theme for text search overlay. + final Brightness? brightness; + + /// Palette color for text search overlay. + final Color? primaryColor; + + @override + _TextSearchOverlayState createState() => _TextSearchOverlayState(); +} + +/// State class of TextSearchOverlay widget.This is for web platform. +class _TextSearchOverlayState extends State { + Color? _color; + + /// Indicates whether search toolbar items need to be shown or not. + bool showItem = false; + + /// Indicates whether enter key is pressed or not. + bool isEnterKeyPressed = false; + + /// An object that is used to retrieve the text search result. + PdfTextSearchResult _pdfTextSearchResult = PdfTextSearchResult(); + + /// An object that is used to retrieve the current value of the TextField. + final TextEditingController _editingController = TextEditingController(); + + ///Indicates whether text search option is match case + bool? isMatchCaseChecked = false; + + ///Indicates whether text search option is whole word + bool? isWholeWordChecked = false; + + /// Focus node for search overlay entry. + final FocusNode? _focusNode = FocusNode(); + + @override + void initState() { + _focusNode?.requestFocus(); + super.initState(); + } + + @override + void dispose() { + _focusNode?.dispose(); + super.dispose(); + } + + @override + void didChangeDependencies() { + _color = widget.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.87) + : Color(0x00ffffff).withOpacity(0.87); + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return Material( + child: Container( + height: 146, // height of search menu + width: 412, // width of search menu + decoration: BoxDecoration( + color: widget.brightness == Brightness.light + ? Color(0xFFFFFFFF) + : Color(0xFF424242), + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.26), + blurRadius: 8, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 16, // x position of search word in search menu + top: 15, // y position of search word in search menu + ), + child: Container( + height: 23, // height of search word in search menu + width: 66, // width of search word in search menu + child: Text( + 'Search', + style: TextStyle( + color: _color, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w500, + fontSize: 20, + letterSpacing: -0.2, + decoration: TextDecoration.none), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + right: 8, // x position of clear button in search menu + top: 8, // y position of clear button in search menu + ), + child: Container( + height: 36, // height of close search menu button + width: 36, // width of close search menu button + child: RawMaterialButton( + onPressed: () { + _closeSearchMenu(); + }, + child: Icon( + Icons.clear, + color: widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.65), + size: 20, + ), + ), + ), + ), + ], + ), + Row( + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.only( + left: 16, // y position of text field in search menu + ), + child: TextFormField( + focusNode: _focusNode, + controller: _editingController, + style: TextStyle( + fontSize: 15, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + color: _color, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.only(top: 20), + border: UnderlineInputBorder( + borderSide: BorderSide(width: 1.0), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: widget.primaryColor!, width: 2.0), + ), + hintText: 'Find in document', + hintStyle: TextStyle( + color: widget.brightness == Brightness.light + ? Color(0x00000000).withOpacity(0.34) + : Color(0xFF949494), + fontSize: 15, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400, + decoration: TextDecoration.none), + suffixIcon: !showItem + ? Padding( + padding: const EdgeInsets.only( + left: 8, right: 8, bottom: 6, top: 15), + child: Container( + height: + 14.57, // height of search button in search menu + width: + 14.57, // width of search button in search menu + child: RawMaterialButton( + onPressed: () { + setState(() { + _handleSearchResult(); + }); + }, + child: Icon( + Icons.search, + color: + widget.brightness == Brightness.light + ? Colors.black.withOpacity(0.54) + : Colors.white.withOpacity(0.65), + size: 18, + ), + ), + ), + ) + : Padding( + padding: const EdgeInsets.only( + left: 8, right: 8, bottom: 6, top: 15), + child: Container( + height: + 14.57, // height of clear search button + width: 14.57, // width of clear search button + child: RawMaterialButton( + onPressed: () { + setState(() { + _pdfTextSearchResult.clear(); + _editingController.clear(); + _focusNode?.requestFocus(); + showItem = false; + }); + }, + child: Icon( + Icons.clear, + color: + widget.brightness == Brightness.light + ? Colors.black.withOpacity(0.54) + : Colors.white.withOpacity(0.65), + size: 18, + ), + ), + ), + ), + ), + onChanged: (String value) { + isEnterKeyPressed = false; + }, + onFieldSubmitted: (String value) { + setState(() { + _handleSearchResult(); + }); + }, + ), + ), + ), + Visibility( + visible: showItem, + child: Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( + children: [ + Text( + _pdfTextSearchResult.currentInstanceIndex.toString(), + style: TextStyle( + color: _color, + fontSize: 15, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + decoration: TextDecoration.none), + ), + Text( + '/', + style: TextStyle( + color: _color, + fontSize: 15, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + decoration: TextDecoration.none), + ), + Text( + _pdfTextSearchResult.totalInstanceCount.toString(), + style: TextStyle( + color: _color, + fontSize: 15, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + decoration: TextDecoration.none), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 10), + child: Container( + height: 24, // height of vertical divider + child: VerticalDivider( + width: 24.0, // width of vertical divider + thickness: 1.0, // thickness of vertical divider + color: widget.brightness == Brightness.light + ? Colors.black.withOpacity(0.24) + : Color.fromRGBO(255, 255, 255, 0.26), + ), + )), + Padding( + padding: const EdgeInsets.only(top: 10), + child: Container( + height: 36, // height of previous instance button + width: 36, // width of previous instance button + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: _pdfTextSearchResult.hasResult + ? () { + setState(() { + _pdfTextSearchResult.previousInstance(); + }); + } + : null, + child: Icon( + Icons.keyboard_arrow_left, + color: widget.brightness == Brightness.light + ? _pdfTextSearchResult.hasResult + ? Color.fromRGBO(0, 0, 0, 0.54) + : Colors.black.withOpacity(0.28) + : _pdfTextSearchResult.hasResult + ? Color.fromRGBO(255, 255, 255, 0.65) + : Colors.white12, + size: 20, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + top: 10, + right: 8, + ), + child: Container( + height: 36, // height of next instance button + width: 36, // width of next instance button + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(2.0), + ), + onPressed: _pdfTextSearchResult.hasResult + ? () { + setState(() { + _pdfTextSearchResult.nextInstance(); + }); + } + : null, + child: Icon( + Icons.keyboard_arrow_right, + color: widget.brightness == Brightness.light + ? _pdfTextSearchResult.hasResult + ? Color.fromRGBO(0, 0, 0, 0.54) + : Colors.black.withOpacity(0.28) + : _pdfTextSearchResult.hasResult + ? Color.fromRGBO(255, 255, 255, 0.65) + : Colors.white12, + size: 20, + ), + ), + ), + ), + ], + ), + Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: Container( + height: 18, // height of match case checkbox + width: 18, // width of match case checkbox + child: Theme( + data: ThemeData( + unselectedWidgetColor: + widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.54), + ), + child: Checkbox( + value: isMatchCaseChecked, + activeColor: widget.primaryColor, + checkColor: Colors.white, + onChanged: (value) { + setState(() { + isEnterKeyPressed = false; + isMatchCaseChecked = value; + }); + }, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8, top: 16, bottom: 16), + child: Text( + 'Match case', + style: TextStyle( + color: _color, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + fontSize: 15, + decoration: TextDecoration.none), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: Container( + height: 18, // height of whole word checkbox + width: 18, // height of whole word checkbox + child: Theme( + data: ThemeData( + unselectedWidgetColor: + widget.brightness == Brightness.light + ? Color.fromRGBO(0, 0, 0, 0.54) + : Color.fromRGBO(255, 255, 255, 0.54), + ), + child: Checkbox( + activeColor: widget.primaryColor, + checkColor: Colors.white, + value: isWholeWordChecked, + onChanged: (value) { + setState(() { + isEnterKeyPressed = false; + isWholeWordChecked = value; + }); + }, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8, top: 16, bottom: 16), + child: Text( + 'Whole word', + style: TextStyle( + color: _color, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.normal, + fontSize: 15, + decoration: TextDecoration.none), + ), + ), + ], + ), + ], + ), + ), + ); + } + + /// Close search menu for web platform. + void _closeSearchMenu() { + setState(() { + widget.onClose?.call(); + _pdfTextSearchResult.clear(); + }); + } + + ///Handle text search result + void _handleSearchResult() { + if (!isEnterKeyPressed) { + _getSearchResult(); + showItem = true; + } else { + _pdfTextSearchResult.nextInstance(); + } + _focusNode?.requestFocus(); + } + + ///Get the text search result + void _getSearchResult() async { + isEnterKeyPressed = true; + if (isMatchCaseChecked! && isWholeWordChecked!) { + _pdfTextSearchResult = await widget.controller!.searchText( + _editingController.text, + searchOption: TextSearchOption.both); + } else if (isMatchCaseChecked!) { + _pdfTextSearchResult = await widget.controller!.searchText( + _editingController.text, + searchOption: TextSearchOption.caseSensitive, + ); + } else if (isWholeWordChecked!) { + _pdfTextSearchResult = await widget.controller!.searchText( + _editingController.text, + searchOption: TextSearchOption.wholeWords, + ); + } else { + _pdfTextSearchResult = await widget.controller!.searchText( + _editingController.text, + ); + } + } +} diff --git a/lib/samples/pdf_viewer/pdf_viewer_getting_started.dart b/lib/samples/pdf_viewer/pdf_viewer_getting_started.dart index e83ea962..7df4c3d6 100644 --- a/lib/samples/pdf_viewer/pdf_viewer_getting_started.dart +++ b/lib/samples/pdf_viewer/pdf_viewer_getting_started.dart @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -///PDF Viewer import -import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart'; - /// Core theme import import 'package:syncfusion_flutter_core/theme.dart'; +///PDF Viewer import +import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart'; + ///Local import import '../../model/sample_view.dart'; @@ -22,22 +22,31 @@ class GettingStartedPdfViewer extends SampleView { } class _GettingStartedPdfViewerState extends SampleViewState { - bool _showPdf; - bool _showToast; - OverlayEntry _overlayEntry; - Color _contextMenuColor; - Color _copyColor; - double _contextMenuWidth; - double _contextMenuHeight; + late bool _canShowPdf; + late bool _canShowToast; + OverlayEntry? _overlayEntry; + late Color _contextMenuColor; + late Color _copyColor; + late double _contextMenuWidth; + late double _contextMenuHeight; + final double _kWebContextMenuHeight = 32; + final double _kMobileContextMenuHeight = 48; + final double _kContextMenuBottom = 55; final PdfViewerController _pdfViewerController = PdfViewerController(); @override void initState() { - _showPdf = false; - _showToast = false; + Future.delayed(Duration(milliseconds: 600), () { + final currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.requestFocus(FocusNode()); + } + }); + super.initState(); + _canShowPdf = false; + _canShowToast = false; _contextMenuHeight = 48; _contextMenuWidth = 100; - super.initState(); } @override @@ -55,28 +64,37 @@ class _GettingStartedPdfViewerState extends SampleViewState { /// Show Context menu for Text Selection. void _showContextMenu( BuildContext context, PdfTextSelectionChangedDetails details) { + _contextMenuHeight = (model.isWebFullView && !model.isMobileResolution) + ? _kWebContextMenuHeight + : _kMobileContextMenuHeight; final RenderBox renderBoxContainer = - context.findRenderObject() as RenderBox; + // ignore: avoid_as + context.findRenderObject()! as RenderBox; final Offset containerOffset = renderBoxContainer.localToGlobal( renderBoxContainer.paintBounds.topLeft, ); - if (containerOffset.dy < details.globalSelectedRegion.topLeft.dy - 55 || + if (containerOffset.dy < + details.globalSelectedRegion!.topLeft.dy - _kContextMenuBottom || (containerOffset.dy < - details.globalSelectedRegion.center.dy - + details.globalSelectedRegion!.center.dy - (_contextMenuHeight / 2) && - details.globalSelectedRegion.height > _contextMenuWidth)) { - double top = details.globalSelectedRegion.height > _contextMenuWidth - ? details.globalSelectedRegion.center.dy - (_contextMenuHeight / 2) - : details.globalSelectedRegion.topLeft.dy - 55; - double left = details.globalSelectedRegion.height > _contextMenuWidth - ? details.globalSelectedRegion.center.dx - (_contextMenuWidth / 2) - : details.globalSelectedRegion.bottomLeft.dx; - if ((details.globalSelectedRegion.top) > + details.globalSelectedRegion!.height > _contextMenuWidth)) { + double top = 0.0; + double left = 0.0; + if ((details.globalSelectedRegion!.top) > MediaQuery.of(context).size.height / 2) { - top = details.globalSelectedRegion.topLeft.dy - 55; - left = details.globalSelectedRegion.bottomLeft.dx; + top = details.globalSelectedRegion!.topLeft.dy - _kContextMenuBottom; + left = details.globalSelectedRegion!.bottomLeft.dx; + } else { + top = details.globalSelectedRegion!.height > _contextMenuWidth + ? details.globalSelectedRegion!.center.dy - (_contextMenuHeight / 2) + : details.globalSelectedRegion!.topLeft.dy - _kContextMenuBottom; + left = details.globalSelectedRegion!.height > _contextMenuWidth + ? details.globalSelectedRegion!.center.dx - (_contextMenuWidth / 2) + : details.globalSelectedRegion!.bottomLeft.dx; } - final OverlayState _overlayState = Overlay.of(context); + final OverlayState? _overlayState = + Overlay.of(context, rootOverlay: true); _overlayEntry = OverlayEntry( builder: (context) => Positioned( top: top, @@ -104,41 +122,87 @@ class _GettingStartedPdfViewerState extends SampleViewState { ), constraints: BoxConstraints.tightFor( width: _contextMenuWidth, height: _contextMenuHeight), - child: FlatButton( - child: Text( - 'Copy', - style: TextStyle(fontSize: 17, color: _copyColor), - ), + child: TextButton( onPressed: () async { _checkAndCloseContextMenu(); _pdfViewerController.clearSelection(); await Clipboard.setData( ClipboardData(text: details.selectedText)); setState(() { - _showToast = true; + _canShowToast = true; }); await Future.delayed(Duration(seconds: 1)); setState(() { - _showToast = false; + _canShowToast = false; }); }, + child: Text( + 'Copy', + style: (model.isWebFullView && !model.isMobileResolution) + ? TextStyle( + color: _copyColor, + fontSize: 16, + fontFamily: 'Roboto', + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400) + : TextStyle(fontSize: 17, color: _copyColor), + ), ), ), ), ); - _overlayState.insert(_overlayEntry); + _overlayState?.insert(_overlayEntry!); + } + } + + /// Check and close the context menu. + void _checkAndCloseContextMenu() { + if (_overlayEntry != null) { + _overlayEntry?.remove(); + _overlayEntry = null; } } + /// Shows toast once after the selected text is copied to the Clipboard. + Widget _showToast() { + return Positioned.fill( + bottom: 25.0, + child: Align( + alignment: Alignment.bottomCenter, + child: Flex( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(left: 16, top: 6, right: 16, bottom: 6), + decoration: BoxDecoration( + color: Colors.grey[600], + borderRadius: BorderRadius.all( + Radius.circular(16.0), + ), + ), + child: Text( + 'Copied', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Roboto', fontSize: 16, color: Colors.white), + ), + ), + ], + ), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder( future: Future.delayed(Duration(milliseconds: 200)).then((value) { - _showPdf = true; + _canShowPdf = true; }), builder: (context, snapshot) { - if (_showPdf) { + if (_canShowPdf) { return SfPdfViewerTheme( data: SfPdfViewerThemeData( brightness: model.themeData.brightness), @@ -158,54 +222,17 @@ class _GettingStartedPdfViewerState extends SampleViewState { }, ), Visibility( - visible: _showToast, - child: Positioned.fill( - bottom: 25.0, - child: Align( - alignment: Alignment.bottomCenter, - child: Flex( - direction: Axis.horizontal, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only( - left: 16, top: 6, right: 16, bottom: 6), - decoration: BoxDecoration( - color: Colors.grey[500], - borderRadius: BorderRadius.all( - Radius.circular(16.0), - ), - ), - child: Text( - 'Copied', - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: 'Roboto', - fontSize: 16, - color: Colors.white), - ), - ), - ], - ), - ), - ), + visible: _canShowToast, + child: _showToast(), ), ]), ); } else { return Container( - color: SfPdfViewerTheme.of(context).backgroundColor, + color: SfPdfViewerTheme.of(context)!.backgroundColor, ); } }), ); } - - /// Check and close the context menu. - void _checkAndCloseContextMenu() { - if (_overlayEntry != null) { - _overlayEntry.remove(); - _overlayEntry = null; - } - } } diff --git a/lib/samples/pdf_viewer/shared/mobile_helper.dart b/lib/samples/pdf_viewer/shared/mobile_helper.dart new file mode 100644 index 00000000..ece0abd8 --- /dev/null +++ b/lib/samples/pdf_viewer/shared/mobile_helper.dart @@ -0,0 +1,4 @@ +/// Prevents default menu. +void preventDefaultMenu() { + return null; +} diff --git a/lib/samples/pdf_viewer/shared/web_helper.dart b/lib/samples/pdf_viewer/shared/web_helper.dart new file mode 100644 index 00000000..b12e4490 --- /dev/null +++ b/lib/samples/pdf_viewer/shared/web_helper.dart @@ -0,0 +1,15 @@ +// ignore: avoid_web_libraries_in_flutter +import 'dart:html' as html; + +/// Prevent default menu. +void preventDefaultMenu() { + html.window.document.onKeyDown.listen((e) => _preventSpecificDefaultMenu(e)); + html.window.document.onContextMenu.listen((e) => e.preventDefault()); +} + +/// Prevent specific default search menu. +void _preventSpecificDefaultMenu(e) { + if (e.keyCode == 114 || (e.ctrlKey && e.keyCode == 70)) { + e.preventDefault(); + } +} diff --git a/lib/samples/progress_bar/angles.dart b/lib/samples/progress_bar/angles.dart index e33ef618..2cfb16f9 100644 --- a/lib/samples/progress_bar/angles.dart +++ b/lib/samples/progress_bar/angles.dart @@ -12,6 +12,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class ProgressBarAngles extends SampleView { + /// Creates AgendaView Calendar sample. const ProgressBarAngles(Key key) : super(key: key); @override @@ -22,7 +23,7 @@ class _ProgressBarAnglesState extends SampleViewState { _ProgressBarAnglesState(); double _size = 150; - Timer _timer; + late Timer _timer; double _value = 0; @override void initState() { @@ -48,7 +49,7 @@ class _ProgressBarAnglesState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 6 : MediaQuery.of(context).size.height / 5.5; return Center( @@ -58,10 +59,12 @@ class _ProgressBarAnglesState extends SampleViewState { children: [ _getFirstProgressBar(), Align( - alignment: !model.isWeb ? Alignment(-0.3, 0) : Alignment(0, 0), + alignment: + !model.isWebFullView ? Alignment(-0.3, 0) : Alignment(0, 0), child: _getSecondProgressBar()), Align( - alignment: !model.isWeb ? Alignment(0.3, 0) : Alignment(0, 0), + alignment: + !model.isWebFullView ? Alignment(0.3, 0) : Alignment(0, 0), child: _getThirdProgressBar(), ), _getFourthProgressBar(), @@ -79,7 +82,8 @@ class _ProgressBarAnglesState extends SampleViewState { _getSecondProgressBar(), _getThirdProgressBar(), Align( - alignment: model.isWeb ? Alignment(0, -0.5) : Alignment(0, 0), + alignment: + model.isWebFullView ? Alignment(0, -0.5) : Alignment(0, 0), child: _getFourthProgressBar()), ], ), diff --git a/lib/samples/progress_bar/custom_labels.dart b/lib/samples/progress_bar/custom_labels.dart index da4cb6c6..b76ce309 100644 --- a/lib/samples/progress_bar/custom_labels.dart +++ b/lib/samples/progress_bar/custom_labels.dart @@ -12,6 +12,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class ProgressBarCustomLabels extends SampleView { + /// Creates progress bar with custom labels. const ProgressBarCustomLabels(Key key) : super(key: key); @override @@ -23,7 +24,7 @@ class _ProgressBarCustomLabelsState extends SampleViewState { _ProgressBarCustomLabelsState(); double _size = 150; - Timer _timer; + late Timer _timer; double _value = 0; Widget _image1 = Container( height: 40, @@ -88,7 +89,7 @@ class _ProgressBarCustomLabelsState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 6.5 : MediaQuery.of(context).size.height / 5.5; return Center( diff --git a/lib/samples/progress_bar/determinate_styles.dart b/lib/samples/progress_bar/determinate_styles.dart index 42c56fe0..74401628 100644 --- a/lib/samples/progress_bar/determinate_styles.dart +++ b/lib/samples/progress_bar/determinate_styles.dart @@ -12,6 +12,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class ProgressBarDeterminateStyle extends SampleView { + /// Creates progress bar smaple with determinate styles. const ProgressBarDeterminateStyle(Key key) : super(key: key); @override @@ -20,10 +21,10 @@ class ProgressBarDeterminateStyle extends SampleView { } class _ProgressBarDeterminateStyleState extends SampleViewState { + _ProgressBarDeterminateStyleState(); double progressValue = 0; double _size = 150; - Timer _timer; - _ProgressBarDeterminateStyleState() {} + late Timer _timer; @override void initState() { @@ -45,7 +46,7 @@ class _ProgressBarDeterminateStyleState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 5 : MediaQuery.of(context).size.height / 4.5; return Center( @@ -118,7 +119,7 @@ class _ProgressBarDeterminateStyleState extends SampleViewState { showTicks: false, startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, axisLineStyle: AxisLineStyle( thickness: 1, color: const Color.fromARGB(255, 0, 169, 181), @@ -160,7 +161,7 @@ class _ProgressBarDeterminateStyleState extends SampleViewState { showTicks: false, startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, axisLineStyle: AxisLineStyle( thickness: 0.05, color: const Color.fromARGB(100, 0, 169, 181), @@ -192,7 +193,7 @@ class _ProgressBarDeterminateStyleState extends SampleViewState { showTicks: false, startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, axisLineStyle: AxisLineStyle( thickness: 0.2, color: const Color.fromARGB(30, 0, 169, 181), @@ -206,15 +207,9 @@ class _ProgressBarDeterminateStyleState extends SampleViewState { enableAnimation: true, animationDuration: 75, animationType: AnimationType.linear, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - Color(0xFFa4edeb), - Color(0xFF00a9b5) - ], stops: [ - 0.25, - 0.75 - ])), + gradient: SweepGradient( + colors: [Color(0xFFa4edeb), Color(0xFF00a9b5)], + stops: [0.25, 0.75])), ], annotations: [ GaugeAnnotation( diff --git a/lib/samples/progress_bar/segment_styles.dart b/lib/samples/progress_bar/segment_styles.dart index 49011e87..4e690ff2 100644 --- a/lib/samples/progress_bar/segment_styles.dart +++ b/lib/samples/progress_bar/segment_styles.dart @@ -12,6 +12,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class ProgressBarSegmentStyle extends SampleView { + /// Creates the progress bar segment style sample. const ProgressBarSegmentStyle(Key key) : super(key: key); @override @@ -24,7 +25,7 @@ class _ProgressBarSegmentStyleState extends SampleViewState { double progressValue = 0; double _size = 150; - Timer _timer; + late Timer _timer; @override void initState() { @@ -52,7 +53,7 @@ class _ProgressBarSegmentStyleState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 4.5 : MediaQuery.of(context).size.height / 4; return Center( @@ -140,7 +141,7 @@ class _ProgressBarSegmentStyleState extends SampleViewState { length: 0.3, thickness: 3, lengthUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Color.fromRGBO(33, 33, 33, 1)), ) diff --git a/lib/samples/progress_bar/track_with_marker.dart b/lib/samples/progress_bar/track_with_marker.dart index 9e6775f7..097febe1 100644 --- a/lib/samples/progress_bar/track_with_marker.dart +++ b/lib/samples/progress_bar/track_with_marker.dart @@ -12,6 +12,7 @@ import '../../model/sample_view.dart'; /// Widget of the AgendaView Calendar. class ProgressBarTrackWithMarker extends SampleView { + /// Creates the progress bar track with marker sample const ProgressBarTrackWithMarker(Key key) : super(key: key); @override @@ -24,7 +25,7 @@ class _ProgressBarTrackWithMarkerState extends SampleViewState { double progressValue = 0; double _size = 150; - Timer _timer; + late Timer _timer; @override void initState() { super.initState(); @@ -45,76 +46,50 @@ class _ProgressBarTrackWithMarkerState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 3.5 : MediaQuery.of(context).size.height / 4.5; return Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - getProgressBarWithCircle(), - Center(child: Text('Circle marker')), - getProgressBarWithRectangle(), - Center(child: Text('Rectangle marker')), - getProgressBarWithImage(), - Center(child: Text('Image marker')), - ] - : [ - getProgressBarWithCircle(), - Center(child: Text('Circle marker')), - getProgressBarWithRectangle(), - Center(child: Text('Rectangle marker')) - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + getProgressBarWithCircle(), + Center(child: Text('Circle marker')), + getProgressBarWithRectangle(), + Center(child: Text('Rectangle marker')), + getProgressBarWithImage(), + Center(child: Text('Image marker')), + ])); } else { _size = MediaQuery.of(context).size.width / 4.5; return Center( child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getProgressBarWithCircle(), - Center(child: Text('Circle marker')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getProgressBarWithRectangle(), - Center(child: Text('Rectangle marker')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getProgressBarWithImage(), - Center(child: Text('Image marker')), - ]), - ] - : [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getProgressBarWithCircle(), - Center(child: Text('Circle marker')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getProgressBarWithRectangle(), - Center(child: Text('Rectangle marker')), - ]), - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + getProgressBarWithCircle(), + Center(child: Text('Circle marker')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + getProgressBarWithRectangle(), + Center(child: Text('Rectangle marker')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + getProgressBarWithImage(), + Center(child: Text('Image marker')), + ]), + ])); } } @@ -151,20 +126,14 @@ class _ProgressBarTrackWithMarkerState extends SampleViewState { animationDuration: 30, animationType: AnimationType.linear, cornerStyle: CornerStyle.startCurve, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - Color(0xFF00a9b5), - Color(0xFFa4edeb) - ], stops: [ - 0.25, - 0.75 - ])), + gradient: SweepGradient( + colors: [Color(0xFF00a9b5), Color(0xFFa4edeb)], + stops: [0.25, 0.75])), MarkerPointer( value: progressValue, markerType: MarkerType.circle, - markerHeight: model.isWeb ? 25 : 20, - markerWidth: model.isWeb ? 25 : 20, + markerHeight: model.isWebFullView ? 25 : 20, + markerWidth: model.isWebFullView ? 25 : 20, enableAnimation: true, animationDuration: 30, animationType: AnimationType.linear, @@ -206,20 +175,14 @@ class _ProgressBarTrackWithMarkerState extends SampleViewState { animationDuration: 30, animationType: AnimationType.linear, cornerStyle: CornerStyle.startCurve, - gradient: model.isWeb - ? null - : const SweepGradient(colors: [ - Color(0xFF00a9b5), - Color(0xFFa4edeb) - ], stops: [ - 0.25, - 0.75 - ])), + gradient: const SweepGradient( + colors: [Color(0xFF00a9b5), Color(0xFFa4edeb)], + stops: [0.25, 0.75])), MarkerPointer( value: progressValue, markerType: MarkerType.rectangle, - markerHeight: model.isWeb ? 25 : 18, - markerWidth: model.isWeb ? 25 : 18, + markerHeight: model.isWebFullView ? 25 : 18, + markerWidth: model.isWebFullView ? 25 : 18, enableAnimation: true, animationDuration: 30, animationType: AnimationType.linear, @@ -261,21 +224,15 @@ class _ProgressBarTrackWithMarkerState extends SampleViewState { animationDuration: 30, animationType: AnimationType.linear, cornerStyle: CornerStyle.startCurve, - gradient: model.isWeb - ? null - : const SweepGradient(colors: [ - Color(0xFF00a9b5), - Color(0xFFa4edeb) - ], stops: [ - 0.25, - 0.75 - ])), + gradient: const SweepGradient( + colors: [Color(0xFF00a9b5), Color(0xFFa4edeb)], + stops: [0.25, 0.75])), MarkerPointer( value: progressValue, markerType: MarkerType.image, imageUrl: 'images/ball_progressbar.png', - markerHeight: model.isWeb ? 15 : 30, - markerWidth: model.isWeb ? 15 : 30, + markerHeight: model.isWebFullView ? 25 : 30, + markerWidth: model.isWebFullView ? 25 : 30, enableAnimation: true, animationDuration: 30, animationType: AnimationType.linear, diff --git a/lib/samples/progress_bar/types.dart b/lib/samples/progress_bar/types.dart index 547d2fe9..914a7521 100644 --- a/lib/samples/progress_bar/types.dart +++ b/lib/samples/progress_bar/types.dart @@ -23,7 +23,7 @@ class _ProgressBarTypesState extends SampleViewState { _ProgressBarTypesState(); double _size = 150; - Timer _timer; + late Timer _timer; double _value = 0; double _value1 = 0; double _value2 = 0; @@ -110,7 +110,7 @@ class _ProgressBarTypesState extends SampleViewState { ], ); } else { - _size = model.isWeb ? size.height / 5 : size.height / 4.5; + _size = model.isWebFullView ? size.height / 5 : size.height / 4.5; return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -144,7 +144,7 @@ class _ProgressBarTypesState extends SampleViewState { endAngle: 270, showLabels: false, showTicks: false, - radiusFactor: model.isWeb ? 0.7 : 0.75, + radiusFactor: model.isWebFullView ? 0.7 : 0.75, axisLineStyle: AxisLineStyle( thickness: 0.05, color: const Color.fromARGB(30, 0, 169, 181), @@ -177,7 +177,7 @@ class _ProgressBarTypesState extends SampleViewState { startAngle: 270, endAngle: 270, canScaleToFit: true, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, axisLineStyle: AxisLineStyle( thickness: 0.05, color: const Color.fromARGB(20, 0, 169, 181), @@ -217,7 +217,7 @@ class _ProgressBarTypesState extends SampleViewState { showTicks: false, startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, axisLineStyle: AxisLineStyle( thickness: 0.2, color: const Color.fromARGB(30, 0, 169, 181), @@ -245,12 +245,12 @@ class _ProgressBarTypesState extends SampleViewState { minorTicksPerInterval: 0, startAngle: 270, endAngle: 270, - radiusFactor: model.isWeb ? 0.7 : 0.8, + radiusFactor: model.isWebFullView ? 0.7 : 0.8, majorTickStyle: MajorTickStyle( length: 0.3, thickness: 3, lengthUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Color.fromRGBO(33, 33, 33, 1)), ) diff --git a/lib/samples/radial_range_slider/basic_features/angles.dart b/lib/samples/radial_range_slider/basic_features/angles.dart index 825183e2..c3cb97e5 100644 --- a/lib/samples/radial_range_slider/basic_features/angles.dart +++ b/lib/samples/radial_range_slider/basic_features/angles.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the Radial Slider angles. class RadialRangeSliderAngles extends SampleView { + /// Creates the radial slider angles sample. const RadialRangeSliderAngles(Key key) : super(key: key); @override @@ -20,6 +21,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { _RadialRangeSliderAnglesState(); double _size = 150; + late double width, height; @override void initState() { super.initState(); @@ -31,52 +33,64 @@ class _RadialRangeSliderAnglesState extends SampleViewState { _markerSize = 18; _annotationFontSize = 15; } else { - _markerSize = model.isWeb ? 18 : 12; - _annotationFontSize = model.isWeb ? 15 : 12; + _markerSize = model.isWebFullView ? 25 : 12; + _annotationFontSize = model.isWebFullView ? 15 : 12; } - if (MediaQuery.of(context).size.height > - MediaQuery.of(context).size.width) { - _size = model.isWeb - ? MediaQuery.of(context).size.height / 6 - : MediaQuery.of(context).size.height / 6; + height = MediaQuery.of(context).size.height; + width = MediaQuery.of(context).size.width; + if (height > width) { + _size = model.isWebFullView ? height / 6 : height / 6; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirstSlider(), + _buildFirstSlider(), Align( - alignment: !model.isWeb ? Alignment(0, 0) : Alignment(0, 0), - child: _getSecondSlider(), + alignment: + !model.isWebFullView ? Alignment(0, 0) : Alignment(0, 0), + child: _buildSecondSlider(), ), Align( - alignment: !model.isWeb ? Alignment(0, 0) : Alignment(0, 0), - child: _getThirdSlider()), + alignment: + !model.isWebFullView ? Alignment(0, 0) : Alignment(0, 0), + child: _buildThirdSlider()), Align( - alignment: model.isWeb ? Alignment(0, 0) : Alignment(0, 0), - child: _getFourthSlider()), + alignment: + model.isWebFullView ? Alignment(0, 0) : Alignment(0, 0), + child: _buildFourthSlider()), ], ), ); } else { - _size = MediaQuery.of(context).size.width / 5.5; + _size = width / 5.5; return Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirstSlider(), Align( - alignment: Alignment(0.8, 0), - child: _getSecondSlider(), + alignment: + model.isWebFullView ? Alignment.centerRight : Alignment(0, 0), + child: _buildFirstSlider(), ), Align( - alignment: Alignment(-0.5, 0), - child: _getThirdSlider(), + alignment: model.isWebFullView + ? Alignment.centerLeft + : Alignment(0.8, 0), + child: _buildSecondSlider(), ), Align( - alignment: model.isWeb ? Alignment(0, 0) : Alignment(0, 0.5), - child: _getFourthSlider()), + alignment: model.isWebFullView + ? Alignment.centerLeft + : Alignment(-0.5, 0), + child: _buildThirdSlider(), + ), + Align( + alignment: model.isWebFullView + ? Alignment(-0.1, 0.25) + : Alignment(0, 0.5), + child: _buildFourthSlider()), ], ), ); @@ -88,59 +102,71 @@ class _RadialRangeSliderAnglesState extends SampleViewState { super.dispose(); } - Widget _getSecondSlider() { + Widget _buildSecondSlider() { return Container( height: _size, width: _size, child: SfRadialGauge(axes: [ RadialAxis( radiusFactor: 0.8, + interval: 10, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 90, endAngle: 270, + canScaleToFit: model.isWebFullView + ? width > height + ? true + : false + : false, ranges: [ GaugeRange( startValue: _thirdMarkerValue, endValue: _fourthMarkerValue, endWidth: 0.1, startWidth: 0.1, - color: const Color.fromRGBO(0, 198, 139, 1), + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor) ], pointers: [ MarkerPointer( value: _thirdMarkerValue, + elevation: 5, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, onValueChanged: handleThirdPointerValueChanged, onValueChanging: handleThirdPointerValueChanging, - borderWidth: 4, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderWidth: 4, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, ), MarkerPointer( value: _fourthMarkerValue, + elevation: 5, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleFourthPointerValueChanged, onValueChanging: handleFourthPointerValueChanging, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -154,7 +180,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, - color: model.currentThemeData.brightness == + color: model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white), @@ -166,59 +192,71 @@ class _RadialRangeSliderAnglesState extends SampleViewState { ); } - Widget _getThirdSlider() { + Widget _buildThirdSlider() { return Container( height: _size, width: _size, child: SfRadialGauge(axes: [ RadialAxis( radiusFactor: 0.8, + interval: 10, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 270, endAngle: 90, + canScaleToFit: model.isWebFullView + ? width > height + ? true + : false + : false, ranges: [ GaugeRange( startValue: _fifthMarkerValue, endValue: _sixthMarkerValue, endWidth: 0.1, startWidth: 0.1, - color: const Color.fromRGBO(0, 198, 139, 1), + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor) ], pointers: [ MarkerPointer( value: _fifthMarkerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleFifthPointerValueChanged, onValueChanging: handleFifthPointerValueChanging, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, ), MarkerPointer( value: _sixthMarkerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleSixthPointerValueChanged, onValueChanging: handleSixthPointerValueChanging, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -232,7 +270,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, - color: model.currentThemeData.brightness == + color: model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white), @@ -244,7 +282,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { ); } - Widget _getFirstSlider() { + Widget _buildFirstSlider() { return Container( height: _size, width: _size, @@ -252,7 +290,9 @@ class _RadialRangeSliderAnglesState extends SampleViewState { RadialAxis( radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 270, @@ -263,40 +303,44 @@ class _RadialRangeSliderAnglesState extends SampleViewState { endValue: _secondMarkerValue, endWidth: 0.1, startWidth: 0.1, - color: const Color.fromRGBO(0, 198, 139, 1), + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor) ], pointers: [ MarkerPointer( value: _firstMarkerValue, + elevation: 5, onValueChanged: handleFirstPointerValueChanged, onValueChanging: handleFirstPointerValueChanging, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, ), MarkerPointer( value: _secondMarkerValue, + elevation: 5, onValueChanged: handleSecondPointerValueChanged, onValueChanging: handleSecondPointerValueChanging, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, enableDragging: true, - borderWidth: 4, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderWidth: 4, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -310,7 +354,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, - color: model.currentThemeData.brightness == + color: model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white), @@ -322,7 +366,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { ); } - Widget _getFourthSlider() { + Widget _buildFourthSlider() { return Container( height: _size, width: _size, @@ -330,7 +374,9 @@ class _RadialRangeSliderAnglesState extends SampleViewState { RadialAxis( radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 180, @@ -341,38 +387,42 @@ class _RadialRangeSliderAnglesState extends SampleViewState { endValue: _eighthMarkerValue, endWidth: 0.1, startWidth: 0.1, - color: const Color.fromRGBO(0, 198, 139, 1), + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor) ], pointers: [ MarkerPointer( value: _seventhMarkerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleSeventhPointerValueChanged, onValueChanging: handleSeventhPointerValueChanging, enableDragging: true, - borderColor: model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, ), MarkerPointer( value: _eighthMarkerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleEighthPointerValueChanged, onValueChanging: handleEighthPointerValueChanging, enableDragging: true, - borderColor: model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -387,7 +437,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { fontFamily: 'Times', fontWeight: FontWeight.bold, color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white), ), @@ -404,7 +454,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { void handleSecondPointerValueChanged(double value) { setState(() { _secondMarkerValue = value; - final int _value = _secondMarkerValue.abs().round().toInt(); + final int _value = _secondMarkerValue.abs().roundToDouble().toInt(); _annotationValue_1 = '$_value'; }); } @@ -413,16 +463,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -430,7 +471,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { void handleFirstPointerValueChanged(double value) { setState(() { _firstMarkerValue = value; - final int _value = _firstMarkerValue.abs().round().toInt(); + final int _value = _firstMarkerValue.abs().roundToDouble().toInt(); _annotationValue1 = '$_value'; }); } @@ -439,16 +480,7 @@ class _RadialRangeSliderAnglesState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -464,16 +496,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Pointer dragging is canceled when dragging pointer value is less than 6. void handleFourthPointerValueChanging(ValueChangingArgs args) { - if (args.value <= _thirdMarkerValue || - (args.value - _fourthMarkerValue).abs() > 10) { - if (args.value <= _thirdMarkerValue) { - if ((args.value - _fourthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fourthMarkerValue = _thirdMarkerValue; - _thirdMarkerValue = args.value; - } - } + if (args.value <= _thirdMarkerValue) { + args.cancel = true; } } @@ -488,16 +512,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Value changeing call back for first pointer void handleThirdPointerValueChanging(ValueChangingArgs args) { - if (args.value >= _fourthMarkerValue || - (args.value - _thirdMarkerValue).abs() > 10) { - if (args.value >= _fourthMarkerValue) { - if ((args.value - _thirdMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _thirdMarkerValue = _fourthMarkerValue; - _fourthMarkerValue = args.value; - } - } + if (args.value >= _fourthMarkerValue) { + args.cancel = true; } } @@ -513,16 +529,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Pointer dragging is canceled when dragging pointer value is less than 6. void handleSixthPointerValueChanging(ValueChangingArgs args) { - if (args.value <= _fifthMarkerValue || - (args.value - _sixthMarkerValue).abs() > 10) { - if (args.value <= _fifthMarkerValue) { - if ((args.value - _sixthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _sixthMarkerValue = _fifthMarkerValue; - _fifthMarkerValue = args.value; - } - } + if (args.value <= _fifthMarkerValue) { + args.cancel = true; } } @@ -537,16 +545,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Value changeing call back for first pointer void handleFifthPointerValueChanging(ValueChangingArgs args) { - if (args.value >= _sixthMarkerValue || - (args.value - _fifthMarkerValue).abs() > 10) { - if (args.value >= _sixthMarkerValue) { - if ((args.value - _fifthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fifthMarkerValue = _sixthMarkerValue; - _sixthMarkerValue = args.value; - } - } + if (args.value >= _sixthMarkerValue) { + args.cancel = true; } } @@ -562,16 +562,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Pointer dragging is canceled when dragging pointer value is less than 6. void handleEighthPointerValueChanging(ValueChangingArgs args) { - if (args.value <= _seventhMarkerValue || - (args.value - _eighthMarkerValue).abs() > 10) { - if (args.value <= _seventhMarkerValue) { - if ((args.value - _eighthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _eighthMarkerValue = _seventhMarkerValue; - _seventhMarkerValue = args.value; - } - } + if (args.value <= _seventhMarkerValue) { + args.cancel = true; } } @@ -586,16 +578,8 @@ class _RadialRangeSliderAnglesState extends SampleViewState { /// Value changeing call back for first pointer void handleSeventhPointerValueChanging(ValueChangingArgs args) { - if (args.value >= _eighthMarkerValue || - (args.value - _seventhMarkerValue).abs() > 10) { - if (args.value >= _eighthMarkerValue) { - if ((args.value - _seventhMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _seventhMarkerValue = _eighthMarkerValue; - _eighthMarkerValue = args.value; - } - } + if (args.value >= _eighthMarkerValue) { + args.cancel = true; } } diff --git a/lib/samples/radial_range_slider/basic_features/labels_and_ticks.dart b/lib/samples/radial_range_slider/basic_features/labels_and_ticks.dart index e5ac63f8..9819db13 100644 --- a/lib/samples/radial_range_slider/basic_features/labels_and_ticks.dart +++ b/lib/samples/radial_range_slider/basic_features/labels_and_ticks.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider ticks and labels. class RadialRangeSliderLabelsTicks extends SampleView { + /// Creates the RadialSlider ticks and labels sample. const RadialRangeSliderLabelsTicks(Key key) : super(key: key); @override @@ -27,23 +28,33 @@ class _RadialRangeSliderLabelsTicksState extends SampleViewState { @override Widget build(BuildContext context) { if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 27; - _annotationFontSize = 25; + _firstMarkerSize = 35; + _annotationFontSize = 15; } else { - _firstMarkerSize = model.isWeb ? 20 : 15; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 35 : 15; + _annotationFontSize = model.isWebFullView ? 25 : 15; } return Center( child: SfRadialGauge(axes: [ RadialAxis( + showFirstLabel: false, + startAngle: 270, + endAngle: 270, radiusFactor: 0.85, + minimum: 0, + maximum: 12, + interval: 3, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), - tickOffset: 0.2, - labelOffset: 0.15, + color: Color.fromRGBO(128, 94, 246, 0.3), + thickness: 0.075, + thicknessUnit: GaugeSizeUnit.factor), + tickOffset: 0.15, + labelOffset: 0.1, offsetUnit: GaugeSizeUnit.factor, - minorTicksPerInterval: 7, + minorTicksPerInterval: 30, + minorTickStyle: + MinorTickStyle(length: 0.05, lengthUnit: GaugeSizeUnit.factor), majorTickStyle: MajorTickStyle(length: 0.1, lengthUnit: GaugeSizeUnit.factor), ranges: [ @@ -51,9 +62,34 @@ class _RadialRangeSliderLabelsTicksState extends SampleViewState { endValue: _secondMarkerValue, startValue: _firstMarkerValue, sizeUnit: GaugeSizeUnit.factor, - color: const Color.fromRGBO(0, 198, 139, 1), - endWidth: 0.1, - startWidth: 0.1) + color: const Color.fromRGBO(128, 94, 246, 1), + endWidth: 0.075, + startWidth: 0.075) + ], + pointers: [ + MarkerPointer( + value: _firstMarkerValue, + elevation: 5, + enableDragging: true, + color: Color.fromRGBO(128, 94, 246, 1), + markerHeight: _firstMarkerSize, + markerWidth: _firstMarkerSize, + markerType: MarkerType.circle, + onValueChanged: handleFirstPointerValueChanged, + onValueChanging: handleFirstPointerValueChanging, + ), + MarkerPointer( + value: _secondMarkerValue, + elevation: 5, + markerOffset: 0.1, + color: Color.fromRGBO(128, 94, 246, 1), + enableDragging: true, + markerHeight: _firstMarkerSize, + markerWidth: _firstMarkerSize, + markerType: MarkerType.circle, + onValueChanged: handleSecondPointerValueChanged, + onValueChanging: handleSecondPointerValueChanging, + ) ], annotations: [ GaugeAnnotation( @@ -61,70 +97,18 @@ class _RadialRangeSliderLabelsTicksState extends SampleViewState { mainAxisSize: MainAxisSize.min, children: [ Text( - '$_annotationValue1 - $_annotationValue2', + _annotationValue2.contains(_annotationValue1) + ? '$_annotationValue1' + : '$_annotationValue1 - $_annotationValue2', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', - fontWeight: FontWeight.bold, ), ), ], ), - positionFactor: 0.7, angle: 90) ]), - // Create secondary radial axis for segmented line - RadialAxis( - interval: 20, - showLabels: false, - showTicks: true, - showAxisLine: false, - tickOffset: -0.05, - offsetUnit: GaugeSizeUnit.factor, - minorTicksPerInterval: 0, - radiusFactor: 0.85, - majorTickStyle: MajorTickStyle( - length: 0.3, - thickness: 3, - lengthUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Color.fromRGBO(33, 33, 33, 1)), - pointers: [ - MarkerPointer( - value: _firstMarkerValue, - enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderColor: const Color.fromRGBO(0, 198, 139, 1), - borderWidth: 7, - markerOffset: 0.0355, - offsetUnit: GaugeSizeUnit.factor, - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, - markerType: MarkerType.circle, - onValueChanged: handleFirstPointerValueChanged, - onValueChanging: handleFirstPointerValueChanging, - ), - MarkerPointer( - value: _secondMarkerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderColor: const Color.fromRGBO(0, 198, 139, 1), - enableDragging: true, - borderWidth: 6, - markerOffset: 0.0355, - offsetUnit: GaugeSizeUnit.factor, - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, - markerType: MarkerType.circle, - onValueChanged: handleSecondPointerValueChanged, - onValueChanging: handleSecondPointerValueChanging, - ) - ], - ), ]), ); } @@ -139,25 +123,20 @@ class _RadialRangeSliderLabelsTicksState extends SampleViewState { void handleSecondPointerValueChanged(double value) { setState(() { _secondMarkerValue = value; - final int _value = _secondMarkerValue.abs().round().toInt(); - _annotationValue2 = '$_value'; + final int _value = _secondMarkerValue.round().toInt(); + _annotationValue2 = _value == 12 + ? '$_value PM' + : _value == 0 + ? ' 12 AM' + : '$_value AM'; }); } /// Pointer dragging is canceled when dragging pointer value is less than 6. void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || - (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + (args.value - _secondMarkerValue).abs() > 1) { + args.cancel = true; } } @@ -165,32 +144,27 @@ class _RadialRangeSliderLabelsTicksState extends SampleViewState { void handleFirstPointerValueChanged(double value) { setState(() { _firstMarkerValue = value; - final int _value = _firstMarkerValue.abs().round().toInt(); - _annotationValue1 = '$_value'; + final int _value = _firstMarkerValue.round().toInt(); + _annotationValue1 = _value == 12 + ? '$_value PM' + : _value == 0 + ? ' 12 AM' + : '$_value AM'; }); } /// Value changeing call back for first pointer void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || - (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + (args.value - _firstMarkerValue).abs() > 1) { + args.cancel = true; } } - double _secondMarkerValue = 70; - double _firstMarkerValue = 10; - double _firstMarkerSize = 10; + double _secondMarkerValue = 9; + double _firstMarkerValue = 0; + double _firstMarkerSize = 35; double _annotationFontSize = 25; - String _annotationValue1 = '10'; - String _annotationValue2 = '70'; + String _annotationValue1 = '12 AM'; + String _annotationValue2 = '9 AM'; } diff --git a/lib/samples/radial_range_slider/basic_features/state.dart b/lib/samples/radial_range_slider/basic_features/state.dart index fc22c097..432739a4 100644 --- a/lib/samples/radial_range_slider/basic_features/state.dart +++ b/lib/samples/radial_range_slider/basic_features/state.dart @@ -10,6 +10,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider state. class RadialRangeSliderStateTypes extends SampleView { + /// Creates the RadialSlider state sample. const RadialRangeSliderStateTypes(Key key) : super(key: key); @override @@ -24,9 +25,9 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { double _secondMarkerValue = 30; double _firstMarkerValue = 0; double _markerSize = 30; - double _annotationFontSize = 25; + final double _annotationFontSize = 25; String _annotationValue1 = '0'; - String _annotationValue2 = '30'; + String _annotationValue2 = '30%'; @override void initState() { super.initState(); @@ -37,7 +38,7 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { if (MediaQuery.of(context).orientation == Orientation.portrait) { _markerSize = 35; } else { - _markerSize = model.isWeb ? 25 : 25; + _markerSize = model.isWebFullView ? 35 : 25; } return Center( @@ -46,7 +47,10 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { RadialAxis( radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: model.isWeb ? 0.15 : 0.25, + color: model.themeData.brightness == Brightness.light + ? Color.fromRGBO(191, 214, 245, 1) + : Color.fromRGBO(36, 58, 89, 1), + thickness: 0.05, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -58,29 +62,35 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { startValue: _firstMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: _enableDragging - ? const Color.fromRGBO(34, 144, 199, 1) + ? const Color.fromRGBO(44, 117, 220, 1) : const Color(0xFF888888), - endWidth: model.isWeb ? 0.15 : 0.25, - startWidth: model.isWeb ? 0.15 : 0.25, + endWidth: 0.05, + startWidth: 0.05, ) ], pointers: [ MarkerPointer( value: _firstMarkerValue, + elevation: 5, onValueChanged: handleFirstPointerValueChanged, onValueChanging: handleFirstPointerValueChanging, enableDragging: _enableDragging, - color: Colors.white, + color: _enableDragging + ? const Color.fromRGBO(44, 117, 220, 1) + : const Color(0xFF888888), markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, ), MarkerPointer( value: _secondMarkerValue, + elevation: 5, onValueChanged: handleSecondPointerValueChanged, onValueChanging: handleSecondPointerValueChanging, enableDragging: _enableDragging, - color: Colors.white, + color: _enableDragging + ? const Color.fromRGBO(44, 117, 220, 1) + : const Color(0xFF888888), markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -88,21 +98,21 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { ], annotations: [ GaugeAnnotation( - widget: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '$_annotationValue1 - $_annotationValue2', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - ), + widget: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '$_annotationValue1 - $_annotationValue2', + style: TextStyle( + fontSize: _annotationFontSize, + fontFamily: 'Times', + fontWeight: FontWeight.bold, ), - ], - ), - positionFactor: 0.13, - angle: 90) + ), + ], + ), + positionFactor: 0.05, + ) ]) ], ), @@ -140,7 +150,7 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { setState(() { _secondMarkerValue = value; final int _value = _secondMarkerValue.abs().toInt(); - _annotationValue2 = '$_value'; + _annotationValue2 = '$_value%'; }); } @@ -148,16 +158,7 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -174,16 +175,7 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } diff --git a/lib/samples/radial_range_slider/customization/custom_text.dart b/lib/samples/radial_range_slider/customization/custom_text.dart index 217a2cba..0f760535 100644 --- a/lib/samples/radial_range_slider/customization/custom_text.dart +++ b/lib/samples/radial_range_slider/customization/custom_text.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider custom text. class RadialRangeSliderCustomText extends SampleView { + /// Creates the RadialSlider custom text sample. const RadialRangeSliderCustomText(Key key) : super(key: key); @override @@ -30,15 +31,14 @@ class _RadialRangeSliderCustomTextState extends SampleViewState { _firstMarkerSize = 30; _annotationFontSize = 20; } else { - _firstMarkerSize = model.isWeb ? 25 : 20; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 28 : 20; + _annotationFontSize = model.isWebFullView ? 28 : 15; } return Center( child: SfRadialGauge(axes: [ RadialAxis( axisLineStyle: AxisLineStyle( - thickness: model.isWeb ? 0.15 : 0.2, - thicknessUnit: GaugeSizeUnit.factor), + thickness: 0.07, thicknessUnit: GaugeSizeUnit.factor), showTicks: false, showLabels: true, labelOffset: 25, @@ -48,31 +48,37 @@ class _RadialRangeSliderCustomTextState extends SampleViewState { startValue: _firstMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: _rangeColor, - endWidth: model.isWeb ? 0.15 : 0.2, - startWidth: model.isWeb ? 0.15 : 0.2, + endWidth: 0.07, + startWidth: 0.07, ) ], pointers: [ MarkerPointer( value: _firstMarkerValue, + elevation: 5, color: Colors.white, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, borderColor: _rangeColor, - borderWidth: 9.5, + overlayRadius: 0, + overlayColor: _rangeColor.withOpacity(0.125), + borderWidth: 8.5, markerType: MarkerType.circle, enableDragging: true, onValueChanged: handleFirstPointerValueChanged, onValueChanging: handleFirstPointerValueChanging, ), MarkerPointer( - value: _secondMarkerValue - 1, + value: _secondMarkerValue, + elevation: 5, onValueChanged: handleSecondPointerValueChanged, onValueChanging: handleSecondPointerValueChanging, enableDragging: true, color: Colors.white, borderColor: _rangeColor, - borderWidth: 9.5, + overlayRadius: 0, + overlayColor: _rangeColor.withOpacity(0.125), + borderWidth: 8.5, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, markerType: MarkerType.circle, @@ -80,21 +86,21 @@ class _RadialRangeSliderCustomTextState extends SampleViewState { ], annotations: [ GaugeAnnotation( - widget: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '$_annotationValue', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - ), + widget: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '$_annotationValue', + style: TextStyle( + fontSize: _annotationFontSize, + fontFamily: 'Times', + fontWeight: FontWeight.bold, ), - ], - ), - positionFactor: 0.13, - angle: 0) + ), + ], + ), + positionFactor: 0.09, + ) ]) ]), ); @@ -132,16 +138,7 @@ class _RadialRangeSliderCustomTextState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -171,16 +168,7 @@ class _RadialRangeSliderCustomTextState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } diff --git a/lib/samples/radial_range_slider/customization/gradient.dart b/lib/samples/radial_range_slider/customization/gradient.dart index 32c15cb5..d6193e23 100644 --- a/lib/samples/radial_range_slider/customization/gradient.dart +++ b/lib/samples/radial_range_slider/customization/gradient.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider gradient. class RadialRangeSliderGradient extends SampleView { + /// Creates RadialSlider gradient. const RadialRangeSliderGradient(Key key) : super(key: key); @override @@ -25,8 +26,8 @@ class _RadialRangeSliderGradientState extends SampleViewState { _firstMarkerSize = 30; _annotationFontSize = 25; } else { - _firstMarkerSize = model.isWeb ? 20 : 15; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 28 : 15; + _annotationFontSize = model.isWebFullView ? 25 : 15; } return Center( child: SfRadialGauge(axes: [ @@ -39,8 +40,8 @@ class _RadialRangeSliderGradientState extends SampleViewState { offsetUnit: GaugeSizeUnit.factor, minorTicksPerInterval: 5, onLabelCreated: (args) { - double axisValue = double.parse(args.text); - double celsiusValue = (axisValue - 32) / 1.8; + final double axisValue = double.parse(args.text); + final double celsiusValue = (axisValue - 32) / 1.8; args.text = celsiusValue.toStringAsFixed(1); }, majorTickStyle: @@ -51,8 +52,8 @@ class _RadialRangeSliderGradientState extends SampleViewState { mainAxisSize: MainAxisSize.min, children: [ Text( - '$_firstCelsiusAnnotationValue°C' + - ' to $_secondCelsiusAnnotationValue', + '$_firstCelsiusAnnotationValue°C' + ' to $_secondCelsiusAnnotationValue', style: TextStyle( fontSize: _celsiusAnnotationFontSize, fontFamily: 'Times', @@ -74,7 +75,7 @@ class _RadialRangeSliderGradientState extends SampleViewState { ]), RadialAxis( axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + thickness: 0.05, thicknessUnit: GaugeSizeUnit.factor), showTicks: false, showLabels: true, labelOffset: 20, @@ -83,27 +84,27 @@ class _RadialRangeSliderGradientState extends SampleViewState { endValue: _secondMarkerValue, startValue: _firstMarkerValue, sizeUnit: GaugeSizeUnit.factor, - gradient: model.isWeb - ? null - : const SweepGradient(colors: [ - Color.fromRGBO(115, 67, 189, 1), - Color.fromRGBO(202, 94, 230, 1) - ], stops: [ - 0.5, - 1 - ]), - endWidth: 0.1, - startWidth: 0.1) + gradient: const SweepGradient(colors: [ + Color.fromRGBO(115, 67, 189, 1), + Color.fromRGBO(202, 94, 230, 1) + ], stops: [ + 0.5, + 1 + ]), + endWidth: 0.05, + startWidth: 0.05) ], pointers: [ MarkerPointer( value: _firstMarkerValue, - color: model.currentThemeData.brightness == Brightness.light + elevation: 5, + overlayColor: Color.fromRGBO(202, 94, 230, 0.125), + color: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Colors.black, borderWidth: 7, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, markerHeight: _firstMarkerSize, @@ -115,15 +116,17 @@ class _RadialRangeSliderGradientState extends SampleViewState { ), MarkerPointer( value: _secondMarkerValue, - color: model.currentThemeData.brightness == Brightness.light + elevation: 5, + color: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Colors.black, borderWidth: 7, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, markerHeight: _firstMarkerSize, + overlayColor: Color.fromRGBO(202, 94, 230, 0.125), markerWidth: _firstMarkerSize, markerType: MarkerType.circle, enableDragging: true, @@ -183,16 +186,7 @@ class _RadialRangeSliderGradientState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -213,16 +207,7 @@ class _RadialRangeSliderGradientState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -230,7 +215,7 @@ class _RadialRangeSliderGradientState extends SampleViewState { double _firstMarkerValue = 0; double _firstMarkerSize = 30; double _annotationFontSize = 25; - double _celsiusAnnotationFontSize = 18; + final double _celsiusAnnotationFontSize = 18; String _firstAnnotationValue = '0'; String _secondAnnotationValue = '60'; String _firstCelsiusAnnotationValue = '-${17.7778.toStringAsFixed(1)}'; diff --git a/lib/samples/radial_range_slider/customization/styles.dart b/lib/samples/radial_range_slider/customization/styles.dart index 6e53b334..d371d939 100644 --- a/lib/samples/radial_range_slider/customization/styles.dart +++ b/lib/samples/radial_range_slider/customization/styles.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider styles. class RadialRangeSliderStyles extends SampleView { + /// Creates the the RadialSlider styles. const RadialRangeSliderStyles(Key key) : super(key: key); @override @@ -29,27 +30,27 @@ class _RadialRangeSliderStylesState extends SampleViewState { double _firstMarkerValue = 0; double _secondMarkerValue = 30; String _annotationValue1 = '0'; - String _annotationValue_1 = '30'; + String _annotationValue_1 = '30%'; double _thirdMarkerValue = 0; double _fourthMarkerValue = 30; String _annotationValue2 = '0'; - String _annotationValue_2 = '30'; + String _annotationValue_2 = '30%'; double _fifthMarkerValue = 0; double _sixthMarkerValue = 30; String _annotationValue3 = '0'; - String _annotationValue_3 = '30'; + String _annotationValue_3 = '30%'; double _seventhMarkerValue = 0; double _eighthMarkerValue = 30; String _annotationValue4 = '0'; - String _annotationValue_4 = '30'; + String _annotationValue_4 = '30%'; double _ninthMarkerValue = 0; double _tenthMarkerValue = 30; String _annotationValue5 = '0'; - String _annotationValue_5 = '30'; + String _annotationValue_5 = '30%'; double _eleventhMarkerValue = 0; double _twelethMarkerValue = 30; @@ -63,19 +64,19 @@ class _RadialRangeSliderStylesState extends SampleViewState { @override Widget build(BuildContext context) { - Size actualSize = MediaQuery.of(context).size; + final Size actualSize = MediaQuery.of(context).size; if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 15; + _firstMarkerSize = 12; _secondMarkerSize = 20; _borderWidth = 5; _markerWidth = 5; _annotationFontSize = 15; } else { - _firstMarkerSize = model.isWeb ? 15 : 10; - _secondMarkerSize = model.isWeb ? 20 : 15; - _markerWidth = model.isWeb ? 3 : 3; - _borderWidth = model.isWeb ? 5 : 3; - _annotationFontSize = model.isWeb ? 15 : 12; + _firstMarkerSize = model.isWebFullView ? 15 : 10; + _secondMarkerSize = model.isWebFullView ? 20 : 15; + _markerWidth = model.isWebFullView ? 3 : 3; + _borderWidth = model.isWebFullView ? 5 : 3; + _annotationFontSize = model.isWebFullView ? 15 : 12; } if (actualSize.width > actualSize.height) { @@ -87,15 +88,19 @@ class _RadialRangeSliderStylesState extends SampleViewState { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, - children: [_getFirtSlider(), _getSecondSlider(), _getThirdSlider()], + children: [ + _buildFirtSlider(), + _buildSecondSlider(), + _buildThirdSlider() + ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFourthSlider(), - _getFifthSlider(), - _getSixthSlider() + _buildFourthSlider(), + _buildFifthSlider(), + _buildSixthSlider() ], ), ], @@ -109,15 +114,19 @@ class _RadialRangeSliderStylesState extends SampleViewState { Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, - children: [_getFirtSlider(), _getSecondSlider(), _getThirdSlider()], + children: [ + _buildFirtSlider(), + _buildSecondSlider(), + _buildThirdSlider() + ], ), Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFourthSlider(), - _getFifthSlider(), - _getSixthSlider() + _buildFourthSlider(), + _buildFifthSlider(), + _buildSixthSlider() ], ), ], @@ -125,7 +134,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { } } - Widget _getFirtSlider() { + Widget _buildFirtSlider() { return Container( height: _size, width: _size, @@ -134,7 +143,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(191, 214, 252, 1) : const Color.fromRGBO(36, 58, 97, 1), thickness: 0.1, @@ -155,29 +164,35 @@ class _RadialRangeSliderStylesState extends SampleViewState { pointers: [ MarkerPointer( value: _firstMarkerValue, + elevation: 5, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, borderWidth: _borderWidth, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, markerType: MarkerType.circle, onValueChanged: handleFirstPointerValueChanged, onValueChanging: handleFirstPointerValueChanging, + overlayColor: Color.fromRGBO(41, 118, 246, 0.125), borderColor: Color.fromRGBO(41, 118, 246, 1)), MarkerPointer( value: _secondMarkerValue, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + elevation: 5, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, borderWidth: _borderWidth, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, markerType: MarkerType.circle, onValueChanged: handleSecondPointerValueChanged, onValueChanging: handleSecondPointerValueChanging, + overlayColor: Color.fromRGBO(41, 118, 246, 0.125), borderColor: Color.fromRGBO(41, 118, 246, 1)), ], annotations: [ @@ -197,7 +212,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { ); } - Widget _getSecondSlider() { + Widget _buildSecondSlider() { return Container( height: _size, width: _size, @@ -206,7 +221,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(218, 218, 218, 1) : const Color.fromRGBO(88, 88, 88, 1), thickness: 0.15, @@ -228,6 +243,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { MarkerPointer( enableDragging: true, value: _thirdMarkerValue, + elevation: 5, color: const Color.fromRGBO(126, 86, 212, 1), borderWidth: 9, markerWidth: _firstMarkerSize, @@ -239,6 +255,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { MarkerPointer( value: _fourthMarkerValue, enableDragging: true, + elevation: 5, color: const Color.fromRGBO(126, 86, 212, 1), borderWidth: 9, markerWidth: _firstMarkerSize, @@ -266,7 +283,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { ); } - Widget _getThirdSlider() { + Widget _buildThirdSlider() { return Container( height: _size, width: _size, @@ -276,7 +293,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { radiusFactor: 0.85, axisLineStyle: AxisLineStyle( color: const Color.fromRGBO(254, 166, 25, 1), - thickness: 0.25, + thickness: 0.2, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -287,44 +304,53 @@ class _RadialRangeSliderStylesState extends SampleViewState { endValue: 100, startValue: 0, sizeUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : const Color.fromRGBO(41, 37, 32, 1), - endWidth: 0.145, - rangeOffset: 0.05, - startWidth: 0.145), + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : const Color.fromRGBO(41, 37, 32, 1), + endWidth: 0.13, + rangeOffset: 0.03, + startWidth: 0.13), GaugeRange( endValue: _sixthMarkerValue, startValue: _fifthMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: const Color.fromRGBO(254, 166, 25, 1), - rangeOffset: 0.05, - endWidth: 0.144, - startWidth: 0.144), + rangeOffset: 0.03, + endWidth: 0.14, + startWidth: 0.14), ], pointers: [ MarkerPointer( value: _sixthMarkerValue, + elevation: 5, enableDragging: true, - color: Colors.white, + color: model.currentThemeData!.brightness == Brightness.light + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(33, 33, 33, 1), borderWidth: _borderWidth, markerHeight: _secondMarkerSize, markerWidth: _secondMarkerSize, onValueChanged: handleSixthPointerValueChanged, onValueChanging: handleSixthPointerValueChanging, markerType: MarkerType.circle, + overlayColor: const Color.fromRGBO(254, 166, 25, 0.125), borderColor: const Color.fromRGBO(254, 166, 25, 1), ), MarkerPointer( value: _fifthMarkerValue, enableDragging: true, - color: Colors.white, + elevation: 5, + color: model.currentThemeData!.brightness == Brightness.light + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(33, 33, 33, 1), borderWidth: _borderWidth, markerHeight: _secondMarkerSize, markerWidth: _secondMarkerSize, onValueChanged: handleFifthPointerValueChanged, onValueChanging: handleFifthPointerValueChanging, markerType: MarkerType.circle, + overlayColor: const Color.fromRGBO(254, 166, 25, 0.125), borderColor: const Color.fromRGBO(254, 166, 25, 1), ) ], @@ -346,7 +372,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { ); } - Widget _getFourthSlider() { + Widget _buildFourthSlider() { return Container( height: _size, width: _size, @@ -355,10 +381,10 @@ class _RadialRangeSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(201, 201, 201, 1) : const Color.fromRGBO(78, 78, 78, 1), - thickness: 0.15, + thickness: 0.24, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -369,42 +395,47 @@ class _RadialRangeSliderStylesState extends SampleViewState { endValue: 100, startValue: 0, sizeUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - endWidth: 0.09, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, + endWidth: 0.18, rangeOffset: 0.03, - startWidth: 0.09), + startWidth: 0.18), GaugeRange( endValue: _eighthMarkerValue, startValue: _seventhMarkerValue, sizeUnit: GaugeSizeUnit.factor, - rangeOffset: 0.05, - endWidth: 0.05, + rangeOffset: 0.08, + endWidth: 0.08, color: const Color.fromRGBO(88, 194, 143, 1), - startWidth: 0.05), + startWidth: 0.08), ], pointers: [ MarkerPointer( value: _seventhMarkerValue, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 3, - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, + borderWidth: 4, + markerHeight: 20, + markerWidth: 20, markerType: MarkerType.circle, onValueChanged: handleSeventhPointerValueChanged, onValueChanging: handleSeventhPointerValueChanging, + overlayRadius: 0, borderColor: Color.fromRGBO(88, 194, 143, 1)), MarkerPointer( value: _seventhMarkerValue, enableDragging: true, + // elevation: 5, color: Color.fromRGBO(88, 194, 143, 1), - borderWidth: 1, - markerHeight: 7, - markerWidth: 7, + borderWidth: 2, + markerHeight: 9, + markerWidth: 9, + overlayRadius: 25, markerType: MarkerType.circle, onValueChanged: handleSeventhPointerValueChanged, onValueChanging: handleSeventhPointerValueChanging, @@ -412,23 +443,27 @@ class _RadialRangeSliderStylesState extends SampleViewState { MarkerPointer( value: _eighthMarkerValue, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 3, - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, + borderWidth: 4, + markerHeight: 20, + markerWidth: 20, markerType: MarkerType.circle, onValueChanged: handleEighthPointerValueChanged, onValueChanging: handleEighthPointerValueChanging, + overlayRadius: 0, borderColor: Color.fromRGBO(88, 194, 143, 1)), MarkerPointer( value: _eighthMarkerValue, enableDragging: true, + // elevation: 5, color: Color.fromRGBO(88, 194, 143, 1), - borderWidth: 1, - markerHeight: 7, - markerWidth: 7, + borderWidth: 2, + markerHeight: 9, + overlayRadius: 25, + markerWidth: 9, markerType: MarkerType.circle, onValueChanged: handleEighthPointerValueChanged, onValueChanging: handleEighthPointerValueChanging, @@ -452,17 +487,17 @@ class _RadialRangeSliderStylesState extends SampleViewState { ); } - Widget _getFifthSlider() { + Widget _buildFifthSlider() { return Container( height: _size, width: _size, child: SfRadialGauge( axes: [ RadialAxis( - radiusFactor: 0.8, + radiusFactor: 0.85, axisLineStyle: AxisLineStyle( color: Color.fromRGBO(41, 118, 246, 1), - thickness: 0.3, + thickness: 0.24, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -474,27 +509,29 @@ class _RadialRangeSliderStylesState extends SampleViewState { startValue: _ninthMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: const Color.fromRGBO(254, 166, 25, 1), - endWidth: 0.15, - rangeOffset: 0.075, - startWidth: 0.15), + endWidth: 0.1, + rangeOffset: 0.065, + startWidth: 0.1), ], pointers: [ MarkerPointer( value: _ninthMarkerValue, + // elevation: 5, color: const Color.fromRGBO(254, 166, 25, 1), - markerHeight: _firstMarkerSize, + markerHeight: 15, enableDragging: true, - markerWidth: _firstMarkerSize, + markerWidth: 15, onValueChanged: handleNinthPointerValueChanged, onValueChanging: handleNinthPointerValueChanging, markerType: MarkerType.circle, borderColor: const Color.fromRGBO(34, 144, 199, 0.75)), MarkerPointer( value: _tenthMarkerValue, + // elevation: 5, enableDragging: true, color: const Color.fromRGBO(254, 166, 25, 1), - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, + markerHeight: 15, + markerWidth: 15, onValueChanged: handleTenthPointerValueChanged, onValueChanging: handleTenthPointerValueChanging, markerType: MarkerType.circle, @@ -518,7 +555,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { ); } - Widget _getSixthSlider() { + Widget _buildSixthSlider() { return Container( height: _size, width: _size, @@ -540,16 +577,16 @@ class _RadialRangeSliderStylesState extends SampleViewState { startValue: _eleventhMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: const Color.fromRGBO(135, 80, 221, 1), - endWidth: 0.07, - rangeOffset: 0.27, - startWidth: 0.07), + endWidth: 0.17, + rangeOffset: 0.17, + startWidth: 0.17), ], pointers: [ NeedlePointer( value: _twelethMarkerValue, enableDragging: true, needleColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), needleEndWidth: 2, @@ -557,16 +594,16 @@ class _RadialRangeSliderStylesState extends SampleViewState { onValueChanged: handleTwelethPointerValueChanged, // onValueChangeEnd: handleTwelethPointerValueChanged, onValueChanging: handleTwelethPointerValueChanging, - needleLength: 0.71, + needleLength: 0.82, knobStyle: KnobStyle( - knobRadius: model.isWeb ? 0.4 : 0.3, + knobRadius: model.isWebFullView ? 0.4 : 0.3, borderWidth: 0.05, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.white : const Color.fromRGBO(33, 33, 33, 1), )), @@ -574,7 +611,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { value: _eleventhMarkerValue, enableDragging: true, needleColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), needleEndWidth: 2, @@ -582,16 +619,16 @@ class _RadialRangeSliderStylesState extends SampleViewState { onValueChanged: handleEleventhPointerValueChanged, // onValueChangeEnd: handleEleventhPointerValueChanged, onValueChanging: handleEleventhPointerValueChanging, - needleLength: 0.71, + needleLength: 0.82, knobStyle: KnobStyle( - knobRadius: model.isWeb ? 0.4 : 0.3, + knobRadius: model.isWebFullView ? 0.4 : 0.3, borderWidth: 0.05, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.white : const Color.fromRGBO(33, 33, 33, 1), )), @@ -601,10 +638,10 @@ class _RadialRangeSliderStylesState extends SampleViewState { widget: Text( '$_annotationValue6 - $_annotationValue_6', style: TextStyle( - fontSize: model.isWeb ? 10 : 12, + fontSize: model.isWebFullView ? 10 : 12, fontFamily: 'Times', fontWeight: FontWeight.bold, - color: model.currentThemeData.brightness == + color: model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, @@ -629,7 +666,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { setState(() { _secondMarkerValue = value; final int _value = _secondMarkerValue.abs().round().toInt(); - _annotationValue_1 = '$_value'; + _annotationValue_1 = '$_value%'; }); } @@ -637,16 +674,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -663,16 +691,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -682,7 +701,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { setState(() { _fourthMarkerValue = value; final int _value = _fourthMarkerValue.abs().round().toInt(); - _annotationValue_2 = '$_value'; + _annotationValue_2 = '$_value%'; }); } @@ -690,16 +709,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleFourthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _thirdMarkerValue || (args.value - _fourthMarkerValue).abs() > 10) { - if (args.value <= _thirdMarkerValue) { - if ((args.value - _fourthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fourthMarkerValue = _thirdMarkerValue; - _thirdMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -716,16 +726,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleThirdPointerValueChanging(ValueChangingArgs args) { if (args.value >= _fourthMarkerValue || (args.value - _thirdMarkerValue).abs() > 10) { - if (args.value >= _fourthMarkerValue) { - if ((args.value - _thirdMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _thirdMarkerValue = _fourthMarkerValue; - _fourthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -735,7 +736,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { setState(() { _sixthMarkerValue = value; final int _value = _sixthMarkerValue.abs().round().toInt(); - _annotationValue_3 = '$_value'; + _annotationValue_3 = '$_value%'; }); } @@ -743,16 +744,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleSixthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _fifthMarkerValue || (args.value - _sixthMarkerValue).abs() > 10) { - if (args.value <= _fifthMarkerValue) { - if ((args.value - _sixthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _sixthMarkerValue = _fifthMarkerValue; - _fifthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -769,16 +761,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleFifthPointerValueChanging(ValueChangingArgs args) { if (args.value >= _sixthMarkerValue || (args.value - _fifthMarkerValue).abs() > 10) { - if (args.value >= _sixthMarkerValue) { - if ((args.value - _fifthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fifthMarkerValue = _sixthMarkerValue; - _sixthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -788,7 +771,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { setState(() { _eighthMarkerValue = value; final int _value = _eighthMarkerValue.abs().round().toInt(); - _annotationValue_4 = '$_value'; + _annotationValue_4 = '$_value%'; }); } @@ -796,16 +779,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleEighthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _seventhMarkerValue || (args.value - _eighthMarkerValue).abs() > 10) { - if (args.value <= _seventhMarkerValue) { - if ((args.value - _eighthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _eighthMarkerValue = _seventhMarkerValue; - _seventhMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -822,16 +796,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleSeventhPointerValueChanging(ValueChangingArgs args) { if (args.value >= _eighthMarkerValue || (args.value - _seventhMarkerValue).abs() > 10) { - if (args.value >= _eighthMarkerValue) { - if ((args.value - _seventhMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _seventhMarkerValue = _eighthMarkerValue; - _eighthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -841,7 +806,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { setState(() { _tenthMarkerValue = value; final int _value = _tenthMarkerValue.abs().round().toInt(); - _annotationValue_5 = '$_value'; + _annotationValue_5 = '$_value%'; }); } @@ -849,16 +814,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleTenthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _ninthMarkerValue || (args.value - _tenthMarkerValue).abs() > 10) { - if (args.value <= _ninthMarkerValue) { - if ((args.value - _tenthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _tenthMarkerValue = _ninthMarkerValue; - _ninthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -875,16 +831,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleNinthPointerValueChanging(ValueChangingArgs args) { if (args.value >= _tenthMarkerValue || (args.value - _ninthMarkerValue).abs() > 10) { - if (args.value >= _tenthMarkerValue) { - if ((args.value - _ninthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _ninthMarkerValue = _tenthMarkerValue; - _tenthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -902,16 +849,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleTwelethPointerValueChanging(ValueChangingArgs args) { if (args.value <= _eleventhMarkerValue || (args.value - _twelethMarkerValue).abs() > 10) { - if (args.value <= _eleventhMarkerValue) { - if ((args.value - _twelethMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _twelethMarkerValue = _eleventhMarkerValue; - _eleventhMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -928,16 +866,7 @@ class _RadialRangeSliderStylesState extends SampleViewState { void handleEleventhPointerValueChanging(ValueChangingArgs args) { if (args.value >= _twelethMarkerValue || (args.value - _eleventhMarkerValue).abs() > 10) { - if (args.value >= _twelethMarkerValue) { - if ((args.value - _eleventhMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _eleventhMarkerValue = _twelethMarkerValue; - _twelethMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } } diff --git a/lib/samples/radial_range_slider/customization/thumb.dart b/lib/samples/radial_range_slider/customization/thumb.dart index e6d7945f..549b35e2 100644 --- a/lib/samples/radial_range_slider/customization/thumb.dart +++ b/lib/samples/radial_range_slider/customization/thumb.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the radial slider thumb customization. class RadialRangeSliderThumb extends SampleView { + /// Creates the radial slider thumb customization. const RadialRangeSliderThumb(Key key) : super(key: key); @override @@ -41,81 +42,55 @@ class _RadialRangeSliderThumbState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 3.5 : MediaQuery.of(context).size.height / 5; return Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - getSliderWithImage(), - Center(child: Text('Image thumb')), - ] - : [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')) - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithCircle(), + Center(child: Text('Circle thumb')), + _buildSliderWithRectangle(), + Center(child: Text('Rectangle thumb')), + _buildSliderWithImage(), + Center(child: Text('Image thumb')), + ])); } else { _size = MediaQuery.of(context).size.width / 4.5; return Center( child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithImage(), - Center(child: Text('Image thumb')), - ]), - ] - : [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - ]), - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithCircle(), + Center(child: Text('Circle thumb')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithRectangle(), + Center(child: Text('Rectangle thumb')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithImage(), + Center(child: Text('Image thumb')), + ]), + ])); } } /// Returns gradient progress style circular progress bar. - Widget getSliderWithCircle() { + Widget _buildSliderWithCircle() { return Container( height: _size, width: _size, @@ -135,22 +110,24 @@ class _RadialRangeSliderThumbState extends SampleViewState { endValue: _secondMarkerValue, startValue: _firstMarkerValue, sizeUnit: GaugeSizeUnit.factor, - color: model.isWeb ? Color.fromRGBO(197, 91, 226, 1) : null, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ]), + color: model.isWebFullView + ? Color.fromRGBO(197, 91, 226, 1) + : null, + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ]), endWidth: 0.1, startWidth: 0.1) ], pointers: [ MarkerPointer( value: _firstMarkerValue, + overlayRadius: 0, + elevation: 5, markerType: MarkerType.circle, markerHeight: 22, markerWidth: 22, @@ -161,6 +138,8 @@ class _RadialRangeSliderThumbState extends SampleViewState { ), MarkerPointer( value: _secondMarkerValue, + elevation: 5, + overlayRadius: 0, markerType: MarkerType.circle, markerHeight: 22, markerWidth: 22, @@ -179,7 +158,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { } /// Returns gradient progress style circular progress bar. - Widget getSliderWithRectangle() { + Widget _buildSliderWithRectangle() { return Container( height: _size, width: _size, @@ -199,16 +178,16 @@ class _RadialRangeSliderThumbState extends SampleViewState { endValue: _thirdMarkerValue, startValue: _fourthMarkerValue, sizeUnit: GaugeSizeUnit.factor, - color: model.isWeb ? Color.fromRGBO(197, 91, 226, 1) : null, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ]), + color: model.isWebFullView + ? Color.fromRGBO(197, 91, 226, 1) + : null, + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ]), endWidth: 0.1, startWidth: 0.1, ) @@ -216,6 +195,8 @@ class _RadialRangeSliderThumbState extends SampleViewState { pointers: [ MarkerPointer( value: _thirdMarkerValue, + overlayRadius: 0, + elevation: 5, markerType: MarkerType.rectangle, markerHeight: 22, markerWidth: 22, @@ -226,6 +207,8 @@ class _RadialRangeSliderThumbState extends SampleViewState { ), MarkerPointer( value: _fourthMarkerValue, + elevation: 5, + overlayRadius: 0, markerType: MarkerType.rectangle, markerHeight: 22, markerWidth: 22, @@ -244,7 +227,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { } /// Returns gradient progress style circular progress bar. - Widget getSliderWithImage() { + Widget _buildSliderWithImage() { return Container( height: _size, width: _size, @@ -265,25 +248,24 @@ class _RadialRangeSliderThumbState extends SampleViewState { startValue: _sixthMarkerValue, sizeUnit: GaugeSizeUnit.factor, color: Colors.green, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ]), + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ]), endWidth: 0.1, startWidth: 0.1) ], pointers: [ MarkerPointer( + overlayRadius: 0, value: _fifthMarkerValue, markerType: MarkerType.image, imageUrl: 'images/ball.png', - markerHeight: model.isWeb ? 15 : 30, - markerWidth: model.isWeb ? 15 : 30, + markerHeight: 30, + markerWidth: 30, enableDragging: true, onValueChanged: handleFifthPointerValueChanged, onValueChanging: handleFifthPointerValueChanging, @@ -293,8 +275,8 @@ class _RadialRangeSliderThumbState extends SampleViewState { value: _sixthMarkerValue, markerType: MarkerType.image, imageUrl: 'images/ball.png', - markerHeight: model.isWeb ? 15 : 30, - markerWidth: model.isWeb ? 15 : 30, + markerHeight: 30, + markerWidth: 30, enableDragging: true, onValueChanged: handleSixthPointerValueChanged, onValueChanging: handleSixthPointerValueChanging, @@ -323,16 +305,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleSecondPointerValueChanging(ValueChangingArgs args) { if (args.value <= _firstMarkerValue || (args.value - _secondMarkerValue).abs() > 10) { - if (args.value <= _firstMarkerValue) { - if ((args.value - _secondMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _secondMarkerValue = _firstMarkerValue; - _firstMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -349,16 +322,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleFirstPointerValueChanging(ValueChangingArgs args) { if (args.value >= _secondMarkerValue || (args.value - _firstMarkerValue).abs() > 10) { - if (args.value >= _secondMarkerValue) { - if ((args.value - _firstMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _firstMarkerValue = _secondMarkerValue; - _secondMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -376,16 +340,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleFourthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _thirdMarkerValue || (args.value - _fourthMarkerValue).abs() > 10) { - if (args.value <= _thirdMarkerValue) { - if ((args.value - _fourthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fourthMarkerValue = _thirdMarkerValue; - _thirdMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -402,16 +357,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleThirdPointerValueChanging(ValueChangingArgs args) { if (args.value >= _fourthMarkerValue || (args.value - _thirdMarkerValue).abs() > 10) { - if (args.value >= _fourthMarkerValue) { - if ((args.value - _thirdMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _thirdMarkerValue = _fourthMarkerValue; - _fourthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -429,16 +375,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleSixthPointerValueChanging(ValueChangingArgs args) { if (args.value <= _fifthMarkerValue || (args.value - _sixthMarkerValue).abs() > 10) { - if (args.value <= _fifthMarkerValue) { - if ((args.value - _sixthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _sixthMarkerValue = _fifthMarkerValue; - _fifthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } @@ -455,16 +392,7 @@ class _RadialRangeSliderThumbState extends SampleViewState { void handleFifthPointerValueChanging(ValueChangingArgs args) { if (args.value >= _sixthMarkerValue || (args.value - _fifthMarkerValue).abs() > 10) { - if (args.value >= _sixthMarkerValue) { - if ((args.value - _fifthMarkerValue).abs() > 10) { - args.cancel = true; - } else { - _fifthMarkerValue = _sixthMarkerValue; - _sixthMarkerValue = args.value; - } - } else { - args.cancel = true; - } + args.cancel = true; } } } diff --git a/lib/samples/radial_slider/basic_features/angles.dart b/lib/samples/radial_slider/basic_features/angles.dart index aafa47b6..8c53c568 100644 --- a/lib/samples/radial_slider/basic_features/angles.dart +++ b/lib/samples/radial_slider/basic_features/angles.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the Radial Slider angles. class RadialSliderAngles extends SampleView { + /// Creates the Radial Slider angles. const RadialSliderAngles(Key key) : super(key: key); @override @@ -19,6 +20,7 @@ class _RadialSliderAnglesState extends SampleViewState { _RadialSliderAnglesState(); double _size = 150; + late double width, height; @override void initState() { super.initState(); @@ -30,44 +32,62 @@ class _RadialSliderAnglesState extends SampleViewState { _markerSize = 18; _annotationFontSize = 15; } else { - _markerSize = model.isWeb ? 18 : 12; - _annotationFontSize = model.isWeb ? 15 : 12; + _markerSize = model.isWebFullView ? 25 : 12; + _annotationFontSize = model.isWebFullView ? 15 : 12; } - if (MediaQuery.of(context).size.height > - MediaQuery.of(context).size.width) { - _size = model.isWeb - ? MediaQuery.of(context).size.height / 6 - : MediaQuery.of(context).size.height / 6; + + height = MediaQuery.of(context).size.height; + width = MediaQuery.of(context).size.width; + if (height > width) { + _size = height / 6; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirstSlider(), + _buildFirstSlider(), Align( - alignment: !model.isWeb ? Alignment(0, 0.1) : Alignment(0, 0), - child: _getSecondSlider(), + alignment: + !model.isWebFullView ? Alignment(0, 0.1) : Alignment(0, 0), + child: _buildSecondSlider(), ), Align( - alignment: !model.isWeb ? Alignment(0, 0.1) : Alignment(0, 0), - child: _getThirdSlider()), - _getFourthSlider(), + alignment: + !model.isWebFullView ? Alignment(0, 0.1) : Alignment(0, 0), + child: _buildThirdSlider()), + _buildFourthSlider(), ], ), ); } else { - _size = MediaQuery.of(context).size.width / 5.5; + _size = width / 5.5; return Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirstSlider(), - _getSecondSlider(), - _getThirdSlider(), Align( - alignment: model.isWeb ? Alignment(0, -0.6) : Alignment(0, 0), - child: _getFourthSlider()), + alignment: + model.isWebFullView ? Alignment.centerRight : Alignment(0, 0), + child: _buildFirstSlider(), + ), + Align( + alignment: model.isWebFullView + ? Alignment.centerLeft + : Alignment(0.8, 0), + child: _buildSecondSlider(), + ), + Align( + alignment: model.isWebFullView + ? Alignment.centerLeft + : Alignment(-0.5, 0), + child: _buildThirdSlider(), + ), + Align( + alignment: model.isWebFullView + ? Alignment(-0.1, 0.25) + : Alignment(0, 0.5), + child: _buildFourthSlider()), ], ), ); @@ -79,15 +99,18 @@ class _RadialSliderAnglesState extends SampleViewState { super.dispose(); } - Widget _getFirstSlider() { + Widget _buildFirstSlider() { return Container( height: _size, width: _size, child: SfRadialGauge(axes: [ RadialAxis( + useRangeColorForAxis: true, radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 270, @@ -96,23 +119,17 @@ class _RadialSliderAnglesState extends SampleViewState { RangePointer( width: 0.1, value: _currentValue, - cornerStyle: CornerStyle.endCurve, - color: const Color.fromRGBO(0, 198, 139, 1), + cornerStyle: CornerStyle.bothCurve, + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( enableDragging: true, + elevation: 5, value: _markerValue, onValueChanged: handlePointerValueChanged, onValueChangeEnd: handlePointerValueChanged, onValueChanging: handlePointerValueChanging, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + color: Color.fromRGBO(88, 194, 143, 1), markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -121,13 +138,13 @@ class _RadialSliderAnglesState extends SampleViewState { annotations: [ GaugeAnnotation( widget: Text( - '$_annotationValue1' + '%', + '$_annotationValue1' '%', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, ), @@ -139,15 +156,23 @@ class _RadialSliderAnglesState extends SampleViewState { ); } - Widget _getSecondSlider() { + Widget _buildSecondSlider() { return Container( height: _size, width: _size, child: SfRadialGauge(axes: [ RadialAxis( radiusFactor: 0.8, + canScaleToFit: model.isWebFullView + ? width > height + ? true + : false + : false, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + cornerStyle: CornerStyle.bothCurve, + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 90, @@ -155,24 +180,26 @@ class _RadialSliderAnglesState extends SampleViewState { pointers: [ RangePointer( width: 0.1, - value: _currentValueForFirstHalfSlider, - cornerStyle: CornerStyle.endCurve, - color: const Color.fromRGBO(0, 198, 139, 1), + value: _markerValueForFirstHalfSlider, + cornerStyle: CornerStyle.bothCurve, + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValueForFirstHalfSlider, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleValueChangedForFirstHalfSlider, onValueChangeEnd: handleValueChangedForFirstHalfSlider, onValueChanging: handleValueChangingForFirstHalfSlider, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -181,13 +208,13 @@ class _RadialSliderAnglesState extends SampleViewState { annotations: [ GaugeAnnotation( widget: Text( - '$_annotationValue2' + '%', + '$_annotationValue2' '%', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, ), @@ -199,7 +226,7 @@ class _RadialSliderAnglesState extends SampleViewState { ); } - Widget _getThirdSlider() { + Widget _buildThirdSlider() { return Container( height: _size, width: _size, @@ -207,7 +234,15 @@ class _RadialSliderAnglesState extends SampleViewState { RadialAxis( radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + cornerStyle: CornerStyle.bothCurve, + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), + canScaleToFit: model.isWebFullView + ? width > height + ? true + : false + : false, showLabels: false, showTicks: false, startAngle: 270, @@ -215,24 +250,26 @@ class _RadialSliderAnglesState extends SampleViewState { pointers: [ RangePointer( width: 0.1, - value: _currentValueForPieSlider, - cornerStyle: CornerStyle.endCurve, - color: const Color.fromRGBO(0, 198, 139, 1), + value: _markerValueForPieSlider, + cornerStyle: CornerStyle.bothCurve, + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValueForPieSlider, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleValueChangedForPieSlider, onValueChangeEnd: handleValueChangedForPieSlider, onValueChanging: handleValueChangingForPieSlider, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -241,13 +278,13 @@ class _RadialSliderAnglesState extends SampleViewState { annotations: [ GaugeAnnotation( widget: Text( - '$_annotationValue3' + '%', + '$_annotationValue3' '%', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, ), @@ -259,7 +296,7 @@ class _RadialSliderAnglesState extends SampleViewState { ); } - Widget _getFourthSlider() { + Widget _buildFourthSlider() { return Container( height: _size, width: _size, @@ -267,33 +304,37 @@ class _RadialSliderAnglesState extends SampleViewState { RadialAxis( radiusFactor: 0.9, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + cornerStyle: CornerStyle.bothCurve, + color: Color.fromRGBO(88, 194, 143, 0.3), + thickness: 0.1, + thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, startAngle: 180, endAngle: 0, - canScaleToFit: true, pointers: [ RangePointer( width: 0.1, - value: _currentValueForFirstQuarterSlider, - cornerStyle: CornerStyle.endCurve, - color: const Color.fromRGBO(0, 198, 139, 1), + value: _markerValueForFirstQuarterSlider, + cornerStyle: CornerStyle.bothCurve, + color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValueForFirstQuarterSlider, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 4, + elevation: 5, + color: Color.fromRGBO(88, 194, 143, 1), + // model.currentThemeData.brightness == Brightness.light + // ? Colors.white + // : Colors.black, + // borderWidth: 4, onValueChanged: handleValueChangedForFirstQuarterSlider, onValueChangeEnd: handleValueChangedForFirstQuarterSlider, onValueChanging: handleValueChangingForFirstQuarterSlider, enableDragging: true, - borderColor: - model.currentThemeData.brightness == Brightness.light - ? Colors.black - : Colors.white, + // borderColor: + // model.currentThemeData.brightness == Brightness.light + // ? Colors.black + // : Colors.white, markerHeight: _markerSize, markerWidth: _markerSize, markerType: MarkerType.circle, @@ -302,13 +343,13 @@ class _RadialSliderAnglesState extends SampleViewState { annotations: [ GaugeAnnotation( widget: Text( - '$_annotationValue4' + '%', + '$_annotationValue4' '%', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', fontWeight: FontWeight.bold, color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, ), @@ -341,18 +382,17 @@ class _RadialSliderAnglesState extends SampleViewState { void _setPointerValue(double value) { setState(() { _markerValue = value.roundToDouble(); - _currentValue = _markerValue + 2; + _currentValue = _markerValue; _annotationValue1 = value.round().toStringAsFixed(0); }); } /// Value changing call back for pie slider. void handleValueChangingForPieSlider(ValueChangingArgs args) { - if ((args.value.round().toInt() - _markerValueForPieSlider).abs() > 20) { + if ((args.value.round().toInt() - _markerValueForPieSlider).abs() > 80) { args.cancel = true; - if (_markerValueForPieSlider > 50) { - final double value = 100; - _setPointerValueForPieSlider(value); + if (_markerValueForPieSlider > 95) { + _setPointerValueForPieSlider(100); } } } @@ -365,19 +405,18 @@ class _RadialSliderAnglesState extends SampleViewState { void _setPointerValueForPieSlider(double value) { setState(() { _markerValueForPieSlider = value.roundToDouble(); - _currentValueForPieSlider = _markerValueForPieSlider + 2; - _annotationValue3 = value.round().toStringAsFixed(0); + //_currentValueForPieSlider = _markerValueForPieSlider + 2; + _annotationValue3 = _markerValueForPieSlider.toStringAsFixed(0); }); } /// Value changing call back for first half slider. void handleValueChangingForFirstHalfSlider(ValueChangingArgs args) { if ((args.value.round().toInt() - _markerValueForFirstHalfSlider).abs() > - 20) { + 80) { args.cancel = true; - if (_markerValueForFirstHalfSlider > 50) { - final double value = 100; - _setPointerValueForHalfSlider(value); + if (_markerValueForFirstHalfSlider > 95) { + _setPointerValueForHalfSlider(100); } } } @@ -391,8 +430,8 @@ class _RadialSliderAnglesState extends SampleViewState { void _setPointerValueForHalfSlider(double value) { setState(() { _markerValueForFirstHalfSlider = value.roundToDouble(); - _currentValueForFirstHalfSlider = _markerValueForFirstHalfSlider + 2; - _annotationValue2 = value.round().toStringAsFixed(0); + //_currentValueForFirstHalfSlider = _markerValueForFirstHalfSlider + 2; + _annotationValue2 = _markerValueForFirstHalfSlider.toStringAsFixed(0); }); } @@ -407,20 +446,17 @@ class _RadialSliderAnglesState extends SampleViewState { void handleValueChangedForFirstQuarterSlider(double value) { setState(() { _markerValueForFirstQuarterSlider = value.roundToDouble(); - _currentValueForFirstQuarterSlider = - _markerValueForFirstQuarterSlider + 2; + // _currentValueForFirstQuarterSlider = + // _markerValueForFirstQuarterSlider + 2; _annotationValue4 = value.round().toStringAsFixed(0); }); } double _currentValue = 60; - double _markerValue = 58; - double _currentValueForPieSlider = 60; - double _markerValueForPieSlider = 58; - double _currentValueForFirstHalfSlider = 60; - double _markerValueForFirstHalfSlider = 58; - double _currentValueForFirstQuarterSlider = 60; - double _markerValueForFirstQuarterSlider = 58; + double _markerValue = 60; + double _markerValueForPieSlider = 60; + double _markerValueForFirstHalfSlider = 60; + double _markerValueForFirstQuarterSlider = 60; double _markerSize = 25; String _annotationValue1 = '60'; String _annotationValue2 = '60'; diff --git a/lib/samples/radial_slider/basic_features/labels_and_ticks.dart b/lib/samples/radial_slider/basic_features/labels_and_ticks.dart index 6ea10b67..24742b9a 100644 --- a/lib/samples/radial_slider/basic_features/labels_and_ticks.dart +++ b/lib/samples/radial_slider/basic_features/labels_and_ticks.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider ticks and labels. class RadialSliderLabelsTicks extends SampleView { + /// Creates the RadialSlider ticks and labels. const RadialSliderLabelsTicks(Key key) : super(key: key); @override @@ -18,6 +19,12 @@ class RadialSliderLabelsTicks extends SampleView { class _RadialSliderLabelsTicksState extends SampleViewState { _RadialSliderLabelsTicksState(); + // double _currentValue = 9; + double _markerValue = 9; + double _value = 9; + // double _firstMarkerSize = 10; + double _annotationFontSize = 25; + String _annotationValue = '9'; @override void initState() { @@ -27,37 +34,55 @@ class _RadialSliderLabelsTicksState extends SampleViewState { @override Widget build(BuildContext context) { if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 27; - _annotationFontSize = 25; + // _firstMarkerSize = 27; + _annotationFontSize = 15; } else { - _firstMarkerSize = model.isWeb ? 20 : 15; - _annotationFontSize = model.isWeb ? 25 : 15; + // _firstMarkerSize = model.isWebFullView ? 20 : 15; + _annotationFontSize = model.isWebFullView ? 25 : 15; } return Center( child: SfRadialGauge(axes: [ RadialAxis( + showFirstLabel: false, + startAngle: 270, + endAngle: 270, radiusFactor: 0.85, + minimum: 0, + maximum: 12, + interval: 3, axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), - tickOffset: 0.2, - labelOffset: 0.15, + color: Color.fromRGBO(128, 94, 246, 0.3), + thickness: 0.075, + thicknessUnit: GaugeSizeUnit.factor), + tickOffset: 0.15, + labelOffset: 0.1, offsetUnit: GaugeSizeUnit.factor, onAxisTapped: handlePointerValueChanged, - minorTicksPerInterval: 5, + minorTicksPerInterval: 30, + minorTickStyle: + MinorTickStyle(length: 0.05, lengthUnit: GaugeSizeUnit.factor), majorTickStyle: MajorTickStyle(length: 0.1, lengthUnit: GaugeSizeUnit.factor), pointers: [ RangePointer( - color: const Color.fromRGBO(0, 198, 139, 1), - value: _currentValue, - onValueChanged: handlePointerValueChanged, + color: const Color.fromRGBO(128, 94, 246, 1), + value: _markerValue, cornerStyle: CornerStyle.bothCurve, - onValueChangeEnd: handlePointerValueChanged, - onValueChanging: handlePointerValueChanging, - enableDragging: true, - width: 0.1, + width: 0.075, sizeUnit: GaugeSizeUnit.factor), + MarkerPointer( + value: _value, + elevation: 5, + markerType: MarkerType.circle, + markerHeight: 35, + markerWidth: 35, + enableDragging: true, + onValueChanged: handlePointerValueChanged, + onValueChangeEnd: handlePointerValueChanged, + onValueChanging: handlePointerValueChanging, + color: const Color.fromRGBO(128, 94, 246, 1), + ) ], annotations: [ GaugeAnnotation( @@ -69,54 +94,22 @@ class _RadialSliderLabelsTicksState extends SampleViewState { style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', - fontWeight: FontWeight.bold, + // fontWeight: FontWeight.bold, ), ), Text( - '%', + ' hrs', style: TextStyle( fontSize: _annotationFontSize, fontFamily: 'Times', - fontWeight: FontWeight.bold, + // fontWeight: FontWeight.bold, ), ) ], ), - positionFactor: 0.7, + // positionFactor: 0.7, angle: 90) ]), - // Create secondary radial axis for segmented line - RadialAxis( - interval: 20, - showLabels: false, - showTicks: true, - showAxisLine: false, - tickOffset: -0.05, - offsetUnit: GaugeSizeUnit.factor, - minorTicksPerInterval: 0, - radiusFactor: 0.85, - majorTickStyle: MajorTickStyle( - length: 0.3, - thickness: 3, - lengthUnit: GaugeSizeUnit.factor, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Color.fromRGBO(33, 33, 33, 1)), - pointers: [ - MarkerPointer( - value: _markerValue, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 7, - markerOffset: 0.0355, - offsetUnit: GaugeSizeUnit.factor, - borderColor: const Color.fromRGBO(0, 198, 139, 1), - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, - markerType: MarkerType.circle, - ), - ]), ]), ); } @@ -134,24 +127,23 @@ class _RadialSliderLabelsTicksState extends SampleViewState { /// Pointer dragging is canceled when dragging pointer value is less than 0. void handlePointerValueChanging(ValueChangingArgs args) { - if (args.value.toInt() < 0) { + if ((args.value.toInt() - _value).abs() > 2.4) { args.cancel = true; + if (_value > 6) { + final double value = 12; + _setPointerValue(value); + } } } /// method to set the pointer value void _setPointerValue(double value) { setState(() { - _currentValue = value.roundToDouble(); - final int _value = _currentValue.round().toInt(); - _annotationValue = '$_value'; - _markerValue = _currentValue; + _value = value; + _markerValue = _value; + // _currentValue = _value.roundToDouble(); + // final int _value = _currentValue.round().toInt(); + _annotationValue = '${_value.round().toInt()}'; }); } - - double _currentValue = 54; - double _markerValue = 54; - double _firstMarkerSize = 10; - double _annotationFontSize = 25; - String _annotationValue = '54'; } diff --git a/lib/samples/radial_slider/basic_features/state.dart b/lib/samples/radial_slider/basic_features/state.dart index 100c7d64..1e6b0ee8 100644 --- a/lib/samples/radial_slider/basic_features/state.dart +++ b/lib/samples/radial_slider/basic_features/state.dart @@ -10,6 +10,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider state. class RadialSliderStateTypes extends SampleView { + /// Creates the RadialSlider state. const RadialSliderStateTypes(Key key) : super(key: key); @override @@ -21,8 +22,7 @@ class _RadialSliderStateTypesState extends SampleViewState { bool _enableDragging = true; double _value = 30; - double _markerValue = 28.75; - double _annotationFontSize = 25; + double _annotationFontSize = 20; String _annotationValue = '30'; double _firstMarkerSize = 30; @override @@ -33,12 +33,11 @@ class _RadialSliderStateTypesState extends SampleViewState { @override Widget build(BuildContext context) { if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 30; - _annotationFontSize = 25; + _firstMarkerSize = 25; + _annotationFontSize = 20; } else { - _firstMarkerSize = model.isWeb ? 22 : 20; - _firstMarkerSize = model.isWeb ? 20 : 20; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 35 : 15; + _annotationFontSize = model.isWebFullView ? 20 : 15; } return Center( @@ -47,7 +46,10 @@ class _RadialSliderStateTypesState extends SampleViewState { RadialAxis( radiusFactor: 0.8, axisLineStyle: AxisLineStyle( - thickness: model.isWeb ? 0.15 : 0.25, + color: model.themeData.brightness == Brightness.light + ? Color.fromRGBO(191, 214, 245, 1) + : Color.fromRGBO(36, 58, 89, 1), + thickness: model.isWebFullView ? 0.05 : 0.075, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -55,20 +57,23 @@ class _RadialSliderStateTypesState extends SampleViewState { endAngle: 270, pointers: [ RangePointer( - width: model.isWeb ? 0.15 : 0.25, + width: model.isWebFullView ? 0.05 : 0.075, value: _value, - enableDragging: _enableDragging, cornerStyle: CornerStyle.bothCurve, - onValueChanged: handlePointerValueChanged, - onValueChangeEnd: handlePointerValueChanged, - onValueChanging: handlePointerValueChanging, color: _enableDragging - ? const Color.fromRGBO(34, 144, 199, 1) + ? const Color.fromRGBO(44, 117, 220, 1) : const Color(0xFF888888), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( - value: _markerValue, - color: Colors.white, + value: _value, + onValueChanged: handlePointerValueChanged, + onValueChangeEnd: handlePointerValueChanged, + onValueChanging: handlePointerValueChanging, + elevation: 5, + enableDragging: _enableDragging, + color: _enableDragging + ? const Color.fromRGBO(44, 117, 220, 1) + : const Color(0xFF888888), markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, markerType: MarkerType.circle, @@ -83,21 +88,21 @@ class _RadialSliderStateTypesState extends SampleViewState { '$_annotationValue', style: TextStyle( fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, + // fontFamily: 'Times', + // fontWeight: FontWeight.bold, ), ), Text( '%', style: TextStyle( fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, + // fontFamily: 'Times', + // fontWeight: FontWeight.bold, ), ) ], ), - positionFactor: 0.13, + positionFactor: 0.0, angle: 90) ]) ], @@ -151,7 +156,6 @@ class _RadialSliderStateTypesState extends SampleViewState { void _setPointerValue(double value) { setState(() { _value = value; - _markerValue = value - 1.75; int _currentValue = _value.toInt(); _currentValue = _currentValue >= 100 ? 100 : _currentValue; _annotationValue = '$_currentValue'; diff --git a/lib/samples/radial_slider/customization/custom_text.dart b/lib/samples/radial_slider/customization/custom_text.dart index 4d80391d..311e476f 100644 --- a/lib/samples/radial_slider/customization/custom_text.dart +++ b/lib/samples/radial_slider/customization/custom_text.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider custom text. class RadialSliderCustomText extends SampleView { + /// Creates the RadialSlider custom text. const RadialSliderCustomText(Key key) : super(key: key); @override @@ -26,17 +27,17 @@ class _RadialSliderCustomTextState extends SampleViewState { @override Widget build(BuildContext context) { if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 20; + _firstMarkerSize = 27; _annotationFontSize = 20; } else { - _firstMarkerSize = model.isWeb ? 25 : 20; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 28 : 12; + _annotationFontSize = model.isWebFullView ? 25 : 15; } return Center( child: SfRadialGauge(axes: [ RadialAxis( axisLineStyle: AxisLineStyle( - thickness: 0.2, + thickness: 0.07, thicknessUnit: GaugeSizeUnit.factor, cornerStyle: CornerStyle.bothCurve, ), @@ -47,17 +48,22 @@ class _RadialSliderCustomTextState extends SampleViewState { pointers: [ RangePointer( color: _rangeColor, - value: _currentValue, - onValueChanged: handlePointerValueChanged, - cornerStyle: CornerStyle.bothCurve, - onValueChangeEnd: handlePointerValueChanged, - onValueChanging: handlePointerValueChanging, - enableDragging: true, - width: 0.2, + value: _markerValue, + cornerStyle: CornerStyle.startCurve, + width: 0.07, sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValue, + overlayRadius: 0, + borderColor: _borderColor, + overlayColor: _borderColor.withOpacity(0.125), + borderWidth: model.isWebFullView ? 10 : 7, color: Colors.white, + onValueChanged: handlePointerValueChanged, + onValueChangeEnd: handlePointerValueChanged, + onValueChanging: handlePointerValueChanging, + elevation: 5, + enableDragging: true, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, markerType: MarkerType.circle, @@ -65,21 +71,21 @@ class _RadialSliderCustomTextState extends SampleViewState { ], annotations: [ GaugeAnnotation( - widget: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '$_annotationValue', - style: TextStyle( - fontSize: _annotationFontSize, - fontFamily: 'Times', - fontWeight: FontWeight.bold, - ), + widget: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '$_annotationValue', + style: TextStyle( + fontSize: _annotationFontSize, + fontFamily: 'Times', + fontWeight: FontWeight.bold, ), - ], - ), - positionFactor: 0.13, - angle: 0.5) + ), + ], + ), + positionFactor: 0.08, + ) ]) ]), ); @@ -94,12 +100,13 @@ class _RadialSliderCustomTextState extends SampleViewState { /// annotation current value. void handlePointerValueChanged(double value) { setState(() { - _currentValue = value.roundToDouble(); - final int _value = _currentValue.toInt(); + _markerValue = value; + final _value = _markerValue.round().toInt(); if (_value < 100 && _annotationValue != 'In-progress') { _annotationValue = 'In-progress'; if (_rangeColor != const Color.fromRGBO(255, 150, 0, 1)) { _rangeColor = const Color.fromRGBO(255, 150, 0, 1); + _borderColor = const Color.fromRGBO(255, 150, 0, 1); } if (_annotationColor != const Color.fromRGBO(255, 150, 0, 1)) { _annotationColor = const Color.fromRGBO(255, 150, 0, 1); @@ -108,9 +115,8 @@ class _RadialSliderCustomTextState extends SampleViewState { _annotationValue = 'Done'; _rangeColor = null; _annotationColor = const Color(0xFF00A8B5); + _borderColor = const Color(0xFF00A8B5); } - - _markerValue = _currentValue - 2; }); } @@ -121,11 +127,11 @@ class _RadialSliderCustomTextState extends SampleViewState { } } - double _currentValue = 60; - double _markerValue = 58; + double _markerValue = 60; double _firstMarkerSize = 10; double _annotationFontSize = 25; String _annotationValue = 'In-progress'; - Color _rangeColor = const Color.fromRGBO(255, 150, 0, 1); + Color? _rangeColor = const Color.fromRGBO(255, 150, 0, 1); + Color _borderColor = const Color.fromRGBO(255, 150, 0, 1); Color _annotationColor = const Color.fromRGBO(255, 150, 0, 1); } diff --git a/lib/samples/radial_slider/customization/gradient.dart b/lib/samples/radial_slider/customization/gradient.dart index a4433347..6d95fe38 100644 --- a/lib/samples/radial_slider/customization/gradient.dart +++ b/lib/samples/radial_slider/customization/gradient.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider gradient. class RadialSliderGradient extends SampleView { + /// Creates the RadialSlider gradient. const RadialSliderGradient(Key key) : super(key: key); @override @@ -24,8 +25,8 @@ class _RadialSliderGradientState extends SampleViewState { _firstMarkerSize = 30; _annotationFontSize = 25; } else { - _firstMarkerSize = model.isWeb ? 20 : 15; - _annotationFontSize = model.isWeb ? 25 : 15; + _firstMarkerSize = model.isWebFullView ? 28 : 15; + _annotationFontSize = model.isWebFullView ? 25 : 15; } return Center( child: SfRadialGauge(axes: [ @@ -38,8 +39,8 @@ class _RadialSliderGradientState extends SampleViewState { offsetUnit: GaugeSizeUnit.factor, minorTicksPerInterval: 5, onLabelCreated: (args) { - double axisValue = double.parse(args.text); - double celsiusValue = (axisValue - 32) / 1.8; + final double axisValue = double.parse(args.text); + final double celsiusValue = (axisValue - 32) / 1.8; args.text = celsiusValue.toStringAsFixed(1); }, majorTickStyle: @@ -47,7 +48,7 @@ class _RadialSliderGradientState extends SampleViewState { annotations: [ GaugeAnnotation( widget: Text( - '${_annotationValue2}°C', + '$_annotationValue2°C', style: TextStyle( fontSize: _celsiusAnnotationFontSize, fontFamily: 'Times', @@ -58,7 +59,7 @@ class _RadialSliderGradientState extends SampleViewState { ]), RadialAxis( axisLineStyle: AxisLineStyle( - thickness: 0.1, thicknessUnit: GaugeSizeUnit.factor), + thickness: 0.05, thicknessUnit: GaugeSizeUnit.factor), showTicks: false, showLabels: true, labelOffset: 20, @@ -66,30 +67,30 @@ class _RadialSliderGradientState extends SampleViewState { pointers: [ RangePointer( value: _currentValue, - onValueChanged: handlePointerValueChanged, - onValueChangeEnd: handlePointerValueChanged, - onValueChanging: handlePointerValueChanging, - enableDragging: true, - width: 0.1, + width: 0.05, cornerStyle: CornerStyle.endCurve, - gradient: model.isWeb - ? null - : const SweepGradient(colors: [ - Color.fromRGBO(115, 67, 189, 1), - Color.fromRGBO(202, 94, 230, 1) - ], stops: [ - 0.5, - 1 - ]), + gradient: const SweepGradient(colors: [ + Color.fromRGBO(115, 67, 189, 1), + Color.fromRGBO(202, 94, 230, 1) + ], stops: [ + 0.5, + 1 + ]), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( - value: _markerValue, - color: model.currentThemeData.brightness == Brightness.light + value: _currentValue, + overlayColor: Color.fromRGBO(202, 94, 230, 0.125), + onValueChanged: handlePointerValueChanged, + onValueChangeEnd: handlePointerValueChanged, + onValueChanging: handlePointerValueChanging, + enableDragging: true, + elevation: 5, + color: model.currentThemeData!.brightness == Brightness.light ? Colors.white : Colors.black, - borderWidth: 7, + borderWidth: 5, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white, markerHeight: _firstMarkerSize, @@ -124,11 +125,11 @@ class _RadialSliderGradientState extends SampleViewState { void handlePointerValueChanged(double value) { setState(() { _currentValue = value.roundToDouble(); + _markerValue = _currentValue; final int _value = _currentValue.round().toInt(); _annotationValue = '$_value'; final double _celsiusValue = (_currentValue - 32) / 1.8; _annotationValue2 = '${_celsiusValue.toStringAsFixed(1)}'; - _markerValue = _currentValue; }); } @@ -140,10 +141,11 @@ class _RadialSliderGradientState extends SampleViewState { } double _currentValue = 60; + //ignore: unused_field double _markerValue = 60; double _firstMarkerSize = 30; double _annotationFontSize = 25; - double _celsiusAnnotationFontSize = 18; + final double _celsiusAnnotationFontSize = 18; String _annotationValue = '60'; String _annotationValue2 = '${15.5556.toStringAsFixed(1)}'; } diff --git a/lib/samples/radial_slider/customization/styles.dart b/lib/samples/radial_slider/customization/styles.dart index 1a4d84b3..9f4f6ee8 100644 --- a/lib/samples/radial_slider/customization/styles.dart +++ b/lib/samples/radial_slider/customization/styles.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the RadialSlider styles. class RadialSliderStyles extends SampleView { + /// Creates the RadialSlider styles. const RadialSliderStyles(Key key) : super(key: key); @override @@ -19,7 +20,7 @@ class _RadialSliderStylesState extends SampleViewState { _RadialSliderStylesState(); double _value = 30; - String _annotationValue = '30'; + String _annotationValue = '30%'; double _annotationFontSize = 25; double _markerValue = 28; double _firstMarkerSize = 20; @@ -27,22 +28,23 @@ class _RadialSliderStylesState extends SampleViewState { double _markerWidth = 10; double _size = 150; double _borderWidth = 8; + double _thirdborderwidth = 7.5; double _value1 = 30; double _markerValue1 = 30; - String _annotationValue1 = '30'; + String _annotationValue1 = '30%'; double _value2 = 30; double _markerValue2 = 28; - String _annotationValue2 = '30'; + String _annotationValue2 = '30%'; double _value3 = 30; double _markerValue3 = 28; - String _annotationValue3 = '30'; + String _annotationValue3 = '30%'; double _value4 = 30; double _markerValue4 = 28; - String _annotationValue4 = '30'; + String _annotationValue4 = '30%'; double _value5 = 30; double _markerValue5 = 30; @@ -55,19 +57,21 @@ class _RadialSliderStylesState extends SampleViewState { @override Widget build(BuildContext context) { - Size actualSize = MediaQuery.of(context).size; + final actualSize = MediaQuery.of(context).size; if (MediaQuery.of(context).orientation == Orientation.portrait) { - _firstMarkerSize = 15; + _firstMarkerSize = 12; _secondMarkerSize = 20; + _thirdborderwidth = 7.5; _borderWidth = 5; _markerWidth = 5; _annotationFontSize = 15; } else { - _firstMarkerSize = model.isWeb ? 15 : 10; - _secondMarkerSize = model.isWeb ? 20 : 15; - _markerWidth = model.isWeb ? 5 : 3; - _borderWidth = model.isWeb ? 5 : 3; - _annotationFontSize = model.isWeb ? 15 : 12; + _firstMarkerSize = model.isWebFullView ? 15 : 10; + _secondMarkerSize = model.isWebFullView ? 20 : 15; + _markerWidth = model.isWebFullView ? 5 : 3; + _borderWidth = model.isWebFullView ? 5 : 3; + _thirdborderwidth = model.isWebFullView ? 5 : 3; + _annotationFontSize = model.isWebFullView ? 15 : 12; } if (actualSize.width > actualSize.height) { @@ -80,18 +84,18 @@ class _RadialSliderStylesState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirtProgressBar(), - _getSecondProgressBar(), - _getThirdProgressBar() + _buildFirtProgressBar(), + _buildSecondProgressBar(), + _buildThirdProgressBar() ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFourthProgressBar(), - _getFifthProgressBar(), - _getSixthProgressBar() + _buildFourthProgressBar(), + _buildFifthProgressBar(), + _buildSixthProgressBar() ], ), ], @@ -106,18 +110,18 @@ class _RadialSliderStylesState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFirtProgressBar(), - _getSecondProgressBar(), - _getThirdProgressBar() + _buildFirtProgressBar(), + _buildSecondProgressBar(), + _buildThirdProgressBar() ], ), Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getFourthProgressBar(), - _getFifthProgressBar(), - _getSixthProgressBar() + _buildFourthProgressBar(), + _buildFifthProgressBar(), + _buildSixthProgressBar() ], ), ], @@ -125,7 +129,7 @@ class _RadialSliderStylesState extends SampleViewState { } } - Widget _getFirtProgressBar() { + Widget _buildFirtProgressBar() { return Container( height: _size, width: _size, @@ -134,7 +138,7 @@ class _RadialSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(191, 214, 252, 1) : const Color.fromRGBO(36, 58, 97, 1), thickness: 0.1, @@ -148,19 +152,23 @@ class _RadialSliderStylesState extends SampleViewState { width: 0.1, value: _value, cornerStyle: CornerStyle.bothCurve, - color: model.currentThemeData.brightness == Brightness.light - ? const Color.fromRGBO(41, 118, 246, 1) - : const Color.fromRGBO(6, 102, 217, 1), + color: + model.currentThemeData!.brightness == Brightness.light + ? const Color.fromRGBO(41, 118, 246, 1) + : const Color.fromRGBO(6, 102, 217, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValue, + elevation: 5, onValueChanged: handleFirstPointerValueChanged, onValueChangeEnd: handleFirstPointerValueChanged, onValueChanging: handleFirstPointerValueChanging, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + overlayColor: Color.fromRGBO(41, 118, 246, 0.125), + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, borderWidth: _borderWidth, markerHeight: _firstMarkerSize, markerWidth: _firstMarkerSize, @@ -184,7 +192,7 @@ class _RadialSliderStylesState extends SampleViewState { ); } - Widget _getSecondProgressBar() { + Widget _buildSecondProgressBar() { return Container( height: _size, width: _size, @@ -193,7 +201,7 @@ class _RadialSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(218, 218, 218, 1) : const Color.fromRGBO(88, 88, 88, 1), thickness: 0.15, @@ -211,6 +219,7 @@ class _RadialSliderStylesState extends SampleViewState { sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValue1, + elevation: 5, onValueChanged: handleSecondPointerValueChanged, onValueChangeEnd: handleSecondPointerValueChanged, onValueChanging: handleSecondPointerValueChanging, @@ -240,7 +249,7 @@ class _RadialSliderStylesState extends SampleViewState { ); } - Widget _getThirdProgressBar() { + Widget _buildThirdProgressBar() { return Container( height: _size, width: _size, @@ -250,7 +259,7 @@ class _RadialSliderStylesState extends SampleViewState { radiusFactor: 0.85, axisLineStyle: AxisLineStyle( color: const Color.fromRGBO(254, 166, 25, 1), - thickness: 0.25, + thickness: 0.2, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -259,33 +268,36 @@ class _RadialSliderStylesState extends SampleViewState { pointers: [ RangePointer( value: 100, - pointerOffset: 0.05, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : const Color.fromRGBO(41, 37, 32, 1), - width: 0.145, + pointerOffset: 0.03, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : const Color.fromRGBO(41, 37, 32, 1), + width: 0.13, sizeUnit: GaugeSizeUnit.factor), RangePointer( - width: 0.144, - pointerOffset: 0.05, + width: 0.13, + pointerOffset: 0.03, value: _value2, color: const Color.fromRGBO(254, 166, 25, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( - value: _markerValue2, - color: model.currentThemeData.brightness == Brightness.light - ? Color.fromRGBO(255, 255, 255, 1) - : Color.fromRGBO(33, 33, 33, 1), - borderWidth: _borderWidth, - onValueChanged: handleThirdPointerValueChanged, - onValueChangeEnd: handleThirdPointerValueChanged, - onValueChanging: handleThirdPointerValueChanging, - enableDragging: true, - markerHeight: _secondMarkerSize, - markerWidth: _secondMarkerSize, - markerType: MarkerType.circle, - borderColor: const Color.fromRGBO(254, 166, 25, 1), - ) + value: _markerValue2, + elevation: 5, + color: + model.currentThemeData!.brightness == Brightness.light + ? Color.fromRGBO(255, 255, 255, 1) + : Color.fromRGBO(33, 33, 33, 1), + borderWidth: _thirdborderwidth, + onValueChanged: handleThirdPointerValueChanged, + onValueChangeEnd: handleThirdPointerValueChanged, + onValueChanging: handleThirdPointerValueChanging, + enableDragging: true, + markerHeight: _secondMarkerSize, + markerWidth: _secondMarkerSize, + markerType: MarkerType.circle, + borderColor: const Color.fromRGBO(254, 166, 25, 1), + overlayColor: const Color.fromRGBO(254, 166, 25, 0.125)) ], annotations: [ GaugeAnnotation( @@ -305,7 +317,7 @@ class _RadialSliderStylesState extends SampleViewState { ); } - Widget _getFourthProgressBar() { + Widget _buildFourthProgressBar() { return Container( height: _size, width: _size, @@ -314,10 +326,10 @@ class _RadialSliderStylesState extends SampleViewState { RadialAxis( radiusFactor: 0.85, axisLineStyle: AxisLineStyle( - color: model.currentThemeData.brightness == Brightness.light + color: model.currentThemeData!.brightness == Brightness.light ? const Color.fromRGBO(201, 201, 201, 1) - : const Color.fromRGBO(78, 78, 78, 1), - thickness: 0.15, + : const Color.fromRGBO(97, 97, 97, 1), + thickness: 0.24, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -327,40 +339,46 @@ class _RadialSliderStylesState extends SampleViewState { RangePointer( value: 100, pointerOffset: 0.03, - width: 0.09, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, + width: 0.18, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, sizeUnit: GaugeSizeUnit.factor), RangePointer( - width: 0.05, - pointerOffset: 0.05, + width: 0.08, + pointerOffset: 0.08, value: _value3, cornerStyle: CornerStyle.bothCurve, color: const Color.fromRGBO(88, 194, 143, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValue3, + elevation: 5, + overlayColor: Color.fromRGBO(88, 194, 143, 0.125), onValueChanged: handleFourthPointerValueChanged, onValueChanging: handleFourthPointerValueChanging, enableDragging: true, - color: model.currentThemeData.brightness == Brightness.light - ? Colors.white - : Colors.black, - borderWidth: 3, - markerHeight: _firstMarkerSize, - markerWidth: _firstMarkerSize, + color: + model.currentThemeData!.brightness == Brightness.light + ? Colors.white + : Colors.black, + borderWidth: 4, + markerHeight: 20, + markerWidth: 20, markerType: MarkerType.circle, borderColor: Color.fromRGBO(88, 194, 143, 1)), MarkerPointer( value: _markerValue3, + // elevation: 5, onValueChanged: handleFourthPointerValueChanged, onValueChanging: handleFourthPointerValueChanging, enableDragging: true, color: Color.fromRGBO(88, 194, 143, 1), - borderWidth: 1, - markerHeight: 7, - markerWidth: 7, + borderWidth: 2, + markerHeight: 9, + markerWidth: 9, + overlayRadius: 0, markerType: MarkerType.circle, borderColor: Color.fromRGBO(88, 194, 143, 1)), ], @@ -382,17 +400,17 @@ class _RadialSliderStylesState extends SampleViewState { ); } - Widget _getFifthProgressBar() { + Widget _buildFifthProgressBar() { return Container( height: _size, width: _size, child: SfRadialGauge( axes: [ RadialAxis( - radiusFactor: 0.8, + radiusFactor: 0.85, axisLineStyle: AxisLineStyle( color: Color.fromRGBO(41, 118, 246, 1), - thickness: 0.3, + thickness: 0.24, thicknessUnit: GaugeSizeUnit.factor), showLabels: false, showTicks: false, @@ -400,21 +418,22 @@ class _RadialSliderStylesState extends SampleViewState { endAngle: 270, pointers: [ RangePointer( - pointerOffset: 0.075, - width: 0.15, + pointerOffset: 0.065, + width: 0.1, value: _value4, cornerStyle: CornerStyle.bothCurve, color: const Color.fromRGBO(254, 166, 25, 1), sizeUnit: GaugeSizeUnit.factor), MarkerPointer( value: _markerValue4, + // elevation: 5, color: const Color.fromRGBO(254, 166, 25, 1), - markerHeight: _firstMarkerSize, + markerHeight: 15, onValueChanged: handleFifthPointerValueChanged, onValueChangeEnd: handleFifthPointerValueChanged, onValueChanging: handleFifthPointerValueChanging, enableDragging: true, - markerWidth: _firstMarkerSize, + markerWidth: 15, markerType: MarkerType.circle, borderColor: const Color.fromRGBO(34, 144, 199, 0.75)) ], @@ -436,7 +455,7 @@ class _RadialSliderStylesState extends SampleViewState { ); } - Widget _getSixthProgressBar() { + Widget _buildSixthProgressBar() { return Container( height: _size, width: _size, @@ -456,27 +475,27 @@ class _RadialSliderStylesState extends SampleViewState { NeedlePointer( value: _markerValue5, needleColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), needleEndWidth: 1.5, needleStartWidth: 1.5, - needleLength: 0.72, + needleLength: 0.82, knobStyle: KnobStyle( - knobRadius: model.isWeb ? 0.4 : 0.3, + knobRadius: model.isWebFullView ? 0.4 : 0.3, borderWidth: 0.05, borderColor: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Color.fromRGBO(65, 65, 65, 1) : Color.fromRGBO(191, 191, 191, 1), color: - model.currentThemeData.brightness == Brightness.light + model.currentThemeData!.brightness == Brightness.light ? Colors.white : const Color.fromRGBO(33, 33, 33, 1), )), RangePointer( - width: 0.07, - pointerOffset: 0.27, + width: 0.15, + pointerOffset: 0.17, value: _value5, onValueChanged: handleSixthPointerValueChanged, onValueChangeEnd: handleSixthPointerValueChanged, @@ -493,7 +512,7 @@ class _RadialSliderStylesState extends SampleViewState { fontSize: 12, fontFamily: 'Times', fontWeight: FontWeight.bold, - color: model.currentThemeData.brightness == + color: model.currentThemeData!.brightness == Brightness.light ? Colors.black : Colors.white), @@ -532,7 +551,7 @@ class _RadialSliderStylesState extends SampleViewState { _markerValue = value.roundToDouble(); _value = (_markerValue + 2); final int _currentValue = _markerValue.round().toInt(); - _annotationValue = '$_currentValue'; + _annotationValue = '$_currentValue%'; }); } @@ -558,7 +577,7 @@ class _RadialSliderStylesState extends SampleViewState { _markerValue1 = value.roundToDouble(); _value1 = (_markerValue1); final int _currentValue = _markerValue1.round().toInt(); - _annotationValue1 = '$_currentValue'; + _annotationValue1 = '$_currentValue%'; }); } @@ -586,7 +605,7 @@ class _RadialSliderStylesState extends SampleViewState { _markerValue2 = value.roundToDouble(); _value2 = (_markerValue2 + 2); final int _currentValue = _markerValue2.round().toInt(); - _annotationValue2 = '$_currentValue'; + _annotationValue2 = '$_currentValue%'; }); } @@ -614,7 +633,7 @@ class _RadialSliderStylesState extends SampleViewState { _markerValue3 = value; _value3 = (_markerValue3 + 2); final int _currentValue = _markerValue3.round().toInt(); - _annotationValue3 = '$_currentValue'; + _annotationValue3 = '$_currentValue%'; }); } @@ -642,7 +661,7 @@ class _RadialSliderStylesState extends SampleViewState { _markerValue4 = value.roundToDouble(); _value4 = (_markerValue4 + 2); final int _currentValue = _markerValue4.round().toInt(); - _annotationValue4 = '$_currentValue'; + _annotationValue4 = '$_currentValue%'; }); } diff --git a/lib/samples/radial_slider/customization/thumb.dart b/lib/samples/radial_slider/customization/thumb.dart index 57cfc81a..159c37d3 100644 --- a/lib/samples/radial_slider/customization/thumb.dart +++ b/lib/samples/radial_slider/customization/thumb.dart @@ -9,6 +9,7 @@ import '../../../model/sample_view.dart'; /// Widget of the radial slider thumb customization. class RadialSliderThumb extends SampleView { + /// Creates radial slider thumb customization. const RadialSliderThumb(Key key) : super(key: key); @override @@ -31,76 +32,50 @@ class _RadialSliderThumbState extends SampleViewState { Widget build(BuildContext context) { if (MediaQuery.of(context).size.height > MediaQuery.of(context).size.width) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 3.5 : MediaQuery.of(context).size.height / 5; return Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - getSliderWithImage(), - Center(child: Text('Image thumb')), - ] - : [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')) - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithCircle(), + Center(child: Text('Circle thumb')), + _buildSliderWithRectangle(), + Center(child: Text('Rectangle thumb')), + _buildSliderWithImage(), + Center(child: Text('Image thumb')), + ])); } else { _size = MediaQuery.of(context).size.width / 4.5; return Center( child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: !model.isWeb - ? [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithImage(), - Center(child: Text('Image thumb')), - ]), - ] - : [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithCircle(), - Center(child: Text('Circle thumb')), - ]), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - getSliderWithRectangle(), - Center(child: Text('Rectangle thumb')), - ]), - ], - )); + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithCircle(), + Center(child: Text('Circle thumb')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithRectangle(), + Center(child: Text('Rectangle thumb')), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSliderWithImage(), + Center(child: Text('Image thumb')), + ]), + ])); } } @@ -110,7 +85,7 @@ class _RadialSliderThumbState extends SampleViewState { } /// Returns gradient progress style circular progress bar. - Widget getSliderWithCircle() { + Widget _buildSliderWithCircle() { return Container( height: _size, width: _size, @@ -130,18 +105,20 @@ class _RadialSliderThumbState extends SampleViewState { value: _progressValue1, width: 0.1, sizeUnit: GaugeSizeUnit.factor, - color: model.isWeb ? Color.fromRGBO(197, 91, 226, 1) : null, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ])), + color: model.isWebFullView + ? Color.fromRGBO(197, 91, 226, 1) + : null, + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ])), MarkerPointer( value: _progressValue1, + elevation: 5, + overlayRadius: 0, markerType: MarkerType.circle, markerHeight: 25, markerWidth: 25, @@ -160,7 +137,7 @@ class _RadialSliderThumbState extends SampleViewState { } /// Returns gradient progress style circular progress bar. - Widget getSliderWithRectangle() { + Widget _buildSliderWithRectangle() { return Container( height: _size, width: _size, @@ -180,18 +157,20 @@ class _RadialSliderThumbState extends SampleViewState { value: _progressValue2, width: 0.1, sizeUnit: GaugeSizeUnit.factor, - color: model.isWeb ? Color.fromRGBO(197, 91, 226, 1) : null, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ])), + color: model.isWebFullView + ? Color.fromRGBO(197, 91, 226, 1) + : null, + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ])), MarkerPointer( value: _progressValue2, + elevation: 5, + overlayRadius: 0, markerType: MarkerType.rectangle, markerHeight: 25, markerWidth: 25, @@ -210,7 +189,7 @@ class _RadialSliderThumbState extends SampleViewState { } /// Returns gradient progress style circular progress bar. - Widget getSliderWithImage() { + Widget _buildSliderWithImage() { return Container( height: _size, width: _size, @@ -230,21 +209,20 @@ class _RadialSliderThumbState extends SampleViewState { value: _progressValue3, width: 0.1, sizeUnit: GaugeSizeUnit.factor, - gradient: model.isWeb - ? null - : SweepGradient(colors: [ - const Color.fromRGBO(197, 91, 226, 1), - const Color.fromRGBO(115, 67, 189, 1) - ], stops: [ - 0.5, - 1 - ])), + gradient: SweepGradient(colors: [ + const Color.fromRGBO(197, 91, 226, 1), + const Color.fromRGBO(115, 67, 189, 1) + ], stops: [ + 0.5, + 1 + ])), MarkerPointer( value: _progressValue3, + elevation: 5, markerType: MarkerType.image, imageUrl: 'images/ball.png', - markerHeight: model.isWeb ? 15 : 30, - markerWidth: model.isWeb ? 15 : 30, + markerHeight: model.isWebFullView ? 30 : 30, + markerWidth: model.isWebFullView ? 30 : 30, enableDragging: true, onValueChanged: handleThirdPointerValueChanged, onValueChanging: handleThirdPointerValueChanging, diff --git a/lib/samples/signature_pad/getting_started/signature_pad_getting_started.dart b/lib/samples/signature_pad/getting_started/signature_pad_getting_started.dart index e5bd547f..4e9fd56b 100644 --- a/lib/samples/signature_pad/getting_started/signature_pad_getting_started.dart +++ b/lib/samples/signature_pad/getting_started/signature_pad_getting_started.dart @@ -1,26 +1,22 @@ -import 'package:flutter/material.dart'; +import 'dart:typed_data'; +import 'dart:ui' as ui; ///Package import import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:syncfusion_flutter_sliders/sliders.dart'; -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:syncfusion_flutter_core/theme.dart'; -import 'dart:ui' as ui; -import 'dart:typed_data'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + +///Signature pad imports. +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; +import 'package:syncfusion_flutter_sliders/sliders.dart'; /// Local imports import '../../../model/sample_view.dart'; import '../shared/mobile_image_converter.dart' if (dart.library.html) '../shared/web_image_converter.dart'; -///Signature pad imports. -import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; - -List<_Product> _products = <_Product>[]; - -final _ProductDataSource _productDataSource = _ProductDataSource(); - ///Renders the signature pad widget. class GettingStartedSignaturePad extends SampleView { /// Creates getting started signature pad. @@ -33,35 +29,41 @@ class GettingStartedSignaturePad extends SampleView { class _GettingStartedSignaturePadState extends SampleViewState { final GlobalKey _signaturePadKey = GlobalKey(); - List _strokeColorWidgets; + List _strokeColors = []; double _minWidth = 1.0; double _maxWidth = 4.0; bool _isSigned = false; int _selectedPenIndex = 0; - Color _strokeColor; - Color _backgroundColor; - Uint8List _signatureData; - double _fontSizeRegular = 12; bool _isDark = false; + late Color _strokeColor; + Color? _backgroundColor; + late Uint8List _signatureData; + final double _fontSizeRegular = 12; + late _ProductDataSource _productDataSource; + late List _strokeColorWidgets; + late bool _isWebOrDesktop; + @override void initState() { _addColors(); - _loadDataSource(); + _productDataSource = _ProductDataSource(_loadDataSource()); _minWidth = kIsWeb ? 2.0 : 1.0; _maxWidth = kIsWeb ? 2.0 : 4.0; + _isWebOrDesktop = (defaultTargetPlatform == TargetPlatform.windows || + defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.macOS || + kIsWeb); super.initState(); } - void _loadDataSource() { - _products = <_Product>[]; - _products.add( - _Product(name: 'Jersey', price: 49.99, quantity: 3, total: 149.97)); - _products.add( - _Product(name: 'AWC Logo Cap', price: 8.99, quantity: 2, total: 17.98)); - _products.add( - _Product(name: 'ML Fork ', price: 175.49, quantity: 6, total: 1052.94)); + List<_Product> _loadDataSource() { + return [ + _Product(name: 'Jersey', price: 49.99, quantity: 3, total: 149.97), + _Product(name: 'AWC Logo Cap', price: 8.99, quantity: 2, total: 17.98), + _Product(name: 'ML Fork ', price: 175.49, quantity: 6, total: 1052.94) + ]; } void _addColors() { @@ -77,37 +79,38 @@ class _GettingStartedSignaturePadState extends SampleViewState { for (int i = 0; i < _strokeColors.length; i++) { _strokeColorWidgets.add( Material( - child: Ink( - decoration: BoxDecoration( - color: Colors.transparent, - shape: BoxShape.circle, + color: Colors.transparent, + child: Ink( + decoration: BoxDecoration( + color: Colors.transparent, + shape: BoxShape.circle, + ), + child: InkWell( + onTap: () => stateChanged( + () { + _strokeColor = _strokeColors[i]; + _selectedPenIndex = i; + }, ), - child: InkWell( - onTap: () => stateChanged( - () { - _strokeColor = _strokeColors[i]; - _selectedPenIndex = i; - }, - ), - child: Center( - child: Stack( - children: [ - Icon(Icons.brightness_1, - size: 25.0, color: _strokeColors[i]), - _selectedPenIndex != null && _selectedPenIndex == i - ? Padding( - child: Icon(Icons.check, - size: 15.0, - color: _isDark ? Colors.black : Colors.white), - padding: EdgeInsets.all(5), - ) - : SizedBox(width: 8), - ], - ), + child: Center( + child: Stack( + children: [ + Icon(Icons.brightness_1, + size: 25.0, color: _strokeColors[i]), + _selectedPenIndex != null && _selectedPenIndex == i + ? Padding( + padding: EdgeInsets.all(5), + child: Icon(Icons.check, + size: 15.0, + color: _isDark ? Colors.black : Colors.white), + ) + : SizedBox(width: 8), + ], ), ), ), - color: Colors.transparent), + ), + ), ); } @@ -121,7 +124,7 @@ class _GettingStartedSignaturePadState extends SampleViewState { void _showPopup() { _isSigned = false; - if (kIsWeb) { + if (_isWebOrDesktop) { _backgroundColor = _isDark ? model.webBackgroundColor : Colors.white; } @@ -130,97 +133,116 @@ class _GettingStartedSignaturePadState extends SampleViewState { builder: (context) { return StatefulBuilder( builder: (context, setState) { - final Color backgroundColor = _backgroundColor; + final Color? backgroundColor = _backgroundColor; final Color textColor = _isDark ? Colors.white : Colors.black87; return AlertDialog( insetPadding: EdgeInsets.all(12.0), backgroundColor: backgroundColor, - title: Row(children: [ - Text('Draw your signature', - style: TextStyle( - color: textColor, - fontSize: 16, - fontWeight: FontWeight.w500, - fontFamily: 'Roboto-Medium')), - InkWell( - child: Icon(Icons.clear, - color: _isDark - ? Colors.grey[400] - : Color.fromRGBO(0, 0, 0, 0.54), - size: 24.0), - //ignore: sdk_version_set_literal - onTap: () => {Navigator.of(context).pop()}, - ) - ], mainAxisAlignment: MainAxisAlignment.spaceBetween), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Draw your signature', + style: TextStyle( + color: textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + fontFamily: 'Roboto-Medium')), + InkWell( + //ignore: sdk_version_set_literal + onTap: () => {Navigator.of(context).pop()}, + child: Icon(Icons.clear, + color: _isDark + ? Colors.grey[400] + : Color.fromRGBO(0, 0, 0, 0.54), + size: 24.0), + ) + ], + ), titlePadding: EdgeInsets.all(16.0), content: SingleChildScrollView( child: Container( - child: Column(children: [ + width: MediaQuery.of(context).size.width < 306 + ? MediaQuery.of(context).size.width + : 306, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ Container( - child: SfSignaturePad( - minimumStrokeWidth: _minWidth, - maximumStrokeWidth: _maxWidth, - strokeColor: _strokeColor, - backgroundColor: _backgroundColor, - onSignStart: _handleOnSignStart, - key: _signaturePadKey), width: MediaQuery.of(context).size.width < 306 ? MediaQuery.of(context).size.width : 306, height: 172, decoration: BoxDecoration( border: - Border.all(color: _getBorderColor(), width: 1), + Border.all(color: _getBorderColor()!, width: 1), ), + child: SfSignaturePad( + minimumStrokeWidth: _minWidth, + maximumStrokeWidth: _maxWidth, + strokeColor: _strokeColor, + backgroundColor: _backgroundColor, + onSignStart: _handleOnSignStart, + key: _signaturePadKey), ), SizedBox(height: 24), - Row(children: [ - Text( - 'Pen Color', - style: TextStyle( - color: textColor, - fontWeight: FontWeight.w400, - fontFamily: 'Roboto-Regular'), - ), - Container( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Pen Color', + style: TextStyle( + color: textColor, + fontWeight: FontWeight.w400, + fontFamily: 'Roboto-Regular'), + ), + Container( + width: 124, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: _addStrokeColorPalettes(setState), ), - width: 124) - ], mainAxisAlignment: MainAxisAlignment.spaceBetween), - ], mainAxisAlignment: MainAxisAlignment.center), - width: MediaQuery.of(context).size.width < 306 - ? MediaQuery.of(context).size.width - : 306), + ) + ], + ), + ], + ), + ), ), contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 12.0), actionsPadding: EdgeInsets.all(8.0), buttonPadding: EdgeInsets.zero, actions: [ - FlatButton( - onPressed: _handleClearButtonPressed, - child: const Text( - 'CLEAR', + TextButton( + onPressed: _handleClearButtonPressed, + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all( + model.currentPaletteColor), + ), + child: const Text( + 'CLEAR', + style: TextStyle( + fontWeight: FontWeight.w500, + fontFamily: 'Roboto-Medium'), + ), + ), + SizedBox(width: 8.0), + TextButton( + onPressed: () { + _handleSaveButtonPressed(); + Navigator.of(context).pop(); + }, + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all( + model.currentPaletteColor), + ), + child: const Text('SAVE', style: TextStyle( fontWeight: FontWeight.w500, - fontFamily: 'Roboto-Medium'), - ), - textColor: model.currentPaletteColor), - SizedBox(width: 8.0), - FlatButton( - onPressed: () { - _handleSaveButtonPressed(); - Navigator.of(context).pop(); - }, - child: const Text('SAVE', - style: TextStyle( - fontWeight: FontWeight.w500, - fontFamily: 'Roboto-Medium')), - textColor: model.currentPaletteColor) + fontFamily: 'Roboto-Medium')), + ) ], ); }, @@ -230,24 +252,25 @@ class _GettingStartedSignaturePadState extends SampleViewState { } void _handleClearButtonPressed() { - _signaturePadKey.currentState.clear(); + _signaturePadKey.currentState!.clear(); _isSigned = false; } void _handleSaveButtonPressed() async { - Uint8List data; + late Uint8List data; if (kIsWeb) { - RenderSignaturePad renderSignaturePad = - _signaturePadKey.currentState.context.findRenderObject(); + final RenderSignaturePad renderSignaturePad = + // ignore: avoid_as + _signaturePadKey.currentState!.context.findRenderObject() + as RenderSignaturePad; data = await ImageConverter.toImage(renderSignaturePad: renderSignaturePad); } else { final imageData = - await _signaturePadKey.currentState.toImage(pixelRatio: 3.0); - if (imageData != null) { - final bytes = - await imageData.toByteData(format: ui.ImageByteFormat.png); + await _signaturePadKey.currentState!.toImage(pixelRatio: 3.0); + final bytes = await imageData.toByteData(format: ui.ImageByteFormat.png); + if (bytes != null) { data = bytes.buffer.asUint8List(); } } @@ -261,6 +284,7 @@ class _GettingStartedSignaturePadState extends SampleViewState { Widget _getInvoiceHeader() { return Container( + height: 60, child: Center( child: Text( 'INVOICE', @@ -270,77 +294,110 @@ class _GettingStartedSignaturePadState extends SampleViewState { fontWeight: FontWeight.bold), ), ), - height: 60, ); } Widget _getProductDetails() { return Column(children: [ Container( - child: IgnorePointer( - child: SfDataGridTheme( - data: SfDataGridThemeData( - headerStyle: DataGridHeaderCellStyle( - textStyle: TextStyle( + padding: EdgeInsets.all(20), + height: 250, + child: IgnorePointer( + ignoring: true, + child: SfDataGridTheme( + data: SfDataGridThemeData( + brightness: _isDark ? Brightness.dark : Brightness.light, + headerColor: Colors.transparent, + gridLineStrokeWidth: 1, + gridLineColor: _isDark ? Colors.grey[850] : Colors.grey[200], + ), + child: SfDataGrid( + source: _productDataSource, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + GridTextColumn( + columnName: 'name', + label: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(10.0, 5.0, 0, 5.0), + color: Colors.transparent, + child: Text( + 'Product', + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle( fontWeight: FontWeight.bold, color: _getTextColor()), - backgroundColor: Colors.transparent), - gridLineStrokeWidth: 1, - gridLineColor: _isDark ? Colors.grey[850] : Colors.grey[200], - cellStyle: DataGridCellStyle( - textStyle: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - backgroundColor: Colors.transparent), + ), + ), ), - child: SfDataGrid( - source: _productDataSource, - columnWidthMode: ColumnWidthMode.fill, - columns: [ - GridTextColumn( - mappingName: 'name', - headerText: 'Product', - columnWidthMode: ColumnWidthMode.cells, - headerTextSoftWrap: true, - headerTextOverflow: TextOverflow.clip, - padding: EdgeInsets.fromLTRB(10.0, 5.0, 0, 5.0)), - GridNumericColumn( - mappingName: 'price', - headerText: 'Price', - headerTextSoftWrap: true, - headerTextOverflow: TextOverflow.clip), - GridNumericColumn( - mappingName: 'quantity', - headerText: 'Quantity', - headerTextSoftWrap: true, - headerTextOverflow: TextOverflow.clip, - padding: EdgeInsets.all(8)), - GridNumericColumn( - mappingName: 'total', - headerText: 'Total', - headerTextSoftWrap: true, - headerTextOverflow: TextOverflow.clip) - ], + GridTextColumn( + columnName: 'price', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + color: Colors.transparent, + child: Text( + 'Price', + overflow: TextOverflow.clip, + softWrap: true, + style: TextStyle( + fontWeight: FontWeight.bold, color: _getTextColor()), + ), + ), ), - ), - ignoring: true), - padding: EdgeInsets.all(20), - height: 250), - Align( - child: Padding( - padding: EdgeInsets.fromLTRB(0.0, 0, 20.0, 0), - child: Text('Grand Total : \$1220.89', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - color: _getTextColor(), - fontWeight: FontWeight.w900), - textAlign: TextAlign.end), + GridTextColumn( + columnName: 'quantity', + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + color: Colors.transparent, + child: Text( + 'Quantity', + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle( + fontWeight: FontWeight.bold, color: _getTextColor()), + ), + ), + ), + GridTextColumn( + columnName: 'total', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.centerRight, + color: Colors.transparent, + child: Text( + 'Total', + overflow: TextOverflow.clip, + softWrap: true, + style: TextStyle( + fontWeight: FontWeight.bold, color: _getTextColor()), + ), + ), + ) + ], + ), ), - alignment: Alignment.centerRight), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: EdgeInsets.fromLTRB(0.0, 0, 20.0, 0), + child: Text('Grand Total : \$1220.89', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, + color: _getTextColor(), + fontWeight: FontWeight.w900), + textAlign: TextAlign.end), + ), + ), ]); } - Color _getTextColor() => _isDark ? Colors.grey[400] : Colors.grey[700]; - Color _getBorderColor() => _isDark ? Colors.grey[500] : Colors.grey[350]; + Color? _getTextColor() => _isDark ? Colors.grey[400] : Colors.grey[700]; + Color? _getBorderColor() => _isDark ? Colors.grey[500] : Colors.grey[350]; Widget _getBillingDetails() { final DateTime now = DateTime.now(); @@ -348,133 +405,135 @@ class _GettingStartedSignaturePadState extends SampleViewState { final String formattedTime = formatter.format(now); return Container( - child: Padding( - child: Row( + height: 150, + child: Padding( + padding: EdgeInsets.all(20.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( - children: [ - Text( - 'Bill To:', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - color: _getTextColor(), - fontWeight: FontWeight.bold), - ), - SizedBox(height: 2), - Text( - 'Abraham Swearegin,', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - ), - Text( - '9920 Bridge Parkway,', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - ), - Text( - 'San Mateo, California,', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - ), - Text( - 'United States.', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - ), - Text( - '9365550136', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, color: _getTextColor()), - ), - ], - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, + Text( + 'Bill To:', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, + color: _getTextColor(), + fontWeight: FontWeight.bold), + ), + SizedBox(height: 2), + Text( + 'Abraham Swearegin,', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + ), + Text( + '9920 Bridge Parkway,', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + ), + Text( + 'San Mateo, California,', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + ), + Text( + 'United States.', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + ), + Text( + '9365550136', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), ), - Column( - children: [ - Text('Invoice No: 2058557939', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - color: _getTextColor()), - textAlign: TextAlign.end), - SizedBox(height: 5), - Text("Date: " + formattedTime, - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - color: _getTextColor()), - textAlign: TextAlign.end), - ], - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end) ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start), - padding: EdgeInsets.all(20.0), + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text('Invoice No: 2058557939', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + textAlign: TextAlign.end), + SizedBox(height: 5), + Text('Date: ' + formattedTime, + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + textAlign: TextAlign.end), + ], + ) + ], ), - height: 150); + ), + ); } Widget _getBottomView() { return Expanded( child: Container( - child: Row( - children: [ - InkWell( - child: Container( - decoration: BoxDecoration( - border: Border.all(color: _getBorderColor()), - ), - child: _isSigned - ? Image.memory(_signatureData) - : Center( - child: Text( - 'Tap here to sign', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - fontWeight: FontWeight.bold, - color: _getTextColor()), - ), - ), - height: 78, - width: 138, - ), - splashColor: Colors.transparent, - highlightColor: Colors.transparent, - //ignore: sdk_version_set_literal - onTap: () => {_showPopup()}, + padding: EdgeInsets.fromLTRB(20.0, 20, 20.0, 10), + color: Colors.transparent, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + //ignore: sdk_version_set_literal + onTap: () => {_showPopup()}, + child: Container( + decoration: BoxDecoration( + border: Border.all(color: _getBorderColor()!), ), - Column( - children: [ - Text('800 Interchange Blvd.', + height: 78, + width: 138, + child: _isSigned + ? Image.memory(_signatureData) + : Center( + child: Text( + 'Tap here to sign', textScaleFactor: 1.0, style: TextStyle( fontSize: _fontSizeRegular, + fontWeight: FontWeight.bold, color: _getTextColor()), - textAlign: TextAlign.end), - SizedBox(height: 5), - Text('Austin, TX 78721', - textScaleFactor: 1.0, - style: TextStyle( - fontSize: _fontSizeRegular, - color: _getTextColor()), - textAlign: TextAlign.end), - ], - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end) - ], + ), + ), + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.spaceBetween), - padding: EdgeInsets.fromLTRB(20.0, 20, 20.0, 10), - color: Colors.transparent), + children: [ + Text('800 Interchange Blvd.', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + textAlign: TextAlign.end), + SizedBox(height: 5), + Text('Austin, TX 78721', + textScaleFactor: 1.0, + style: TextStyle( + fontSize: _fontSizeRegular, color: _getTextColor()), + textAlign: TextAlign.end), + ], + ) + ], + ), + ), ); } @@ -483,48 +542,48 @@ class _GettingStartedSignaturePadState extends SampleViewState { final double _screenWidth = MediaQuery.of(context).size.width; //ignore: unused_local_variable final double _screenHeight = MediaQuery.of(context).size.height; - _isDark = model.themeData.brightness == Brightness.dark; + _isDark = _productDataSource.isDark = + Theme.of(context).brightness == Brightness.dark; _strokeColors[0] = _isDark ? const Color.fromRGBO(255, 255, 255, 1) : const Color.fromRGBO(0, 0, 0, 1); _strokeColor = _strokeColors[_selectedPenIndex]; return Container( - child: Center( - child: SingleChildScrollView( - child: Container( - child: Column(children: [ - _getInvoiceHeader(), - _getBillingDetails(), - _getProductDetails(), - _getBottomView() - ]), - width: - kIsWeb ? 500 : (_screenWidth > 400 ? 400 : _screenWidth), - height: 625, - margin: kIsWeb ? EdgeInsets.all(10.0) : null, - decoration: kIsWeb - ? BoxDecoration( - color: - _isDark ? model.webBackgroundColor : Colors.white, - borderRadius: BorderRadius.all(Radius.circular(10)), - boxShadow: [ - BoxShadow( - color: _isDark - ? Colors.black.withOpacity(0.3) - : Colors.grey.withOpacity(0.3), - spreadRadius: 5, - blurRadius: 7, - offset: - Offset(0, 3), // changes position of shadow - ), - ], - ) - : null)), - ), - color: _isDark - ? Colors.transparent - : const Color.fromRGBO(250, 250, 250, 1)); + color: + _isDark ? Colors.transparent : const Color.fromRGBO(250, 250, 250, 1), + child: Center( + child: SingleChildScrollView( + child: Container( + width: + _isWebOrDesktop ? 500 : (_screenWidth > 400 ? 400 : _screenWidth), + height: 625, + margin: _isWebOrDesktop ? EdgeInsets.all(10.0) : null, + decoration: _isWebOrDesktop + ? BoxDecoration( + color: _isDark ? model.webBackgroundColor : Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)), + boxShadow: [ + BoxShadow( + color: _isDark + ? Colors.black.withOpacity(0.3) + : Colors.grey.withOpacity(0.3), + spreadRadius: 5, + blurRadius: 7, + offset: Offset(0, 3), // changes position of shadow + ), + ], + ) + : null, + child: Column(children: [ + _getInvoiceHeader(), + _getBillingDetails(), + _getProductDetails(), + _getBottomView() + ]), + )), + ), + ); } @override @@ -533,11 +592,12 @@ class _GettingStartedSignaturePadState extends SampleViewState { builder: (BuildContext context, StateSetter stateSetter) { return ListView(shrinkWrap: true, children: [ Padding( - child: Text( - 'Minimum Width', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - padding: EdgeInsets.fromLTRB(5, 0, 0, 0)), + padding: EdgeInsets.fromLTRB(5, 0, 0, 0), + child: Text( + 'Minimum Width', + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), + ), SizedBox(height: 4), SfSliderTheme( data: SfSliderThemeData( @@ -570,11 +630,12 @@ class _GettingStartedSignaturePadState extends SampleViewState { )), SizedBox(height: 16), Padding( - child: Text( - 'Maximum Width', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - padding: EdgeInsets.fromLTRB(5, 0, 0, 0)), + padding: EdgeInsets.fromLTRB(5, 0, 0, 0), + child: Text( + 'Maximum Width', + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), + ), SizedBox(height: 4), SfSliderTheme( data: SfSliderThemeData( @@ -613,9 +674,11 @@ class _GettingStartedSignaturePadState extends SampleViewState { class _Product { const _Product( - {this.productId, this.name, this.price, this.quantity, this.total}); + {required this.name, + required this.price, + required this.quantity, + required this.total}); - final String productId; final String name; final double price; final int quantity; @@ -623,30 +686,87 @@ class _Product { } class _ProductDataSource extends DataGridSource { + _ProductDataSource(List<_Product> products) { + _products = products.map((e) { + return DataGridRow(cells: [ + DataGridCell( + columnName: 'name', + value: e.name, + ), + DataGridCell( + columnName: 'price', + value: e.price, + ), + DataGridCell( + columnName: 'quantity', + value: e.quantity, + ), + DataGridCell( + columnName: 'total', + value: e.total, + ), + ]); + }).toList(); + } + + late bool isDark; + + late List _products; + @override - List get dataSource => _products; + List get rows => _products; + + Color? _getTextColor() => isDark ? Colors.grey[400] : Colors.grey[700]; + + final double _fontSizeRegular = 12; @override - getCellValue(int rowIndex, String columnName) { - switch (columnName) { - case 'productId': - return _products[rowIndex].productId; - break; - case 'name': - return _products[rowIndex].name; - break; - case 'price': - return _products[rowIndex].price; - break; - case 'quantity': - return _products[rowIndex].quantity; - break; - case 'total': - return _products[rowIndex].total; - break; - default: - return ' '; - break; - } + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.fromLTRB(10.0, 5.0, 0, 5.0), + color: Colors.transparent, + child: Text( + row.getCells()[0].value.toString(), + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle(fontSize: _fontSizeRegular, color: _getTextColor()), + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + color: Colors.transparent, + child: Text( + row.getCells()[1].value.toString(), + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle(fontSize: _fontSizeRegular, color: _getTextColor()), + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + color: Colors.transparent, + child: Text( + row.getCells()[2].value.toString(), + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle(fontSize: _fontSizeRegular, color: _getTextColor()), + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all(8), + color: Colors.transparent, + child: Text( + row.getCells()[3].value.toString(), + softWrap: true, + overflow: TextOverflow.clip, + style: TextStyle(fontSize: _fontSizeRegular, color: _getTextColor()), + ), + ), + ]); } } diff --git a/lib/samples/signature_pad/shared/mobile_image_converter.dart b/lib/samples/signature_pad/shared/mobile_image_converter.dart index 936da346..b1f13380 100644 --- a/lib/samples/signature_pad/shared/mobile_image_converter.dart +++ b/lib/samples/signature_pad/shared/mobile_image_converter.dart @@ -6,7 +6,7 @@ import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; class ImageConverter { /// toImage static Future toImage( - {RenderSignaturePad renderSignaturePad}) async { - return null; + {required RenderSignaturePad renderSignaturePad}) async { + return Uint8List.fromList([0]); } } diff --git a/lib/samples/signature_pad/shared/web_image_converter.dart b/lib/samples/signature_pad/shared/web_image_converter.dart index 7c5bfb3a..43a362ac 100644 --- a/lib/samples/signature_pad/shared/web_image_converter.dart +++ b/lib/samples/signature_pad/shared/web_image_converter.dart @@ -8,7 +8,7 @@ import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; class ImageConverter { /// toImage static Future toImage( - {RenderSignaturePad renderSignaturePad}) async { + {required RenderSignaturePad renderSignaturePad}) async { final canvas = html.CanvasElement( width: renderSignaturePad.size.width.toInt(), height: renderSignaturePad.size.height.toInt()); @@ -18,7 +18,8 @@ class ImageConverter { final completer = Completer(); final reader = html.FileReader(); reader.readAsArrayBuffer(blob); - reader.onLoad.listen((_) => completer.complete(reader.result)); + // ignore: avoid_as + reader.onLoad.listen((_) => completer.complete(reader.result as Uint8List)); return await completer.future; } } diff --git a/lib/samples/sliders/range_selector/range_selector_default_appearance.dart b/lib/samples/sliders/range_selector/range_selector_default_appearance.dart index b15ba1dd..53dd0905 100644 --- a/lib/samples/sliders/range_selector/range_selector_default_appearance.dart +++ b/lib/samples/sliders/range_selector/range_selector_default_appearance.dart @@ -32,9 +32,9 @@ class _DefaultRangeSelectorPageState extends SampleViewState { _DefaultRangeSelectorPageState(); final DateTime min = DateTime(2002, 01, 01), max = DateTime(2011, 01, 01); - List chartData; - RangeController rangeController; - LinearGradient gradientColors; + late List chartData; + late RangeController rangeController; + late LinearGradient gradientColors; @override void initState() { @@ -71,7 +71,7 @@ class _DefaultRangeSelectorPageState extends SampleViewState { for (int i = 0; i < chartData.length; i++) { //ignore: avoid_as if (chartData[i].x.year == (values.start as DateTime).year) { - startRate = chartData[i].y; + startRate = chartData[i].y!.toDouble(); } if (chartData[i].x.isAfter( //ignore: avoid_as @@ -80,7 +80,7 @@ class _DefaultRangeSelectorPageState extends SampleViewState { //ignore: avoid_as (values.end as DateTime).add(const Duration(hours: 12)))) { dataCount++; - totalData += chartData[i].y; + totalData += chartData[i].y!; } } return totalData = dataCount != 0 ? totalData / dataCount : startRate; @@ -100,7 +100,7 @@ class _DefaultRangeSelectorPageState extends SampleViewState { 0, mediaQueryData.orientation == Orientation.portrait ? 50 - : model.isWeb + : model.isWebFullView ? 15 : 2, 0, @@ -123,11 +123,11 @@ class _DefaultRangeSelectorPageState extends SampleViewState { labelOffset: const Offset(0, 0), activeLabelStyle: TextStyle( fontSize: 10, - color: themeData.textTheme.bodyText1.color + color: themeData.textTheme.bodyText1!.color! .withOpacity(0.87)), inactiveLabelStyle: TextStyle( fontSize: 10, - color: themeData.textTheme.bodyText1.color + color: themeData.textTheme.bodyText1!.color! .withOpacity(0.87)), inactiveRegionColor: themeData.brightness == Brightness.light @@ -138,7 +138,8 @@ class _DefaultRangeSelectorPageState extends SampleViewState { min: min, max: max, labelPlacement: LabelPlacement.betweenTicks, - interval: (model.isWeb && mediaQueryData.size.width <= 1000) + interval: (model.isWebFullView && + mediaQueryData.size.width <= 1000) ? 2 : 1, controller: rangeController, @@ -157,6 +158,16 @@ class _DefaultRangeSelectorPageState extends SampleViewState { }); }, child: Container( + width: mediaQueryData.orientation == Orientation.landscape + ? model.isWebFullView + ? mediaQueryData.size.width * 0.6 + : mediaQueryData.size.width + : mediaQueryData.size.width, + height: mediaQueryData.orientation == Orientation.portrait + ? mediaQueryData.size.height * 0.45 + : model.isWebFullView + ? mediaQueryData.size.height * 0.38 + : mediaQueryData.size.height * 0.4, child: SfCartesianChart( margin: const EdgeInsets.all(0), primaryXAxis: DateTimeAxis( @@ -177,37 +188,30 @@ class _DefaultRangeSelectorPageState extends SampleViewState { animationDuration: 0) ], ), - width: mediaQueryData.orientation == Orientation.landscape - ? model.isWeb - ? mediaQueryData.size.width * 0.6 - : mediaQueryData.size.width - : mediaQueryData.size.width, - height: mediaQueryData.orientation == Orientation.portrait - ? mediaQueryData.size.height * 0.45 - : model.isWeb - ? mediaQueryData.size.height * 0.38 - : mediaQueryData.size.height * 0.4, ), ), ), ), ), - Center( - child: Container( - height: mediaQueryData.size.height, - padding: EdgeInsets.only( - top: (mediaQueryData.size.height - - (model.isWeb ? 150 : 100)) * - 0.8), - child: SizedBox( - height: 15, - child: Text( - 'Average rate : ' + - _getAverageInflationRate(rangeController) - .toStringAsFixed(2) + - '%', - style: const TextStyle(fontSize: 18), - )))) + Padding( + padding: mediaQueryData.orientation == Orientation.landscape || + model.isWebFullView + ? EdgeInsets.only(bottom: mediaQueryData.size.height * 0.025) + : EdgeInsets.only(bottom: mediaQueryData.size.height * 0.1), + child: Align( + alignment: Alignment.bottomCenter, + child: SizedBox( + height: 25, + child: Text( + 'Average rate : ' + + _getAverageInflationRate(rangeController) + .toStringAsFixed(2) + + '%', + style: const TextStyle(fontSize: 18), + ), + ), + ), + ) ], )); } diff --git a/lib/samples/sliders/range_selector/range_selector_with_bar_chart.dart b/lib/samples/sliders/range_selector/range_selector_with_bar_chart.dart index 62053e7a..e2b58e81 100644 --- a/lib/samples/sliders/range_selector/range_selector_with_bar_chart.dart +++ b/lib/samples/sliders/range_selector/range_selector_with_bar_chart.dart @@ -32,52 +32,52 @@ class _RangeSelectorBarChartPageState extends SampleViewState with SingleTickerProviderStateMixin { _RangeSelectorBarChartPageState(); - DateTime _dayMin = DateTime(2020, 05, 31, 12); - DateTime _dayMax = DateTime(2020, 06, 30, 12); - SfRangeValues _monthValues = + final DateTime _dayMin = DateTime(2020, 05, 31, 12); + final DateTime _dayMax = DateTime(2020, 06, 30, 12); + final SfRangeValues _monthValues = SfRangeValues(DateTime(2020, 06, 12), DateTime(2020, 06, 23)); - RangeController _rangeController; + late RangeController _rangeController; - List _chartData; + late List<_ChartSampleData> _chartData; - String _profitText; + late String _profitText; @override void initState() { super.initState(); - _chartData = [ - ChartSampleData(x: DateTime(2020, 06, 01), y: 100.0), - ChartSampleData(x: DateTime(2020, 06, 02), y: 150.541), - ChartSampleData(x: DateTime(2020, 06, 03), y: -25.818), - ChartSampleData(x: DateTime(2020, 06, 04), y: 30.51), - ChartSampleData(x: DateTime(2020, 06, 05), y: -50.302), - ChartSampleData(x: DateTime(2020, 06, 06), y: -150.017), - ChartSampleData(x: DateTime(2020, 06, 07), y: -25.683), - ChartSampleData(x: DateTime(2020, 06, 08), y: 75.818), - ChartSampleData(x: DateTime(2020, 06, 09), y: 130.541), - ChartSampleData(x: DateTime(2020, 06, 10), y: -55.341), - ChartSampleData(x: DateTime(2020, 06, 11), y: -90.205), - ChartSampleData(x: DateTime(2020, 06, 12), y: -35.541), - ChartSampleData(x: DateTime(2020, 06, 13), y: 10.818), - ChartSampleData(x: DateTime(2020, 06, 14), y: 45.51), - ChartSampleData(x: DateTime(2020, 06, 15), y: 78.302), - ChartSampleData(x: DateTime(2020, 06, 16), y: -37.017), - ChartSampleData(x: DateTime(2020, 06, 17), y: -14.683), - ChartSampleData(x: DateTime(2020, 06, 18), y: -49.818), - ChartSampleData(x: DateTime(2020, 06, 19), y: 98.541), - ChartSampleData(x: DateTime(2020, 06, 20), y: 75.341), - ChartSampleData(x: DateTime(2020, 06, 21), y: -69.205), - ChartSampleData(x: DateTime(2020, 06, 22), y: 18.541), - ChartSampleData(x: DateTime(2020, 06, 23), y: 73.818), - ChartSampleData(x: DateTime(2020, 06, 24), y: -96.51), - ChartSampleData(x: DateTime(2020, 06, 25), y: -23.302), - ChartSampleData(x: DateTime(2020, 06, 26), y: -79.017), - ChartSampleData(x: DateTime(2020, 06, 27), y: 41.683), - ChartSampleData(x: DateTime(2020, 06, 28), y: -65.818), - ChartSampleData(x: DateTime(2020, 06, 29), y: -52.541), - ChartSampleData(x: DateTime(2020, 06, 30), y: 23.341), + _chartData = <_ChartSampleData>[ + _ChartSampleData(x: DateTime(2020, 06, 01), y: 100.0), + _ChartSampleData(x: DateTime(2020, 06, 02), y: 150.541), + _ChartSampleData(x: DateTime(2020, 06, 03), y: -25.818), + _ChartSampleData(x: DateTime(2020, 06, 04), y: 30.51), + _ChartSampleData(x: DateTime(2020, 06, 05), y: -50.302), + _ChartSampleData(x: DateTime(2020, 06, 06), y: -150.017), + _ChartSampleData(x: DateTime(2020, 06, 07), y: -25.683), + _ChartSampleData(x: DateTime(2020, 06, 08), y: 75.818), + _ChartSampleData(x: DateTime(2020, 06, 09), y: 130.541), + _ChartSampleData(x: DateTime(2020, 06, 10), y: -55.341), + _ChartSampleData(x: DateTime(2020, 06, 11), y: -90.205), + _ChartSampleData(x: DateTime(2020, 06, 12), y: -35.541), + _ChartSampleData(x: DateTime(2020, 06, 13), y: 10.818), + _ChartSampleData(x: DateTime(2020, 06, 14), y: 45.51), + _ChartSampleData(x: DateTime(2020, 06, 15), y: 78.302), + _ChartSampleData(x: DateTime(2020, 06, 16), y: -37.017), + _ChartSampleData(x: DateTime(2020, 06, 17), y: -14.683), + _ChartSampleData(x: DateTime(2020, 06, 18), y: -49.818), + _ChartSampleData(x: DateTime(2020, 06, 19), y: 98.541), + _ChartSampleData(x: DateTime(2020, 06, 20), y: 75.341), + _ChartSampleData(x: DateTime(2020, 06, 21), y: -69.205), + _ChartSampleData(x: DateTime(2020, 06, 22), y: 18.541), + _ChartSampleData(x: DateTime(2020, 06, 23), y: 73.818), + _ChartSampleData(x: DateTime(2020, 06, 24), y: -96.51), + _ChartSampleData(x: DateTime(2020, 06, 25), y: -23.302), + _ChartSampleData(x: DateTime(2020, 06, 26), y: -79.017), + _ChartSampleData(x: DateTime(2020, 06, 27), y: 41.683), + _ChartSampleData(x: DateTime(2020, 06, 28), y: -65.818), + _ChartSampleData(x: DateTime(2020, 06, 29), y: -52.541), + _ChartSampleData(x: DateTime(2020, 06, 30), y: 23.341), ]; _rangeController = RangeController( @@ -90,8 +90,8 @@ class _RangeSelectorBarChartPageState extends SampleViewState @override void dispose() { - _rangeController?.dispose(); - _chartData?.clear(); + _rangeController.dispose(); + _chartData.clear(); super.dispose(); } @@ -166,7 +166,7 @@ class _RangeSelectorBarChartPageState extends SampleViewState child: Container( width: mediaQueryData.orientation == Orientation.landscape - ? model.isWeb + ? model.isWebFullView ? mediaQueryData.size.width * 0.5 : mediaQueryData.size.width : mediaQueryData.size.width, @@ -177,13 +177,13 @@ class _RangeSelectorBarChartPageState extends SampleViewState ), ])), ), - Center( - child: Container( - height: mediaQueryData.size.height, - padding: EdgeInsets.only( - top: - (mediaQueryData.size.height - (model.isWeb ? 180 : 120)) * - 0.8), + Padding( + padding: mediaQueryData.orientation == Orientation.landscape || + model.isWebFullView + ? EdgeInsets.only(bottom: mediaQueryData.size.height * 0.1) + : EdgeInsets.only(bottom: mediaQueryData.size.height * 0.2), + child: Align( + alignment: Alignment.bottomCenter, child: Text( _profitText, style: TextStyle(fontSize: 18.0), @@ -215,13 +215,13 @@ class _RangeSelectorBarChartPageState extends SampleViewState } /// Get default column series - List> _getColumnSeries() { - return >[ - ColumnSeries( + List> _getColumnSeries() { + return >[ + ColumnSeries<_ChartSampleData, DateTime>( dataSource: _chartData, - xValueMapper: (ChartSampleData data, _) => data.x, - yValueMapper: (ChartSampleData data, _) => data.y, - pointColorMapper: (ChartSampleData data, _) => + xValueMapper: (_ChartSampleData data, _) => data.x, + yValueMapper: (_ChartSampleData data, _) => data.y, + pointColorMapper: (_ChartSampleData data, _) => data.y < 0 ? Colors.red : Colors.green, borderRadius: BorderRadius.all(Radius.circular(15)), ) @@ -257,16 +257,14 @@ class _RangeSelectorBarChartPageState extends SampleViewState } //Chart sample data -class ChartSampleData { +class _ChartSampleData { /// Holds the datapoint values like x, y, etc., - ChartSampleData({this.x, this.y, this.color}); + _ChartSampleData({this.x, this.y}); /// Holds x value of the datapoint final dynamic x; final dynamic y; - - final Color color; } /// To move the thumb to center of the chart, we will override the `paint` @@ -277,15 +275,15 @@ class ThumbShape extends SfThumbShape { void paint( PaintingContext context, Offset center, { - RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb, }) { super.paint( context, @@ -311,17 +309,17 @@ class TrackShape extends SfTrackShape { void paint( PaintingContext context, Offset offset, - Offset thumbCenter, - Offset startThumbCenter, - Offset endThumbCenter, { - RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + Offset? thumbCenter, + Offset? startThumbCenter, + Offset? endThumbCenter, { + required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Animation enableAnimation, - Paint inactivePaint, - Paint activePaint, - TextDirection textDirection, + required Animation enableAnimation, + required Paint? inactivePaint, + required Paint? activePaint, + required TextDirection textDirection, }) { super.paint( context, @@ -347,17 +345,14 @@ class TrackShape extends SfTrackShape { /// `super.onPaint` to the half the height of the `parentBox`. class OverlayShape extends SfOverlayShape { @override - void paint( - PaintingContext context, - Offset center, { - RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, - dynamic currentValue, - Paint paint, - Animation animation, - SfThumb thumb, - }) { + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation animation, + required SfThumb? thumb}) { super.paint( context, center - @@ -378,17 +373,13 @@ class OverlayShape extends SfOverlayShape { /// `super.onPaint` to the half the height of the `parentBox`. class TooltipShape extends SfRectangularTooltipShape { @override - void paint( - PaintingContext context, - Offset thumbCenter, - Offset offset, - TextPainter textPainter, { - RenderBox parentBox, - SfSliderThemeData sliderThemeData, - Paint paint, - Animation animation, - Rect trackRect, - }) { + void paint(PaintingContext context, Offset thumbCenter, Offset offset, + TextPainter textPainter, + {required RenderBox parentBox, + required SfSliderThemeData sliderThemeData, + required Paint paint, + required Animation animation, + required Rect trackRect}) { super.paint( context, thumbCenter - diff --git a/lib/samples/sliders/range_selector/range_selector_with_histogram_chart.dart b/lib/samples/sliders/range_selector/range_selector_with_histogram_chart.dart index 7fecb319..3ad7978b 100644 --- a/lib/samples/sliders/range_selector/range_selector_with_histogram_chart.dart +++ b/lib/samples/sliders/range_selector/range_selector_with_histogram_chart.dart @@ -35,11 +35,11 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState final double _max = 1000.0; SfRangeValues _values = SfRangeValues(400.0, 700.0); - RangeController _rangeController; - TextEditingController _textController = TextEditingController(); + late RangeController _rangeController; + final TextEditingController _textController = TextEditingController(); - List _chartData; - List _updatedChartData = []; + late List<_RoomData> _chartData; + final List<_RoomData> _updatedChartData = <_RoomData>[]; bool _needBanquetHall = false; bool _needHealthSpa = false; @@ -49,85 +49,85 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState @override void initState() { _rangeController = RangeController(start: _values.start, end: _values.end); - _chartData = [ - RoomData(rate: 300, hasBanquetHall: true), - RoomData( + _chartData = <_RoomData>[ + _RoomData(rate: 300, hasBanquetHall: true), + _RoomData( rate: 762, hasBanquetHall: true, hasHealthSpa: true, petsAllowed: true), - RoomData(rate: 550, hasBanquetHall: true, petsAllowed: true), - RoomData(rate: 336, hasHealthSpa: true), - RoomData(rate: 150), - RoomData(rate: 440, hasBanquetHall: true, hasHealthSpa: true), - RoomData(rate: 350, hasIndoorEntertainment: true), - RoomData(rate: 300, petsAllowed: true), - RoomData(rate: 550, hasHealthSpa: true, petsAllowed: true), - RoomData(rate: 199, hasHealthSpa: true), - RoomData(rate: 729, hasIndoorEntertainment: true, hasBanquetHall: true), - RoomData(rate: 179, petsAllowed: true), - RoomData( + _RoomData(rate: 550, hasBanquetHall: true, petsAllowed: true), + _RoomData(rate: 336, hasHealthSpa: true), + _RoomData(rate: 150), + _RoomData(rate: 440, hasBanquetHall: true, hasHealthSpa: true), + _RoomData(rate: 350, hasIndoorEntertainment: true), + _RoomData(rate: 300, petsAllowed: true), + _RoomData(rate: 550, hasHealthSpa: true, petsAllowed: true), + _RoomData(rate: 199, hasHealthSpa: true), + _RoomData(rate: 729, hasIndoorEntertainment: true, hasBanquetHall: true), + _RoomData(rate: 179, petsAllowed: true), + _RoomData( rate: 969, hasBanquetHall: true, hasHealthSpa: true, petsAllowed: true, hasIndoorEntertainment: true), - RoomData(rate: 699, hasBanquetHall: true, petsAllowed: true), - RoomData(rate: 288, petsAllowed: true), - RoomData(rate: 399, petsAllowed: true), - RoomData(rate: 429, petsAllowed: true, hasHealthSpa: true), - RoomData(rate: 316, hasBanquetHall: true), - RoomData(rate: 778, hasHealthSpa: true, hasIndoorEntertainment: true), - RoomData( + _RoomData(rate: 699, hasBanquetHall: true, petsAllowed: true), + _RoomData(rate: 288, petsAllowed: true), + _RoomData(rate: 399, petsAllowed: true), + _RoomData(rate: 429, petsAllowed: true, hasHealthSpa: true), + _RoomData(rate: 316, hasBanquetHall: true), + _RoomData(rate: 778, hasHealthSpa: true, hasIndoorEntertainment: true), + _RoomData( rate: 899, hasBanquetHall: true, hasHealthSpa: true, petsAllowed: true, hasIndoorEntertainment: true), - RoomData(rate: 199, hasBanquetHall: true), - RoomData(rate: 299, hasHealthSpa: true), - RoomData( + _RoomData(rate: 199, hasBanquetHall: true), + _RoomData(rate: 299, hasHealthSpa: true), + _RoomData( rate: 947, hasBanquetHall: true, hasHealthSpa: true, petsAllowed: true, hasIndoorEntertainment: true), - RoomData( + _RoomData( rate: 899, hasBanquetHall: true, hasIndoorEntertainment: true, petsAllowed: true), - RoomData( + _RoomData( rate: 794, hasBanquetHall: true, petsAllowed: true, hasHealthSpa: true, ), - RoomData( + _RoomData( rate: 969, hasBanquetHall: true, hasHealthSpa: true, petsAllowed: true, hasIndoorEntertainment: true), - RoomData( + _RoomData( rate: 849, hasHealthSpa: true, petsAllowed: true, hasIndoorEntertainment: true), - RoomData(rate: 724, hasBanquetHall: true, hasIndoorEntertainment: true), - RoomData(rate: 449, hasBanquetHall: true, hasHealthSpa: true), - RoomData(rate: 409, petsAllowed: true), - RoomData(rate: 699, hasBanquetHall: true, petsAllowed: true), - RoomData(rate: 474, hasHealthSpa: true), - RoomData(rate: 599, hasIndoorEntertainment: true, petsAllowed: true), - RoomData(rate: 639, hasHealthSpa: true, petsAllowed: true), - RoomData(rate: 618, hasHealthSpa: true, petsAllowed: true), - RoomData(rate: 549, petsAllowed: true), - RoomData(rate: 399, hasHealthSpa: true), - RoomData(rate: 215), - RoomData(rate: 287, hasIndoorEntertainment: true), - RoomData(rate: 100), - RoomData( + _RoomData(rate: 724, hasBanquetHall: true, hasIndoorEntertainment: true), + _RoomData(rate: 449, hasBanquetHall: true, hasHealthSpa: true), + _RoomData(rate: 409, petsAllowed: true), + _RoomData(rate: 699, hasBanquetHall: true, petsAllowed: true), + _RoomData(rate: 474, hasHealthSpa: true), + _RoomData(rate: 599, hasIndoorEntertainment: true, petsAllowed: true), + _RoomData(rate: 639, hasHealthSpa: true, petsAllowed: true), + _RoomData(rate: 618, hasHealthSpa: true, petsAllowed: true), + _RoomData(rate: 549, petsAllowed: true), + _RoomData(rate: 399, hasHealthSpa: true), + _RoomData(rate: 215), + _RoomData(rate: 287, hasIndoorEntertainment: true), + _RoomData(rate: 100), + _RoomData( rate: 999, hasBanquetHall: true, hasHealthSpa: true, @@ -142,10 +142,10 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState @override void dispose() { - _rangeController?.dispose(); - _textController?.dispose(); - _chartData?.clear(); - _updatedChartData?.clear(); + _rangeController.dispose(); + _textController.dispose(); + _chartData.clear(); + _updatedChartData.clear(); super.dispose(); } @@ -156,7 +156,7 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState bool arePetsAllowed = false, bool hasIndoorEntertainment = false, }) { - _updatedChartData?.clear(); + _updatedChartData.clear(); for (int i = 0; i < _chartData.length; i++) { if (hasBanquetHall && hasHealthSpa && @@ -261,17 +261,18 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState return SingleChildScrollView( child: Container( color: isLightTheme ? const Color.fromRGBO(250, 250, 250, 1) : null, - padding: model.isWeb + padding: model.isWebFullView ? const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 20.0) : const EdgeInsets.fromLTRB(10.0, 12.5, 10.0, 10.0), - child: _getRangeSelector(mediaQueryData, isLightTheme), + child: _buildRangeSelector(mediaQueryData, isLightTheme), ), ); } - Widget _getRangeSelector(MediaQueryData mediaQueryData, bool isLightTheme) { + Widget _buildRangeSelector(MediaQueryData mediaQueryData, bool isLightTheme) { final Axis direction = - (mediaQueryData.orientation == Orientation.landscape || model.isWeb) && + (mediaQueryData.orientation == Orientation.landscape || + model.isWebFullView) && mediaQueryData.size.width > mediaQueryData.size.height ? Axis.horizontal : Axis.vertical; @@ -290,18 +291,18 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState crossAxisAlignment: CrossAxisAlignment.start, children: [ direction == Axis.horizontal - ? Expanded(child: _getRangeSelectorWidget(isLightTheme)) - : _getRangeSelectorWidget(isLightTheme), + ? Expanded(child: _buildRangeSelectorWidget(isLightTheme)) + : _buildRangeSelectorWidget(isLightTheme), direction == Axis.horizontal - ? Expanded(child: _getAmenities()) - : _getAmenities(), + ? Expanded(child: _buildAmenities()) + : _buildAmenities(), ], ), ], ); } - Widget _getRangeSelectorWidget(bool isLightTheme) { + Widget _buildRangeSelectorWidget(bool isLightTheme) { return Padding( padding: const EdgeInsets.all(5.0), child: Card( @@ -310,14 +311,15 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState borderRadius: BorderRadius.circular(3.0), ), child: Padding( - padding: model.isWeb + padding: model.isWebFullView ? const EdgeInsets.all(20.0) : const EdgeInsets.fromLTRB(10, 20, 10, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only(left: model.isWeb ? 5.0 : 15.0), + padding: + EdgeInsets.only(left: model.isWebFullView ? 5.0 : 15.0), child: Text( '\$100 to \$1000', style: TextStyle(fontSize: 20), @@ -325,7 +327,7 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState ), Padding( padding: EdgeInsets.fromLTRB( - model.isWeb ? 5.0 : 15.0, 5.0, 0.0, 5.0), + model.isWebFullView ? 5.0 : 15.0, 5.0, 0.0, 5.0), child: Text(_textController.text), ), SfRangeSelectorTheme( @@ -370,7 +372,7 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState }); }, child: SfCartesianChart( - margin: const EdgeInsets.all(0.0), + margin: EdgeInsets.zero, plotAreaBorderWidth: 0, enableAxisAnimation: true, primaryXAxis: NumericAxis( @@ -390,21 +392,21 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState } ///Get the histogram series - List> _getHistogramSeries() { - return >[ - HistogramSeries( + List> _getHistogramSeries() { + return >[ + HistogramSeries<_RoomData, double>( dataSource: _updatedChartData, binInterval: 100, width: 1.0, spacing: 0, color: Color.fromRGBO(0, 179, 134, 0.5), - yValueMapper: (RoomData sales, _) => sales.rate, + yValueMapper: (_RoomData sales, _) => sales.rate, ), ]; } /// UI part of amenities section. - Widget _getAmenities() { + Widget _buildAmenities() { return Column(children: [ Padding( padding: const EdgeInsets.all(5.0), @@ -437,7 +439,7 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState ), value: true, activeColor: Colors.grey, - onChanged: (bool value) {}, + onChanged: (bool? value) {}, ), CheckboxListTile( contentPadding: EdgeInsets.only(left: 8), @@ -446,9 +448,9 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState style: TextStyle(fontSize: 16), ), value: _needBanquetHall, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _needBanquetHall = value; + _needBanquetHall = value!; }); }), CheckboxListTile( @@ -458,9 +460,9 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState style: TextStyle(fontSize: 16), ), value: _needHealthSpa, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _needHealthSpa = value; + _needHealthSpa = value!; }); }), CheckboxListTile( @@ -470,9 +472,9 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState style: TextStyle(fontSize: 16), ), value: _needPets, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _needPets = value; + _needPets = value!; }); }), CheckboxListTile( @@ -482,9 +484,9 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState style: TextStyle(fontSize: 16), ), value: _needIndoorEntertainment, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _needIndoorEntertainment = value; + _needIndoorEntertainment = value!; }); }), ], @@ -495,17 +497,20 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState ), Padding( padding: const EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 0.0), - child: _getFilterButton(), + child: _buildFilterButton(), ) ]); } - Widget _getFilterButton() { + Widget _buildFilterButton() { return Container( width: 350, height: 50, - child: RaisedButton( - color: Color.fromRGBO(255, 102, 102, 1.0), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + Color.fromRGBO(255, 102, 102, 1.0)), + ), /// On clicking the button, chart inside the range selector will be /// updated with the filtered data. @@ -532,9 +537,9 @@ class _RangeSelectorHistogramChartPageState extends SampleViewState } ///Chart sample data -class RoomData { - RoomData({ - this.rate, +class _RoomData { + _RoomData({ + required this.rate, this.hasBanquetHall = false, this.hasHealthSpa = false, this.petsAllowed = false, diff --git a/lib/samples/sliders/range_selector/range_selector_with_selection.dart b/lib/samples/sliders/range_selector/range_selector_with_selection.dart index ad9f8710..f952ccc9 100644 --- a/lib/samples/sliders/range_selector/range_selector_with_selection.dart +++ b/lib/samples/sliders/range_selector/range_selector_with_selection.dart @@ -33,10 +33,10 @@ class _RangeSelectorSelectionPageState extends SampleViewState _RangeSelectorSelectionPageState(); final DateTime min = DateTime(2019, 04, 01), max = DateTime(2019, 04, 30, 24); - RangeController rangeController; - TextEditingController textController; - List<_ChartData> data; - List selectedItems; + late RangeController rangeController; + late TextEditingController textController; + late List<_ChartData> data; + late List selectedItems; @override void initState() { @@ -137,11 +137,11 @@ class _RangeSelectorSelectionPageState extends SampleViewState inactiveTrackColor: const Color.fromRGBO(194, 194, 194, 1), activeLabelStyle: TextStyle( fontSize: 12, - color: themeData.textTheme.bodyText1.color + color: themeData.textTheme.bodyText1!.color! .withOpacity(0.87)), inactiveLabelStyle: TextStyle( fontSize: 12, - color: themeData.textTheme.bodyText1.color + color: themeData.textTheme.bodyText1!.color! .withOpacity(0.87)), inactiveRegionColor: Colors.transparent), child: SfRangeSelector( @@ -157,62 +157,63 @@ class _RangeSelectorSelectionPageState extends SampleViewState _setTotalDataUsage(values); }, child: Container( - child: Padding( - padding: const EdgeInsets.only(top: 20), - child: SfCartesianChart( - title: ChartTitle(text: 'Data Usage For April 2019'), - margin: const EdgeInsets.all(0), - primaryXAxis: DateTimeAxis( - isVisible: false, - minimum: DateTime(2019, 04, 01), - maximum: DateTime(2019, 04, 30, 24)), - primaryYAxis: - NumericAxis(isVisible: false, maximum: 26), - plotAreaBorderWidth: 0, - plotAreaBackgroundColor: Colors.transparent, - series: >[ - ColumnSeries<_ChartData, DateTime>( - width: 0.8, - initialSelectedDataIndexes: selectedItems, - selectionBehavior: SelectionBehavior( - enable: true, - unselectedOpacity: 0, - selectedBorderColor: - const Color.fromRGBO(0, 178, 206, 1), - selectedColor: - const Color.fromRGBO(0, 178, 206, 1), - unselectedColor: Colors.transparent, - selectionController: rangeController), - dashArray: model.isWeb ? null : [3, 2], - color: const Color.fromRGBO(255, 255, 255, 0), - borderColor: - const Color.fromRGBO(194, 194, 194, 1), - animationDuration: 0, - borderWidth: 1, - dataSource: data, - xValueMapper: (_ChartData score, _) => score.date, - yValueMapper: (_ChartData score, _) => score.runs, - ) - ], - ), + width: mediaQueryData.orientation == Orientation.landscape + ? model.isWebFullView + ? mediaQueryData.size.width * 0.5 + : mediaQueryData.size.width + : mediaQueryData.size.width, + height: mediaQueryData.size.height * 0.55 - 25, + child: Padding( + padding: const EdgeInsets.only(top: 20), + child: SfCartesianChart( + title: ChartTitle(text: 'Data Usage For April 2019'), + margin: const EdgeInsets.all(0), + primaryXAxis: DateTimeAxis( + isVisible: false, + minimum: DateTime(2019, 04, 01), + maximum: DateTime(2019, 04, 30, 24)), + primaryYAxis: + NumericAxis(isVisible: false, maximum: 26), + plotAreaBorderWidth: 0, + plotAreaBackgroundColor: Colors.transparent, + series: >[ + ColumnSeries<_ChartData, DateTime>( + width: 0.8, + initialSelectedDataIndexes: selectedItems, + selectionBehavior: SelectionBehavior( + enable: true, + unselectedOpacity: 0, + selectedBorderColor: + const Color.fromRGBO(0, 178, 206, 1), + selectedColor: + const Color.fromRGBO(0, 178, 206, 1), + unselectedColor: Colors.transparent, + selectionController: rangeController), + dashArray: + model.isWebFullView ? null : [3, 2], + color: const Color.fromRGBO(255, 255, 255, 0), + borderColor: const Color.fromRGBO(194, 194, 194, 1), + animationDuration: 0, + borderWidth: 1, + dataSource: data, + xValueMapper: (_ChartData score, _) => score.date, + yValueMapper: (_ChartData score, _) => score.runs, + ) + ], ), - width: mediaQueryData.orientation == Orientation.landscape - ? model.isWeb - ? mediaQueryData.size.width * 0.5 - : mediaQueryData.size.width - : mediaQueryData.size.width, - height: mediaQueryData.size.height * 0.55 - 25), + ), + ), ), ), ), ), - Center( - child: Container( - height: mediaQueryData.size.height, - padding: EdgeInsets.only( - top: (mediaQueryData.size.height - - (model.isWeb ? 150 : 120)) * - 0.8), + Padding( + padding: mediaQueryData.orientation == Orientation.landscape || + model.isWebFullView + ? EdgeInsets.only(bottom: mediaQueryData.size.height * 0.025) + : EdgeInsets.only(bottom: mediaQueryData.size.height * 0.1), + child: Align( + alignment: Alignment.bottomCenter, child: SizedBox( width: 250, height: 20, diff --git a/lib/samples/sliders/range_selector/range_selector_with_zooming.dart b/lib/samples/sliders/range_selector/range_selector_with_zooming.dart index 8d952bfa..8853559f 100644 --- a/lib/samples/sliders/range_selector/range_selector_with_zooming.dart +++ b/lib/samples/sliders/range_selector/range_selector_with_zooming.dart @@ -37,9 +37,9 @@ class _RangeSelectorZoomingPageState extends SampleViewState final DateTime min = DateTime(2017, 01, 01), max = DateTime(2018, 01, 01); final List chartData = []; - RangeController rangeController; - SfCartesianChart columnChart, splineChart; - List columnData, splineSeriesData; + late RangeController rangeController; + late SfCartesianChart columnChart, splineChart; + late List columnData, splineSeriesData; bool enableDeferredUpdate = true; @override @@ -650,14 +650,15 @@ class _RangeSelectorZoomingPageState extends SampleViewState final Widget page = Container( margin: const EdgeInsets.all(0), padding: const EdgeInsets.all(0), - color: model.isWeb ? model.cardThemeColor : model.cardThemeColor, + color: + model.isWebFullView ? model.cardThemeColor : model.cardThemeColor, child: Center( child: Column( children: [ Expanded( child: Container( width: mediaQueryData.orientation == Orientation.landscape - ? model.isWeb + ? model.isWebFullView ? mediaQueryData.size.width * 0.7 : mediaQueryData.size.width : mediaQueryData.size.width, @@ -666,7 +667,6 @@ class _RangeSelectorZoomingPageState extends SampleViewState ), SfRangeSelectorTheme( data: SfRangeSelectorThemeData( - labelOffset: Offset(model.isWeb ? -5 : 0, 0), activeLabelStyle: TextStyle( fontSize: 10, color: isLightTheme ? Colors.black : Colors.white), @@ -687,6 +687,11 @@ class _RangeSelectorZoomingPageState extends SampleViewState child: Container( margin: const EdgeInsets.all(0), padding: const EdgeInsets.all(0), + width: mediaQueryData.orientation == Orientation.landscape + ? model.isWebFullView + ? mediaQueryData.size.width * 0.7 + : mediaQueryData.size.width + : mediaQueryData.size.width, child: Center( child: Padding( padding: const EdgeInsets.fromLTRB(14, 0, 15, 15), @@ -701,11 +706,12 @@ class _RangeSelectorZoomingPageState extends SampleViewState controller: rangeController, showTicks: true, showLabels: true, + enableIntervalSelection: true, dragMode: SliderDragMode.both, labelFormatterCallback: (dynamic actualLabel, String formattedText) { String label = DateFormat.MMM().format(actualLabel); - label = (model.isWeb && + label = (model.isWebFullView && mediaQueryData.size.width <= 1000) ? label[0] : label; @@ -713,25 +719,21 @@ class _RangeSelectorZoomingPageState extends SampleViewState }, onChanged: (SfRangeValues values) {}, child: Container( - child: columnChart, height: 75, padding: const EdgeInsets.all(0), margin: const EdgeInsets.all(0), + child: columnChart, ), ), ), ), - width: mediaQueryData.orientation == Orientation.landscape - ? model.isWeb - ? mediaQueryData.size.width * 0.7 - : mediaQueryData.size.width - : mediaQueryData.size.width, )), ], ), )); return Scaffold( - body: mediaQueryData.orientation == Orientation.landscape && !model.isWeb + body: mediaQueryData.orientation == Orientation.landscape && + !model.isWebFullView ? SingleChildScrollView( child: Container(height: 400, child: page), ) @@ -756,9 +758,9 @@ class _RangeSelectorZoomingPageState extends SampleViewState child: CheckboxListTile( activeColor: model.backgroundColor, value: enableDeferredUpdate, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - enableDeferredUpdate = value; + enableDeferredUpdate = value!; stateSetter(() {}); }); }))), diff --git a/lib/samples/sliders/range_slider/customization/color_customization/color_customization.dart b/lib/samples/sliders/range_slider/customization/color_customization/color_customization.dart index 9d82bfeb..dc8cda4a 100644 --- a/lib/samples/sliders/range_slider/customization/color_customization/color_customization.dart +++ b/lib/samples/sliders/range_slider/customization/color_customization/color_customization.dart @@ -19,7 +19,9 @@ class ColorCustomizedRangeSliderPage extends SampleView { class _ColorCustomizedRangeSliderPageState extends SampleViewState { _ColorCustomizedRangeSliderPageState(); - Widget rangeSlider; + + late Widget rangeSlider; + late bool _isDesktop; @override void initState() { @@ -29,8 +31,13 @@ class _ColorCustomizedRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + _isDesktop ? rangeSlider : SingleChildScrollView( child: Container( @@ -50,18 +57,20 @@ class _ColorCustomizedRangeSlider extends StatefulWidget { class _ColorCustomizedRangeSliderState extends State<_ColorCustomizedRangeSlider> { - Widget _getWebLayout() { + late bool _isDesktop; + + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, - width: MediaQuery.of(context).size.width / 3, - child: _getMobileLayout(), + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -79,6 +88,11 @@ class _ColorCustomizedRangeSliderState @override Widget build(BuildContext context) { - return kIsWeb ? _getWebLayout() : _getMobileLayout(); + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; + return _isDesktop ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/customization/color_customization/gradient_track.dart b/lib/samples/sliders/range_slider/customization/color_customization/gradient_track.dart index aa8bcbfc..489c967e 100644 --- a/lib/samples/sliders/range_slider/customization/color_customization/gradient_track.dart +++ b/lib/samples/sliders/range_slider/customization/color_customization/gradient_track.dart @@ -120,15 +120,15 @@ class _ThumbShape extends SfThumbShape { @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { super.paint(context, center, parentBox: parentBox, child: child, @@ -158,13 +158,13 @@ class _OverlayShape extends SfOverlayShape { @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation animation, - SfThumb thumb}) { + required Paint? paint, + required Animation animation, + required SfThumb? thumb}) { final double radius = getPreferredSize(themeData).width / 2; final Tween tween = Tween(begin: 0.0, end: radius); @@ -185,37 +185,32 @@ class _TrackShape extends SfTrackShape { final Gradient gradient; @override - void paint( - PaintingContext context, - Offset offset, - Offset thumbCenter, - Offset startThumbCenter, - Offset endThumbCenter, { - RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, - dynamic currentValue, - Animation enableAnimation, - Paint inactivePaint, - Paint activePaint, - TextDirection textDirection, - }) { - final Radius radius = Radius.circular(themeData.trackCornerRadius); + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Animation enableAnimation, + required Paint? inactivePaint, + required Paint? activePaint, + required TextDirection textDirection}) { + final Radius radius = Radius.circular(themeData.trackCornerRadius!); final Rect actualTrackRect = getPreferredRect(parentBox, themeData, offset); if (endThumbCenter == null) { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = 0 - ..color = themeData.activeTrackColor; + ..color = themeData.activeTrackColor!; Rect trackRect = Rect.fromLTRB(actualTrackRect.left, actualTrackRect.top, - startThumbCenter.dx, actualTrackRect.bottom); + startThumbCenter!.dx, actualTrackRect.bottom); final RRect leftRRect = RRect.fromRectAndCorners(trackRect, topLeft: radius, bottomLeft: radius); context.canvas.drawRRect(leftRRect, paint); - paint.color = themeData.inactiveTrackColor; + paint.color = themeData.inactiveTrackColor!; trackRect = Rect.fromLTRB(startThumbCenter.dx, actualTrackRect.top, actualTrackRect.right, actualTrackRect.bottom); final RRect rightRRect = RRect.fromRectAndCorners(trackRect, @@ -225,11 +220,11 @@ class _TrackShape extends SfTrackShape { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = 0 - ..color = themeData.inactiveTrackColor; + ..color = themeData.inactiveTrackColor!; // Drawing inactive track. Rect trackRect = Rect.fromLTRB(actualTrackRect.left, actualTrackRect.top, - startThumbCenter.dx, actualTrackRect.bottom); + startThumbCenter!.dx, actualTrackRect.bottom); final RRect leftRRect = RRect.fromRectAndCorners(trackRect, topLeft: radius, bottomLeft: radius); context.canvas.drawRRect(leftRRect, paint); @@ -247,7 +242,7 @@ class _TrackShape extends SfTrackShape { // Drawing inactive track. paint.shader = null; - paint.color = themeData.inactiveTrackColor; + paint.color = themeData.inactiveTrackColor!; trackRect = Rect.fromLTRB(endThumbCenter.dx, actualTrackRect.top, actualTrackRect.width + actualTrackRect.left, actualTrackRect.bottom); final RRect rightRRect = RRect.fromRectAndCorners(trackRect, diff --git a/lib/samples/sliders/range_slider/customization/shape_customization/divisor_customization.dart b/lib/samples/sliders/range_slider/customization/shape_customization/divisor_customization.dart index 85eb5d5c..198c3613 100644 --- a/lib/samples/sliders/range_slider/customization/shape_customization/divisor_customization.dart +++ b/lib/samples/sliders/range_slider/customization/shape_customization/divisor_customization.dart @@ -61,25 +61,25 @@ class _DivisorShape extends SfDivisorShape { SampleModel model; @override - void paint(PaintingContext context, Offset center, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset center, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection}) { - bool isActive; + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection}) { + late bool isActive; switch (textDirection) { case TextDirection.ltr: - isActive = - center.dx >= startThumbCenter.dx && center.dx <= endThumbCenter.dx; + isActive = center.dx >= startThumbCenter!.dx && + center.dx <= endThumbCenter!.dx; break; case TextDirection.rtl: - isActive = - center.dx >= endThumbCenter.dx && center.dx <= startThumbCenter.dx; + isActive = center.dx >= endThumbCenter!.dx && + center.dx <= startThumbCenter!.dx; break; } @@ -89,7 +89,7 @@ class _DivisorShape extends SfDivisorShape { ..isAntiAlias = true ..style = PaintingStyle.fill ..color = isActive - ? themeData.activeDivisorColor + ? themeData.activeDivisorColor! : model.themeData.canvasColor); } } diff --git a/lib/samples/sliders/range_slider/customization/shape_customization/shape_customization.dart b/lib/samples/sliders/range_slider/customization/shape_customization/shape_customization.dart index deb80719..68d92c89 100644 --- a/lib/samples/sliders/range_slider/customization/shape_customization/shape_customization.dart +++ b/lib/samples/sliders/range_slider/customization/shape_customization/shape_customization.dart @@ -1,3 +1,5 @@ +import 'package:flutter/foundation.dart'; + ///Package imports import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -22,7 +24,9 @@ class ShapeCustomizedRangeSliderPage extends SampleView { class _ShapeCustomizedRangeSliderPageState extends SampleViewState { _ShapeCustomizedRangeSliderPageState(); - Widget rangeSlider; + + late Widget rangeSlider; + late bool _isDesktop; @override void initState() { @@ -32,8 +36,13 @@ class _ShapeCustomizedRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + _isDesktop ? rangeSlider : SingleChildScrollView( child: Container( @@ -52,18 +61,20 @@ class _ShapeCustomizedRangeSlider extends SampleView { } class _ShapeCustomizedRangeSliderState extends SampleViewState { - Widget _getWebLayout() { + late bool _isDesktop; + + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, - width: MediaQuery.of(context).size.width / 3, - child: _getMobileLayout(), + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -83,6 +94,11 @@ class _ShapeCustomizedRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.windows || + themeData.platform == TargetPlatform.linux; + return _isDesktop ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/customization/shape_customization/thumb_customization.dart b/lib/samples/sliders/range_slider/customization/shape_customization/thumb_customization.dart index 89f7dca5..4e6ce447 100644 --- a/lib/samples/sliders/range_slider/customization/shape_customization/thumb_customization.dart +++ b/lib/samples/sliders/range_slider/customization/shape_customization/thumb_customization.dart @@ -99,15 +99,15 @@ class _ThumbShape extends SfThumbShape { final bool isDoubleStroke; @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { super.paint(context, center, parentBox: parentBox, child: child, @@ -125,7 +125,7 @@ class _ThumbShape extends SfThumbShape { ..isAntiAlias = true ..strokeWidth = 2 ..style = PaintingStyle.stroke - ..color = themeData.activeTrackColor); + ..color = themeData.activeTrackColor!); if (isDoubleStroke) { context.canvas.drawCircle( @@ -143,15 +143,15 @@ class _ThumbShape extends SfThumbShape { class _RectThumbShape extends SfThumbShape { @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { super.paint(context, center, parentBox: parentBox, child: child, @@ -175,6 +175,6 @@ class _RectThumbShape extends SfThumbShape { Paint() ..isAntiAlias = true ..style = PaintingStyle.fill - ..color = themeData.activeTrackColor); + ..color = themeData.activeTrackColor!); } } diff --git a/lib/samples/sliders/range_slider/customization/shape_customization/tick_customization.dart b/lib/samples/sliders/range_slider/customization/shape_customization/tick_customization.dart index 35498175..435baf47 100644 --- a/lib/samples/sliders/range_slider/customization/shape_customization/tick_customization.dart +++ b/lib/samples/sliders/range_slider/customization/shape_customization/tick_customization.dart @@ -64,18 +64,18 @@ class _TickCustomizedRangeSliderState extends SampleViewState { class _TickShape extends SfTickShape { @override - void paint(PaintingContext context, Offset offset, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Animation enableAnimation, - TextDirection textDirection}) { + required Animation enableAnimation, + required TextDirection textDirection}) { final Size tickSize = getPreferredSize(themeData); final bool isTickRightOfThumb = endThumbCenter == null - ? offset.dx > thumbCenter.dx - : offset.dx < startThumbCenter.dx || offset.dx > endThumbCenter.dx; + ? offset.dx > thumbCenter!.dx + : offset.dx < startThumbCenter!.dx || offset.dx > endThumbCenter.dx; final Color begin = isTickRightOfThumb ? themeData.disabledInactiveTickColor : themeData.disabledActiveTickColor; @@ -85,20 +85,20 @@ class _TickShape extends SfTickShape { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = tickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation); + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; context.canvas.drawLine( offset, Offset(offset.dx, offset.dy + tickSize.height), paint); context.canvas.drawLine( Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight)), Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight) - tickSize.height), @@ -108,18 +108,18 @@ class _TickShape extends SfTickShape { class _MinorTickShape extends SfTickShape { @override - void paint(PaintingContext context, Offset offset, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Animation enableAnimation, - TextDirection textDirection}) { + required Animation enableAnimation, + required TextDirection textDirection}) { final Size minorTickSize = getPreferredSize(themeData); final bool isMinorTickRightOfThumb = endThumbCenter == null - ? offset.dx > thumbCenter.dx - : offset.dx < startThumbCenter.dx || offset.dx > endThumbCenter.dx; + ? offset.dx > thumbCenter!.dx + : offset.dx < startThumbCenter!.dx || offset.dx > endThumbCenter.dx; final Color begin = isMinorTickRightOfThumb ? themeData.disabledInactiveMinorTickColor @@ -130,20 +130,20 @@ class _MinorTickShape extends SfTickShape { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = minorTickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation); + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; context.canvas.drawLine( offset, Offset(offset.dx, offset.dy + minorTickSize.height), paint); context.canvas.drawLine( Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight)), Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight) - minorTickSize.height), diff --git a/lib/samples/sliders/range_slider/customization/size_customization/size_customization.dart b/lib/samples/sliders/range_slider/customization/size_customization/size_customization.dart index 9107a4d9..b62e26a0 100644 --- a/lib/samples/sliders/range_slider/customization/size_customization/size_customization.dart +++ b/lib/samples/sliders/range_slider/customization/size_customization/size_customization.dart @@ -25,7 +25,7 @@ class SfRangeSliderSizeCustomizationPage extends SampleView { class _SfRangeSliderSizeCustomizationPageState extends SampleViewState { _SfRangeSliderSizeCustomizationPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -36,7 +36,7 @@ class _SfRangeSliderSizeCustomizationPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -117,18 +117,18 @@ class _SfRangeSliderSizeCustomizationState extends SampleViewState { enableTooltip: true)); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -149,6 +149,6 @@ class _SfRangeSliderSizeCustomizationState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/customization/thumb_customization/range_slider_thumb_icon_customization.dart b/lib/samples/sliders/range_slider/customization/thumb_customization/range_slider_thumb_icon_customization.dart index 24151544..34b9baba 100644 --- a/lib/samples/sliders/range_slider/customization/thumb_customization/range_slider_thumb_icon_customization.dart +++ b/lib/samples/sliders/range_slider/customization/thumb_customization/range_slider_thumb_icon_customization.dart @@ -24,7 +24,7 @@ class ThumbCustomizationRangeSliderPage extends SampleView { class _ThumbCustomizationRangeSliderPageState extends SampleViewState { _ThumbCustomizationRangeSliderPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -35,7 +35,7 @@ class _ThumbCustomizationRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -108,18 +108,18 @@ class _ThumbCustomizationRangeSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -140,6 +140,6 @@ class _ThumbCustomizationRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_date_time_label.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_date_time_label.dart index 22e18096..6516f579 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_date_time_label.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_date_time_label.dart @@ -23,7 +23,7 @@ class DateRangeSliderPage extends SampleView { class _DateRangeSliderPageState extends SampleViewState { _DateRangeSliderPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -34,7 +34,7 @@ class _DateRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -108,18 +108,18 @@ class _DateRangeSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -140,6 +140,6 @@ class _DateRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart index 5e695369..8fd7e027 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_default_appearance.dart @@ -23,7 +23,7 @@ class DefaultRangeSliderPage extends SampleView { class _DefaultRangeSliderPageState extends SampleViewState { _DefaultRangeSliderPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -34,7 +34,7 @@ class _DefaultRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -54,7 +54,11 @@ class _DefaultRangeSliderState extends SampleViewState { SfRangeSlider _inactiveRangeSlider() { //ignore: missing_required_param return SfRangeSlider( - min: 0.0, max: 100.0, values: _inactiveRangeSliderValue); + min: 0.0, + max: 100.0, + values: _inactiveRangeSliderValue, + onChanged: null, + ); } SfRangeSliderTheme _activeRangeSliderSlider() { @@ -75,7 +79,7 @@ class _DefaultRangeSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( @@ -104,6 +108,6 @@ class _DefaultRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _getMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_divisor_label_tick.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_divisor_label_tick.dart index 46f7ddc2..af5c0ea8 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_divisor_label_tick.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_divisor_label_tick.dart @@ -19,7 +19,7 @@ class ScaleRangeSliderPage extends SampleView { class _ScaleRangeSliderPageState extends SampleViewState { _ScaleRangeSliderPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -30,7 +30,7 @@ class _ScaleRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 325, child: rangeSlider), @@ -93,18 +93,18 @@ class _ScaleRangeSliderState extends SampleViewState { }); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -126,6 +126,6 @@ class _ScaleRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_interval_selection.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_interval_selection.dart index 8f831793..b8e9172c 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_interval_selection.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_interval_selection.dart @@ -24,7 +24,7 @@ class RangeSliderIntervalSelectionPage extends SampleView { class _RangeSliderIntervalSelectionPageState extends SampleViewState { _RangeSliderIntervalSelectionPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -35,7 +35,7 @@ class _RangeSliderIntervalSelectionPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 325, child: rangeSlider), @@ -105,18 +105,18 @@ class _RangeSliderIntervalSelectionState extends SampleViewState { enableTooltip: true)); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -136,12 +136,13 @@ class _RangeSliderIntervalSelectionState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.start, children: const [ Padding( - child: Icon(Icons.lightbulb_outline, - color: Colors.orange, size: 24.0), - padding: EdgeInsets.only(left: 15)), + padding: EdgeInsets.only(left: 15), + child: Icon(Icons.lightbulb_outline, + color: Colors.orange, size: 24.0), + ), Padding( - child: Text('Tap on the interval to select it.'), - padding: EdgeInsets.only(left: 5)) + padding: EdgeInsets.only(left: 5), + child: Text('Tap on the interval to select it.')) ]) ], )); @@ -149,6 +150,6 @@ class _RangeSliderIntervalSelectionState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_step.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_step.dart index d6b672a3..0ff91a78 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_step.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_step.dart @@ -23,7 +23,7 @@ class SliderStepDurationPage extends SampleView { class _SliderStepDurationPageState extends SampleViewState { _SliderStepDurationPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -34,7 +34,7 @@ class _SliderStepDurationPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -100,18 +100,18 @@ class _SliderStepDurationState extends SampleViewState { enableTooltip: true)); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -132,6 +132,6 @@ class _SliderStepDurationState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/range_slider/default_appearance/range_slider_tooltip_type.dart b/lib/samples/sliders/range_slider/default_appearance/range_slider_tooltip_type.dart index ac8c07ab..8c45906d 100644 --- a/lib/samples/sliders/range_slider/default_appearance/range_slider_tooltip_type.dart +++ b/lib/samples/sliders/range_slider/default_appearance/range_slider_tooltip_type.dart @@ -23,7 +23,7 @@ class TooltipRangeSliderPage extends SampleView { class _TooltipRangeSliderPageState extends SampleViewState { _TooltipRangeSliderPageState(); - Widget rangeSlider; + late Widget rangeSlider; @override void initState() { @@ -34,7 +34,7 @@ class _TooltipRangeSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? rangeSlider : SingleChildScrollView( child: Container(height: 300, child: rangeSlider), @@ -109,18 +109,18 @@ class _TooltipRangeSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -141,6 +141,6 @@ class _TooltipRangeSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/basic_features/default_slider.dart b/lib/samples/sliders/slider/basic_features/default_slider.dart index 96e03e88..e2869a9e 100644 --- a/lib/samples/sliders/slider/basic_features/default_slider.dart +++ b/lib/samples/sliders/slider/basic_features/default_slider.dart @@ -23,7 +23,7 @@ class DefaultSliderPage extends SampleView { class _DefaultSliderPageState extends SampleViewState { _DefaultSliderPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -34,7 +34,7 @@ class _DefaultSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -53,7 +53,12 @@ class _DefaultSliderState extends SampleViewState { SfSlider _inactiveSlider() { //ignore: missing_required_param - return SfSlider(min: 0.0, max: 100.0, value: _inactiveSliderValue); + return SfSlider( + min: 0.0, + max: 100.0, + value: _inactiveSliderValue, + onChanged: null, + ); } SfSliderTheme _activeSlider() { @@ -73,18 +78,18 @@ class _DefaultSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -102,6 +107,6 @@ class _DefaultSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/basic_features/slider_date_interval.dart b/lib/samples/sliders/slider/basic_features/slider_date_interval.dart index 27ac4dd3..9d2e71d5 100644 --- a/lib/samples/sliders/slider/basic_features/slider_date_interval.dart +++ b/lib/samples/sliders/slider/basic_features/slider_date_interval.dart @@ -23,7 +23,7 @@ class DateIntervalSliderPage extends SampleView { class _DateIntervalSliderPageState extends SampleViewState { _DateIntervalSliderPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -34,7 +34,7 @@ class _DateIntervalSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -104,18 +104,18 @@ class _DateIntervalSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -136,6 +136,6 @@ class _DateIntervalSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/basic_features/slider_divisor_label_tick.dart b/lib/samples/sliders/slider/basic_features/slider_divisor_label_tick.dart index c7c05355..f4bbb425 100644 --- a/lib/samples/sliders/slider/basic_features/slider_divisor_label_tick.dart +++ b/lib/samples/sliders/slider/basic_features/slider_divisor_label_tick.dart @@ -24,7 +24,7 @@ class SliderLabelCustomizationPage extends SampleView { class _SliderLabelCustomizationPageState extends SampleViewState { _SliderLabelCustomizationPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -35,7 +35,7 @@ class _SliderLabelCustomizationPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -112,18 +112,18 @@ class _SliderLabelCustomizationState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -145,6 +145,6 @@ class _SliderLabelCustomizationState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/basic_features/slider_step.dart b/lib/samples/sliders/slider/basic_features/slider_step.dart index 048085aa..2bf48e4d 100644 --- a/lib/samples/sliders/slider/basic_features/slider_step.dart +++ b/lib/samples/sliders/slider/basic_features/slider_step.dart @@ -23,7 +23,7 @@ class StepSliderPage extends SampleView { class _StepSliderPageState extends SampleViewState { _StepSliderPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -34,7 +34,7 @@ class _StepSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -97,18 +97,18 @@ class _StepSliderState extends SampleViewState { enableTooltip: true)); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -129,6 +129,6 @@ class _StepSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/basic_features/slider_tooltip_type.dart b/lib/samples/sliders/slider/basic_features/slider_tooltip_type.dart index 20f573c7..72eea2ee 100644 --- a/lib/samples/sliders/slider/basic_features/slider_tooltip_type.dart +++ b/lib/samples/sliders/slider/basic_features/slider_tooltip_type.dart @@ -23,7 +23,7 @@ class SliderTooltipTypeSliderPage extends SampleView { class _SliderTooltipPageState extends SampleViewState { _SliderTooltipPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -34,7 +34,7 @@ class _SliderTooltipPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 325, child: slider), @@ -105,18 +105,18 @@ class _SliderTooltipTypeState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -137,6 +137,6 @@ class _SliderTooltipTypeState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/customization/color_customization/slider_color_customization.dart b/lib/samples/sliders/slider/customization/color_customization/slider_color_customization.dart index 149fd513..e27af80f 100644 --- a/lib/samples/sliders/slider/customization/color_customization/slider_color_customization.dart +++ b/lib/samples/sliders/slider/customization/color_customization/slider_color_customization.dart @@ -24,7 +24,7 @@ class SliderColorCustomizationPage extends SampleView { class _SliderColorCustomizationPageState extends SampleViewState { _SliderColorCustomizationPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -35,7 +35,7 @@ class _SliderColorCustomizationPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 325, child: slider), @@ -80,10 +80,12 @@ class _SliderColorCustomizationState extends SampleViewState { SfSliderTheme _sliderWithThumbStrokeColorCustomization() { return SfSliderTheme( data: SfSliderThemeData( - inactiveDivisorColor: - model.isWeb ? model.webBackgroundColor : model.cardThemeColor, - activeDivisorColor: - model.isWeb ? model.webBackgroundColor : model.cardThemeColor, + inactiveDivisorColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, + activeDivisorColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, activeDivisorStrokeWidth: 2, activeDivisorStrokeColor: Colors.deepOrange.withOpacity(0.24), inactiveDivisorStrokeWidth: 2, @@ -93,8 +95,9 @@ class _SliderColorCustomizationState extends SampleViewState { activeTrackColor: Colors.deepOrange, inactiveTrackColor: Colors.deepOrange.withOpacity(0.24), overlayColor: Colors.deepOrange.withOpacity(0.12), - thumbColor: - model.isWeb ? model.webBackgroundColor : model.cardThemeColor, + thumbColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, thumbStrokeWidth: 2.0, tooltipBackgroundColor: Colors.deepOrange, thumbStrokeColor: Colors.deepOrange), @@ -113,18 +116,18 @@ class _SliderColorCustomizationState extends SampleViewState { numberFormat: NumberFormat('#'))); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -145,6 +148,6 @@ class _SliderColorCustomizationState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/customization/shape_customization/slider_divisor_customization.dart b/lib/samples/sliders/slider/customization/shape_customization/slider_divisor_customization.dart index b0ae5cfd..71044f06 100644 --- a/lib/samples/sliders/slider/customization/shape_customization/slider_divisor_customization.dart +++ b/lib/samples/sliders/slider/customization/shape_customization/slider_divisor_customization.dart @@ -46,23 +46,23 @@ class _DivisorShape extends SfDivisorShape { SampleModel model; @override - void paint(PaintingContext context, Offset center, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset center, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection}) { bool isActive; switch (textDirection) { case TextDirection.ltr: - isActive = center.dx <= thumbCenter.dx; + isActive = center.dx <= thumbCenter!.dx; break; case TextDirection.rtl: - isActive = center.dx >= thumbCenter.dx; + isActive = center.dx >= thumbCenter!.dx; break; } @@ -72,7 +72,7 @@ class _DivisorShape extends SfDivisorShape { ..isAntiAlias = true ..style = PaintingStyle.fill ..color = isActive - ? themeData.activeTrackColor + ? themeData.activeTrackColor! : model.themeData.canvasColor); } } diff --git a/lib/samples/sliders/slider/customization/shape_customization/slider_shape_customization.dart b/lib/samples/sliders/slider/customization/shape_customization/slider_shape_customization.dart index df619ea7..03af583e 100644 --- a/lib/samples/sliders/slider/customization/shape_customization/slider_shape_customization.dart +++ b/lib/samples/sliders/slider/customization/shape_customization/slider_shape_customization.dart @@ -29,7 +29,7 @@ class ShapeCustomizedSliderPage extends SampleView { class _ShapeCustomizedSliderPageState extends SampleViewState { _ShapeCustomizedSliderPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -40,7 +40,7 @@ class _ShapeCustomizedSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container( @@ -63,18 +63,18 @@ class _ShapeCustomizedSliderState extends SampleViewState { final double _min = 0.0; final double _max = 100.0; - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -114,7 +114,7 @@ class _ShapeCustomizedSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } @@ -128,26 +128,21 @@ class _SfTrackShape extends SfTrackShape { : max; } - double min; - double max; - double trackIntermediatePos; + late double min; + late double max; + double? trackIntermediatePos; @override - void paint( - PaintingContext context, - Offset offset, - Offset thumbCenter, - Offset startThumbCenter, - Offset endThumbCenter, { - RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, - dynamic currentValue, - Animation enableAnimation, - Paint inactivePaint, - Paint activePaint, - TextDirection textDirection, - }) { + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Animation enableAnimation, + required Paint? inactivePaint, + required Paint? activePaint, + required TextDirection textDirection}) { final Rect trackRect = getPreferredRect(parentBox, themeData, offset); final double actualValue = currentValue.runtimeType == DateTime ? currentValue.millisecondsSinceEpoch.toDouble() @@ -160,19 +155,19 @@ class _SfTrackShape extends SfTrackShape { final Paint trackPaint = Paint(); trackPaint.color = actualValueInPercent <= 80.0 ? Colors.green : Colors.red; final Rect lowVolumeRect = Rect.fromLTRB( - trackRect.left, trackRect.top, thumbCenter.dx, trackRect.bottom); + trackRect.left, trackRect.top, thumbCenter!.dx, trackRect.bottom); context.canvas.drawRect(lowVolumeRect, trackPaint); if (actualValueInPercent <= 80.0) { trackPaint.color = Colors.green.withOpacity(0.40); final Rect lowVolumeRectWithLessOpacity = Rect.fromLTRB(thumbCenter.dx, - trackRect.top, trackIntermediatePos, trackRect.bottom); + trackRect.top, trackIntermediatePos!, trackRect.bottom); context.canvas.drawRect(lowVolumeRectWithLessOpacity, trackPaint); } trackPaint.color = Colors.red.withOpacity(0.40); final double highTrackLeft = - actualValueInPercent >= 80.0 ? thumbCenter.dx : trackIntermediatePos; + actualValueInPercent >= 80.0 ? thumbCenter.dx : trackIntermediatePos!; final Rect highVolumeRectWithLessOpacity = Rect.fromLTRB(highTrackLeft, trackRect.top, trackRect.width + trackRect.left, trackRect.bottom); context.canvas.drawRect(highVolumeRectWithLessOpacity, trackPaint); @@ -195,20 +190,20 @@ class _SfThumbShape extends SfThumbShape { : max; } - double min; - double max; + late double min; + late double max; @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { final double actualValue = currentValue.runtimeType == DateTime ? currentValue.millisecondsSinceEpoch.toDouble() : currentValue; @@ -225,6 +220,8 @@ class _SfThumbShape extends SfThumbShape { currentValue: currentValue, paint: paint, enableAnimation: enableAnimation, - textDirection: textDirection); + textDirection: textDirection, + thumb: thumb, + child: child); } } diff --git a/lib/samples/sliders/slider/customization/shape_customization/slider_thumb_customization.dart b/lib/samples/sliders/slider/customization/shape_customization/slider_thumb_customization.dart index eaee3eab..14071cad 100644 --- a/lib/samples/sliders/slider/customization/shape_customization/slider_thumb_customization.dart +++ b/lib/samples/sliders/slider/customization/shape_customization/slider_thumb_customization.dart @@ -65,15 +65,15 @@ class _ThumbCustomizedSliderState extends SampleViewState { class _RectThumbShape extends SfThumbShape { @override void paint(PaintingContext context, Offset center, - {RenderBox parentBox, - RenderBox child, - SfSliderThemeData themeData, - SfRangeValues currentValues, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Paint paint, - Animation enableAnimation, - TextDirection textDirection, - SfThumb thumb}) { + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { super.paint(context, center, parentBox: parentBox, child: child, @@ -93,7 +93,7 @@ class _RectThumbShape extends SfThumbShape { context.canvas.drawPath( path, Paint() - ..color = themeData.activeTrackColor + ..color = themeData.activeTrackColor! ..style = PaintingStyle.fill ..strokeWidth = 2); } diff --git a/lib/samples/sliders/slider/customization/shape_customization/slider_tick_customization.dart b/lib/samples/sliders/slider/customization/shape_customization/slider_tick_customization.dart index d0936884..9b4563b8 100644 --- a/lib/samples/sliders/slider/customization/shape_customization/slider_tick_customization.dart +++ b/lib/samples/sliders/slider/customization/shape_customization/slider_tick_customization.dart @@ -62,16 +62,16 @@ class _TickCustomizedSliderState extends SampleViewState { class _TickShape extends SfTickShape { @override - void paint(PaintingContext context, Offset offset, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Animation enableAnimation, - TextDirection textDirection}) { + required Animation enableAnimation, + required TextDirection textDirection}) { final Size tickSize = getPreferredSize(themeData); - final bool isTickRightOfThumb = offset.dx > thumbCenter.dx; + final bool isTickRightOfThumb = offset.dx > thumbCenter!.dx; final Color begin = isTickRightOfThumb ? themeData.disabledInactiveTickColor : themeData.disabledActiveTickColor; @@ -81,19 +81,19 @@ class _TickShape extends SfTickShape { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = tickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation); + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; context.canvas.drawLine( Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight)), Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight) - tickSize.height), @@ -103,16 +103,16 @@ class _TickShape extends SfTickShape { class _MinorTickShape extends SfTickShape { @override - void paint(PaintingContext context, Offset offset, Offset thumbCenter, - Offset startThumbCenter, Offset endThumbCenter, - {RenderBox parentBox, - SfSliderThemeData themeData, - SfRangeValues currentValues, + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, dynamic currentValue, - Animation enableAnimation, - TextDirection textDirection}) { + required Animation enableAnimation, + required TextDirection textDirection}) { final Size minorTickSize = getPreferredSize(themeData); - final bool isMinorTickRightOfThumb = offset.dx > thumbCenter.dx; + final bool isMinorTickRightOfThumb = offset.dx > thumbCenter!.dx; final Color begin = isMinorTickRightOfThumb ? themeData.disabledInactiveMinorTickColor @@ -123,19 +123,19 @@ class _MinorTickShape extends SfTickShape { final Paint paint = Paint() ..isAntiAlias = true ..strokeWidth = minorTickSize.width - ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation); + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation)!; context.canvas.drawLine( Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight)), Offset( offset.dx, offset.dy - - 2 * themeData.tickOffset.dy - + 2 * themeData.tickOffset!.dy - math.max(themeData.activeTrackHeight, themeData.inactiveTrackHeight) - minorTickSize.height), diff --git a/lib/samples/sliders/slider/customization/size_customization/slider_size_customization.dart b/lib/samples/sliders/slider/customization/size_customization/slider_size_customization.dart index 5e8eb43a..790608ac 100644 --- a/lib/samples/sliders/slider/customization/size_customization/slider_size_customization.dart +++ b/lib/samples/sliders/slider/customization/size_customization/slider_size_customization.dart @@ -24,7 +24,7 @@ class SliderSizeCustomizationPage extends SampleView { class _SliderSizeCustomizationPageState extends SampleViewState { _SliderSizeCustomizationPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -35,7 +35,7 @@ class _SliderSizeCustomizationPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -111,18 +111,18 @@ class _SfSliderSizeCustomizationState extends SampleViewState { enableTooltip: true)); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -143,6 +143,6 @@ class _SfSliderSizeCustomizationState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider/customization/thumb_customization/thumb_icon_customization.dart b/lib/samples/sliders/slider/customization/thumb_customization/thumb_icon_customization.dart index 9278354e..69d5621e 100644 --- a/lib/samples/sliders/slider/customization/thumb_customization/thumb_icon_customization.dart +++ b/lib/samples/sliders/slider/customization/thumb_customization/thumb_icon_customization.dart @@ -23,7 +23,7 @@ class ThumbCustomizationSliderPage extends SampleView { class _ThumbCustomizationSliderPageState extends SampleViewState { _ThumbCustomizationSliderPageState(); - Widget slider; + late Widget slider; @override void initState() { @@ -34,7 +34,7 @@ class _ThumbCustomizationSliderPageState extends SampleViewState { @override Widget build(BuildContext context) { return MediaQuery.of(context).orientation == Orientation.portrait || - model.isWeb + model.isWebFullView ? slider : SingleChildScrollView( child: Container(height: 300, child: slider), @@ -114,18 +114,18 @@ class _ThumbCustomizationSliderState extends SampleViewState { )); } - Widget _getWebLayout() { + Widget _buildWebLayout() { return Container( alignment: Alignment.center, child: Container( alignment: Alignment.center, width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, - child: _getMobileLayout(), + child: _buildMobileLayout(), ), ); } - Widget _getMobileLayout() { + Widget _buildMobileLayout() { final double padding = MediaQuery.of(context).size.width / 20.0; return Container( padding: EdgeInsets.fromLTRB(padding, 0, padding, 0), @@ -146,6 +146,6 @@ class _ThumbCustomizationSliderState extends SampleViewState { @override Widget build(BuildContext context) { - return model.isWeb ? _getWebLayout() : _getMobileLayout(); + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); } } diff --git a/lib/samples/sliders/slider_utils.dart b/lib/samples/sliders/slider_utils.dart index ae1fdc38..9f17c2a7 100644 --- a/lib/samples/sliders/slider_utils.dart +++ b/lib/samples/sliders/slider_utils.dart @@ -20,9 +20,6 @@ Widget get columnSpacing30 { Widget title(String text) { return Align( alignment: Alignment.centerLeft, - child: Padding( - child: Text(text), - padding: const EdgeInsets.only(left: 25), - ), + child: Padding(padding: const EdgeInsets.only(left: 25), child: Text(text)), ); } diff --git a/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_color_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_color_customization.dart new file mode 100644 index 00000000..71739ab3 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_color_customization.dart @@ -0,0 +1,66 @@ +///Package import +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +///Local import +import '../../../../../model/sample_view.dart'; +import 'vertical_range_slider_gradient_color_customization.dart'; + +///Renders range slider with customized color +class VerticalColorCustomizedRangeSliderPage extends SampleView { + ///Creates range slider with customized color + const VerticalColorCustomizedRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalColorCustomizedRangeSliderPageState createState() => + _VerticalColorCustomizedRangeSliderPageState(); +} + +class _VerticalColorCustomizedRangeSliderPageState extends SampleViewState { + _VerticalColorCustomizedRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _ColorCustomizedRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _ColorCustomizedRangeSlider extends SampleView { + @override + _ColorCustomizedRangeSliderState createState() => + _ColorCustomizedRangeSliderState(); +} + +class _ColorCustomizedRangeSliderState extends SampleViewState { + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + return VerticalGradientTrackRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_gradient_color_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_gradient_color_customization.dart new file mode 100644 index 00000000..547dce3d --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/color_customization/vertical_range_slider_gradient_color_customization.dart @@ -0,0 +1,309 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +/// Renders range slider with gradient track +class VerticalGradientTrackRangeSlider extends SampleView { + @override + _VerticalGradientTrackRangeSliderState createState() => + _VerticalGradientTrackRangeSliderState(); +} + +class _VerticalGradientTrackRangeSliderState extends SampleViewState { + SfRangeValues _blueGradientSliderValues = const SfRangeValues(2.0, 4.0); + SfRangeValues _sliderValues = const SfRangeValues(30.0, 70.0); + + final Color _inactiveColor = const Color.fromRGBO(194, 194, 194, 0.5); + + LinearGradient get _blueGradientColor { + final List colors = []; + colors.add(const Color.fromARGB(255, 0, 238, 217)); + colors.add(const Color.fromARGB(255, 88, 124, 241)); + final List stops = [0.0, 1.0]; + return LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: colors, + stops: stops); + } + + SfRangeSliderTheme _blueGradientRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTrackColor: _inactiveColor, + thumbColor: Colors.white, + overlayColor: const Color.fromARGB(255, 0, 238, 217).withOpacity(0.12), + activeTrackHeight: 8.0, + inactiveTrackHeight: 8.0, + trackCornerRadius: 4.0, + ), + child: SfRangeSlider.vertical( + min: 0.0, + max: 6.0, + values: _blueGradientSliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _blueGradientSliderValues = values; + }); + }, + thumbShape: _ThumbShape( + _blueGradientColor.colors[0], _blueGradientColor.colors[1]), + overlayShape: _OverlayShape( + _blueGradientColor.colors[0], _blueGradientColor.colors[1]), + trackShape: _TrackShape(_blueGradientColor), + ), + ); + } + + SfRangeSliderTheme _rangeSliderWithThumbCustomization() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveDivisorColor: Colors.white, + activeDivisorColor: Colors.white, + activeDivisorStrokeWidth: 2, + activeDivisorStrokeColor: _inactiveColor, + inactiveDivisorStrokeWidth: 2, + inactiveDivisorStrokeColor: Colors.tealAccent, + activeDivisorRadius: 5.0, + inactiveDivisorRadius: 5.0, + activeTrackColor: Colors.tealAccent, + inactiveTrackColor: _inactiveColor, + overlayColor: Colors.tealAccent.withOpacity(0.12), + labelOffset: Offset(10, 0), + thumbColor: Colors.white, + thumbStrokeWidth: 2.0, + thumbStrokeColor: Colors.tealAccent), + child: SfRangeSlider.vertical( + min: 10.0, + max: 90.0, + interval: 20.0, + showLabels: true, + showDivisors: true, + values: _sliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _sliderValues = values; + }); + }, + ), + ); + } + + @override + Widget build(BuildContext context) { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(0, padding, 0, padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column(children: [ + Expanded(child: _TrackColorCustomizedRangeSlider()), + Text('Track') + ]), + Column(children: [ + Expanded(child: _rangeSliderWithThumbCustomization()), + Text('Stroke'), + ]), + Column(children: [ + Expanded(child: _blueGradientRangeSlider()), + Text('Gradient'), + ]) + ], + )); + } +} + +class _ThumbShape extends SfThumbShape { + const _ThumbShape(this.leftThumbColor, this.rightThumbColor); + + final Color leftThumbColor; + final Color rightThumbColor; + + @override + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { + super.paint(context, center, + parentBox: parentBox, + child: child, + themeData: themeData, + currentValues: currentValues, + paint: paint, + enableAnimation: enableAnimation, + textDirection: textDirection, + thumb: thumb); + + context.canvas.drawCircle( + center, + getPreferredSize(themeData).width / 2, + Paint() + ..isAntiAlias = true + ..strokeWidth = 2 + ..style = PaintingStyle.stroke + ..color = thumb == SfThumb.start ? leftThumbColor : rightThumbColor); + } +} + +class _OverlayShape extends SfOverlayShape { + const _OverlayShape(this.leftThumbColor, this.rightThumbColor); + + final Color leftThumbColor; + final Color rightThumbColor; + + @override + void paint(PaintingContext context, Offset center, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Paint? paint, + Animation? animation, + SfThumb? thumb}) { + final double radius = getPreferredSize(themeData!).width / 2; + final Tween tween = Tween(begin: 0.0, end: radius); + + context.canvas.drawCircle( + center, + tween.evaluate(animation!), + Paint() + ..isAntiAlias = true + ..strokeWidth = 0 + ..color = (thumb == SfThumb.start ? leftThumbColor : rightThumbColor) + .withOpacity(0.12)); + } +} + +class _TrackShape extends SfTrackShape { + const _TrackShape(this.gradient); + + final Gradient gradient; + + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Animation? enableAnimation, + Paint? inactivePaint, + Paint? activePaint, + TextDirection? textDirection}) { + final Radius radius = Radius.circular(themeData!.trackCornerRadius!); + final Rect actualTrackRect = + getPreferredRect(parentBox!, themeData, offset); + + if (endThumbCenter == null) { + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = 0 + ..color = themeData.activeTrackColor!; + + Rect trackRect = Rect.fromLTRB(actualTrackRect.left, thumbCenter!.dy, + actualTrackRect.right, actualTrackRect.bottom); + final RRect leftRRect = RRect.fromRectAndCorners(trackRect, + topLeft: radius, bottomLeft: radius); + context.canvas.drawRRect(leftRRect, paint); + + paint.color = themeData.inactiveTrackColor!; + trackRect = Rect.fromLTRB(actualTrackRect.left, actualTrackRect.top, + actualTrackRect.right, thumbCenter.dy); + final RRect rightRRect = RRect.fromRectAndCorners(trackRect, + topRight: radius, bottomRight: radius); + context.canvas.drawRRect(rightRRect, paint); + } else { + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = 0 + ..color = themeData.inactiveTrackColor!; + + // Drawing inactive track. + Rect trackRect = Rect.fromLTRB(actualTrackRect.left, startThumbCenter!.dy, + actualTrackRect.right, actualTrackRect.bottom); + final RRect leftRRect = RRect.fromRectAndCorners(trackRect, + bottomRight: radius, bottomLeft: radius); + context.canvas.drawRRect(leftRRect, paint); + + // Drawing active track. + trackRect = Rect.fromLTRB(actualTrackRect.left, endThumbCenter.dy, + actualTrackRect.right, startThumbCenter.dy); + paint.shader = gradient.createShader(trackRect); + paint.color = themeData.activeTrackColor!; + final RRect centerRRect = RRect.fromRectAndCorners(trackRect, + topLeft: Radius.zero, + topRight: Radius.zero, + bottomLeft: Radius.zero, + bottomRight: Radius.zero); + context.canvas.drawRRect(centerRRect, paint); + + // Drawing inactive track. + paint.shader = null; + paint.color = themeData.inactiveTrackColor!; + trackRect = Rect.fromLTRB(actualTrackRect.left, actualTrackRect.top, + actualTrackRect.right, endThumbCenter.dy); + final RRect rightRRect = RRect.fromRectAndCorners(trackRect, + topLeft: radius, + topRight: radius, + bottomLeft: Radius.zero, + bottomRight: Radius.zero); + context.canvas.drawRRect(rightRRect, paint); + } + } +} + +class _TrackColorCustomizedRangeSlider extends SampleView { + @override + _TrackColorCustomizedRangeSliderState createState() => + _TrackColorCustomizedRangeSliderState(); +} + +class _TrackColorCustomizedRangeSliderState extends SampleViewState { + final double _min = 0.0; + final double _max = 6.0; + final Color _activeColor = const Color.fromRGBO(255, 125, 30, 1); + final Color _inactiveTickColor = const Color.fromRGBO(200, 200, 200, 1); + SfRangeValues _values = const SfRangeValues(2.0, 4.0); + + @override + Widget build(BuildContext context) { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTickColor: _inactiveTickColor, + activeTickColor: _activeColor, + inactiveMinorTickColor: _inactiveTickColor, + activeMinorTickColor: _activeColor, + inactiveTrackColor: const Color.fromRGBO(194, 194, 194, 0.5)), + child: SfRangeSlider.vertical( + min: _min, + max: _max, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + interval: 1, + minorTicksPerInterval: 3, + showTicks: true, + activeColor: _activeColor, + ), + ); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_divisor_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_divisor_customization.dart new file mode 100644 index 00000000..5a2f45a5 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_divisor_customization.dart @@ -0,0 +1,86 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/model.dart'; +import '../../../../../model/sample_view.dart'; + +///Renders range slider with customized divisor +class VerticalDivisorCustomizedRangeSlider extends SampleView { + @override + _VerticalDivisorCustomizedRangeSliderState createState() => + _VerticalDivisorCustomizedRangeSliderState(); +} + +class _VerticalDivisorCustomizedRangeSliderState extends SampleViewState { + final Color _inactiveColor = const Color.fromARGB(255, 194, 194, 194); + final Color _activeColor = Colors.blue; + SfRangeValues _values = const SfRangeValues(30.0, 70.0); + + @override + Widget build(BuildContext context) { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTrackColor: _inactiveColor.withOpacity(0.5), + activeTrackColor: _activeColor, + thumbColor: _activeColor, + inactiveDivisorColor: const Color.fromARGB(255, 194, 194, 194), + activeDivisorColor: Colors.blue, + overlayColor: _activeColor.withOpacity(0.12), + tooltipBackgroundColor: _activeColor), + child: SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + interval: 10, + showDivisors: true, + enableTooltip: true, + numberFormat: NumberFormat('#'), + divisorShape: _DivisorShape(model), + ), + ); + } +} + +class _DivisorShape extends SfDivisorShape { + _DivisorShape(this.model); + + SampleModel model; + + @override + void paint(PaintingContext context, Offset center, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Paint? paint, + Animation? enableAnimation, + TextDirection? textDirection}) { + bool isActive; + isActive = + center.dy <= startThumbCenter!.dy && center.dy >= endThumbCenter!.dy; + + context.canvas.drawRect( + Rect.fromCenter(center: center, width: 10.0, height: 5.0), + Paint() + ..isAntiAlias = true + ..style = PaintingStyle.fill + ..color = isActive + ? themeData!.activeDivisorColor! + : model.themeData.canvasColor); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_shape_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_shape_customization.dart new file mode 100644 index 00000000..697ef940 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_shape_customization.dart @@ -0,0 +1,84 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; +import 'vertical_range_slider_divisor_customization.dart'; +import 'vertical_range_slider_thumb_customization.dart'; +import 'vertical_range_slider_tick_customization.dart'; + +/// Renders range slider with customized shapes +class VerticalShapeCustomizedRangeSliderPage extends SampleView { + /// Creates range slider with customized shapes + const VerticalShapeCustomizedRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalShapeCustomizedRangeSliderPageState createState() => + _VerticalShapeCustomizedRangeSliderPageState(); +} + +class _VerticalShapeCustomizedRangeSliderPageState extends SampleViewState { + _VerticalShapeCustomizedRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _ShapeCustomizedRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _ShapeCustomizedRangeSlider extends SampleView { + @override + _ShapeCustomizedRangeSliderState createState() => + _ShapeCustomizedRangeSliderState(); +} + +class _ShapeCustomizedRangeSliderState extends SampleViewState { + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(0, padding, 0, padding), + child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + Column(children: [ + Expanded(child: VerticalThumbCustomizedRangeSlider()), + Text('Thumb') + ]), + Column(children: [ + Expanded(child: VerticalDivisorCustomizedRangeSlider()), + Text('Divisor'), + ]), + Column(children: [ + Expanded(child: VerticalTickCustomizedRangeSlider()), + Text('Tick'), + ]), + ])); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_thumb_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_thumb_customization.dart new file mode 100644 index 00000000..2afa8d14 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_thumb_customization.dart @@ -0,0 +1,186 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders range slider with customized thumb +class VerticalThumbCustomizedRangeSlider extends SampleView { + @override + _VerticalThumbCustomizedRangeSliderState createState() => + _VerticalThumbCustomizedRangeSliderState(); +} + +class _VerticalThumbCustomizedRangeSliderState extends SampleViewState { + SfRangeValues _singleStrokeSliderValues = const SfRangeValues(30.0, 70.0); + SfRangeValues _doubleStrokeSliderValues = const SfRangeValues(30.0, 70.0); + final Color _inactiveColor = const Color.fromARGB(255, 255, 146, 176); + final Color _activeColor = const Color.fromARGB(255, 255, 0, 58); + + SfRangeSliderTheme _strokeThumbRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTrackColor: _inactiveColor, + activeTrackColor: _activeColor, + thumbColor: Colors.white, + overlayColor: _activeColor.withOpacity(0.12), + tickOffset: const Offset(13, 0), + inactiveTickColor: _inactiveColor, + activeTickColor: _activeColor, + inactiveMinorTickColor: _inactiveColor, + activeMinorTickColor: _activeColor, + tooltipBackgroundColor: _activeColor, + ), + child: SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + values: _singleStrokeSliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _singleStrokeSliderValues = values; + }); + }, + interval: 10, + minorTicksPerInterval: 3, + showTicks: true, + enableTooltip: true, + numberFormat: NumberFormat('#'), + thumbShape: _RectThumbShape(), + ), + ); + } + + SfRangeSliderTheme _doubleStrokeThumbRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTrackColor: + const Color.fromARGB(255, 200, 200, 200).withOpacity(0.5), + tooltipBackgroundColor: const Color.fromARGB(255, 0, 178, 206), + ), + child: SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + values: _doubleStrokeSliderValues, + tooltipPosition: SliderTooltipPosition.right, + onChanged: (SfRangeValues values) { + setState(() { + _doubleStrokeSliderValues = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'), + thumbShape: const _ThumbShape(true), + activeColor: const Color.fromARGB(255, 0, 178, 206), + ), + ); + } + + @override + Widget build(BuildContext context) { + final double padding = + MediaQuery.of(context).orientation == Orientation.landscape + ? 80.0 + : 50.0; + return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + _doubleStrokeThumbRangeSlider(), + Padding( + padding: EdgeInsets.only(left: padding), + child: _strokeThumbRangeSlider()) + ]); + } +} + +class _ThumbShape extends SfThumbShape { + const _ThumbShape(this.isDoubleStroke); + + final bool isDoubleStroke; + + @override + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { + super.paint(context, center, + parentBox: parentBox, + child: child, + themeData: themeData, + currentValues: currentValues, + paint: paint, + enableAnimation: enableAnimation, + textDirection: textDirection, + thumb: thumb); + + context.canvas.drawCircle( + center, + getPreferredSize(themeData).width / 2, + Paint() + ..isAntiAlias = true + ..strokeWidth = 2 + ..style = PaintingStyle.stroke + ..color = themeData.activeTrackColor!); + + if (isDoubleStroke) { + context.canvas.drawCircle( + center, + getPreferredSize(themeData).width / 3, + Paint() + ..isAntiAlias = true + ..strokeWidth = 3 + ..style = PaintingStyle.stroke + ..color = Colors.white); + } + } +} + +class _RectThumbShape extends SfThumbShape { + @override + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { + super.paint(context, center, + parentBox: parentBox, + child: child, + themeData: themeData, + currentValues: currentValues, + paint: paint, + enableAnimation: enableAnimation, + textDirection: textDirection, + thumb: thumb); + + final double width = getPreferredSize(themeData).width; + final double height = getPreferredSize(themeData).height; + + context.canvas.drawRRect( + RRect.fromLTRBR( + center.dx - width / 2, + center.dy - height / 2, + center.dx + width / 2, + center.dy + height / 2, + const Radius.circular(5.0)), + Paint() + ..isAntiAlias = true + ..style = PaintingStyle.fill + ..color = themeData.activeTrackColor!); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_tick_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_tick_customization.dart new file mode 100644 index 00000000..0a26fe8f --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/shape_customization/vertical_range_slider_tick_customization.dart @@ -0,0 +1,152 @@ +///Dart import +import 'dart:math' as math; + +///flutter package import +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders range slider with customized tick +class VerticalTickCustomizedRangeSlider extends SampleView { + @override + _VerticalTickCustomizedRangeSliderState createState() => + _VerticalTickCustomizedRangeSliderState(); +} + +class _VerticalTickCustomizedRangeSliderState extends SampleViewState { + SfRangeValues _values = const SfRangeValues(30.0, 70.0); + final Color _inactiveColor = const Color.fromARGB(255, 194, 194, 194); + final Color _activeColor = const Color.fromARGB(255, 255, 0, 58); + + @override + Widget build(BuildContext context) { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + inactiveTrackColor: _inactiveColor.withOpacity(0.5), + activeTrackColor: _activeColor, + inactiveTickColor: _inactiveColor.withOpacity(0.8), + activeTickColor: _activeColor, + inactiveMinorTickColor: _inactiveColor, + activeMinorTickColor: _activeColor, + thumbColor: _activeColor, + overlayColor: _activeColor.withOpacity(0.24), + tickOffset: const Offset(0, 0), + tooltipBackgroundColor: _activeColor), + child: SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + interval: 10, + minorTicksPerInterval: 3, + showTicks: true, + enableTooltip: true, + numberFormat: NumberFormat('#'), + tickShape: _TickShape(), + minorTickShape: _MinorTickShape(), + ), + ); + } +} + +class _TickShape extends SfTickShape { + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Animation? enableAnimation, + TextDirection? textDirection}) { + final Size tickSize = getPreferredSize(themeData!); + final bool isTickRightOfThumb = endThumbCenter == null + ? offset.dy < thumbCenter!.dy + : offset.dy > startThumbCenter!.dy || offset.dy < endThumbCenter.dy; + final Color begin = isTickRightOfThumb + ? themeData.disabledInactiveTickColor + : themeData.disabledActiveTickColor; + final Color end = isTickRightOfThumb + ? themeData.inactiveTickColor + : themeData.activeTickColor; + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = tickSize.height + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation!)!; + context.canvas + .drawLine(offset, Offset(offset.dx + tickSize.width, offset.dy), paint); + context.canvas.drawLine( + Offset( + offset.dx - + 2 * themeData.tickOffset!.dx - + math.max( + themeData.activeTrackHeight, themeData.inactiveTrackHeight), + offset.dy), + Offset( + offset.dx - + 2 * themeData.tickOffset!.dx - + math.max(themeData.activeTrackHeight, + themeData.inactiveTrackHeight) - + tickSize.width, + offset.dy), + paint); + } +} + +class _MinorTickShape extends SfTickShape { + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Animation? enableAnimation, + TextDirection? textDirection, + bool? isVertical}) { + final Size minorTickSize = getPreferredSize(themeData!); + final bool isMinorTickRightOfThumb = endThumbCenter == null + ? offset.dy < thumbCenter!.dy + : offset.dy > startThumbCenter!.dy || offset.dy < endThumbCenter.dy; + final Color begin = isMinorTickRightOfThumb + ? themeData.disabledInactiveMinorTickColor + : themeData.disabledActiveMinorTickColor; + final Color end = isMinorTickRightOfThumb + ? themeData.inactiveMinorTickColor + : themeData.activeMinorTickColor; + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = minorTickSize.height + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation!)!; + context.canvas.drawLine( + offset, Offset(offset.dx + minorTickSize.width, offset.dy), paint); + context.canvas.drawLine( + Offset( + offset.dx - + 2 * themeData.tickOffset!.dx - + math.max( + themeData.activeTrackHeight, themeData.inactiveTrackHeight), + offset.dy), + Offset( + offset.dx - + 2 * themeData.tickOffset!.dx - + math.max(themeData.activeTrackHeight, + themeData.inactiveTrackHeight) - + minorTickSize.width, + offset.dy), + paint); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/size_customization/vertical_range_slider_size_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/size_customization/vertical_range_slider_size_customization.dart new file mode 100644 index 00000000..7807482d --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/size_customization/vertical_range_slider_size_customization.dart @@ -0,0 +1,153 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders range slider with customized size +class VerticalSfRangeSliderSizeCustomizationPage extends SampleView { + ///Creates range slider with customized divisor + const VerticalSfRangeSliderSizeCustomizationPage(Key key) : super(key: key); + + @override + _VerticalSfRangeSliderSizeCustomizationPageState createState() => + _VerticalSfRangeSliderSizeCustomizationPageState(); +} + +class _VerticalSfRangeSliderSizeCustomizationPageState extends SampleViewState { + _VerticalSfRangeSliderSizeCustomizationPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _SfRangeSliderSizeCustomization(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _SfRangeSliderSizeCustomization extends SampleView { + @override + _SfRangeSliderSizeCustomizationState createState() => + _SfRangeSliderSizeCustomizationState(); +} + +class _SfRangeSliderSizeCustomizationState extends SampleViewState { + SfRangeValues _yearValues = + SfRangeValues(DateTime(2005, 1, 01), DateTime(2015, 1, 1)); + SfRangeValues _values = const SfRangeValues(-25.0, 25.0); + + SfRangeSliderTheme _divisorCustomizationRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + activeDivisorRadius: 6.0, + inactiveDivisorRadius: 3.0, + inactiveDivisorColor: Colors.teal.withOpacity(0.24), + activeDivisorColor: Colors.teal, + activeTrackColor: Colors.teal, + thumbColor: Colors.teal, + tooltipBackgroundColor: Colors.teal, + overlayColor: Colors.teal.withOpacity(0.12), + inactiveTrackColor: Colors.teal.withOpacity(0.24)), + child: SfRangeSlider.vertical( + min: DateTime(2000, 01, 01), + max: DateTime(2020, 01, 01), + showLabels: true, + interval: 5, + stepDuration: const SliderStepDuration(years: 5), + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.years, + showDivisors: true, + values: _yearValues, + onChanged: (SfRangeValues values) { + setState(() { + _yearValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfRangeSliderTheme _numericRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + activeTrackHeight: 8.0, + inactiveTrackHeight: 4.0, + activeTrackColor: Colors.orange, + thumbColor: Colors.orange, + tooltipBackgroundColor: Colors.orange, + overlayColor: Colors.orange.withOpacity(0.12), + inactiveTrackColor: Colors.orange.withOpacity(0.24)), + child: SfRangeSlider.vertical( + showLabels: true, + interval: 25, + min: -50.0, + max: 50.0, + stepSize: 25, + showTicks: true, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + enableTooltip: true)); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _numericRangeSlider()), + Text('Track') + ]), + Column(children: [ + Expanded(child: _divisorCustomizationRangeSlider()), + Text('Divisor') + ]) + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/customization/thumb_customization/vertical_range_slider_thumb_icon_customization.dart b/lib/samples/sliders/vertical_range_slider/customization/thumb_customization/vertical_range_slider_thumb_icon_customization.dart new file mode 100644 index 00000000..e69613f0 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/customization/thumb_customization/vertical_range_slider_thumb_icon_customization.dart @@ -0,0 +1,144 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders range slider with customized thumb icon +class VerticalThumbCustomizationRangeSliderPage extends SampleView { + ///Creates range slider with customized thumb icon + const VerticalThumbCustomizationRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalThumbCustomizationRangeSliderPageState createState() => + _VerticalThumbCustomizationRangeSliderPageState(); +} + +class _VerticalThumbCustomizationRangeSliderPageState extends SampleViewState { + _VerticalThumbCustomizationRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _ThumbCustomizationRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _ThumbCustomizationRangeSlider extends SampleView { + @override + _ThumbCustomizationRangeSliderState createState() => + _ThumbCustomizationRangeSliderState(); +} + +class _ThumbCustomizationRangeSliderState extends SampleViewState { + SfRangeValues _thumbValues = const SfRangeValues(4.0, 6.0); + final double _thumbMin = 0.0; + final double _thumbMax = 10.0; + SfRangeValues _values = const SfRangeValues(4.0, 6.0); + + SfRangeSliderTheme _thumbIconSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + thumbRadius: 16, + tooltipBackgroundColor: model.backgroundColor, + ), + child: SfRangeSlider.vertical( + interval: 2.0, + min: _thumbMin, + max: _thumbMax, + startThumbIcon: Icon(Icons.keyboard_arrow_down_outlined, + color: Colors.white, size: 16.0), + endThumbIcon: Icon(Icons.keyboard_arrow_up_outlined, + color: Colors.white, size: 16.0), + minorTicksPerInterval: 1, + showTicks: true, + values: _thumbValues, + onChanged: (SfRangeValues values) { + setState(() { + _thumbValues = values; + }); + }, + )); + } + + Widget _thumbView(dynamic value) { + return Container( + alignment: Alignment.center, + child: Text( + value.toInt().toString(), + style: const TextStyle(color: Colors.white), + textAlign: TextAlign.center, + )); + } + + SfRangeSliderTheme _thumbCustomizationSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData(thumbRadius: 14), + child: SfRangeSlider.vertical( + interval: 2.0, + min: 0.0, + max: 10.0, + startThumbIcon: _thumbView(_values.start), + endThumbIcon: _thumbView(_values.end), + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _thumbCustomizationSlider()), + Text('Text view') + ]), + Column(children: [ + Expanded(child: _thumbIconSlider()), + Text('Icon view'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_date_time_label.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_date_time_label.dart new file mode 100644 index 00000000..02781009 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_date_time_label.dart @@ -0,0 +1,144 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders the range slider with date time labels +class VerticalDateRangeSliderPage extends SampleView { + /// Creates the range slider with date time labels + const VerticalDateRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalDateRangeSliderPageState createState() => + _VerticalDateRangeSliderPageState(); +} + +class _VerticalDateRangeSliderPageState extends SampleViewState { + _VerticalDateRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _DateRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _DateRangeSlider extends SampleView { + @override + _DateRangeSliderState createState() => _DateRangeSliderState(); +} + +class _DateRangeSliderState extends SampleViewState { + SfRangeValues _yearValues = + SfRangeValues(DateTime(2002, 4, 01), DateTime(2003, 10, 01)); + SfRangeValues _hourValues = SfRangeValues( + DateTime(2010, 01, 01, 13, 00, 00), DateTime(2010, 01, 01, 17, 00, 00)); + + SfRangeSliderTheme _yearRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: DateTime(2001, 01, 01), + max: DateTime(2005, 01, 01), + showLabels: true, + interval: 1, + dateFormat: DateFormat.y(), + dateIntervalType: DateIntervalType.years, + labelPlacement: LabelPlacement.betweenTicks, + showTicks: true, + values: _yearValues, + onChanged: (SfRangeValues values) { + setState(() { + _yearValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfRangeSliderTheme _hourRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: DateTime(2010, 01, 01, 9, 00, 00), + max: DateTime(2010, 01, 01, 21, 05, 00), + showLabels: true, + interval: 4, + showTicks: true, + minorTicksPerInterval: 3, + dateFormat: DateFormat('h a'), + dateIntervalType: DateIntervalType.hours, + values: _hourValues, + onChanged: (SfRangeValues values) { + setState(() { + _hourValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat('h:mm a').format(actualLabel); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _yearRangeSlider()), + Text('Interval as year') + ]), + Column(children: [ + Expanded(child: _hourRangeSlider()), + Text('Interval as hour') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_default_appearance.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_default_appearance.dart new file mode 100644 index 00000000..e1aae865 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_default_appearance.dart @@ -0,0 +1,116 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders default range slider widget +class VerticalDefaultRangeSliderPage extends SampleView { + /// Creates default range slider widget + const VerticalDefaultRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalDefaultRangeSliderPageState createState() => + _VerticalDefaultRangeSliderPageState(); +} + +class _VerticalDefaultRangeSliderPageState extends SampleViewState { + _VerticalDefaultRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _DefaultRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _DefaultRangeSlider extends SampleView { + @override + _DefaultRangeSliderState createState() => _DefaultRangeSliderState(); +} + +class _DefaultRangeSliderState extends SampleViewState { + final SfRangeValues _inactiveRangeSliderValue = SfRangeValues(20.0, 80.0); + SfRangeValues _activeRangeSliderValue = SfRangeValues(20.0, 80.0); + + SfRangeSlider _inactiveRangeSlider() { + //ignore: missing_required_param + return SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + values: _inactiveRangeSliderValue, + onChanged: null, + ); + } + + SfRangeSliderTheme _activeRangeSliderSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + onChanged: (dynamic values) { + setState(() { + _activeRangeSliderValue = values; + }); + }, + values: _activeRangeSliderValue, + enableTooltip: true, + numberFormat: NumberFormat('#'), + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _activeRangeSliderSlider()), + Text('Enabled') + ]), + Column(children: [ + Expanded(child: _inactiveRangeSlider()), + Text('Disabled') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_divisor_label_tick.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_divisor_label_tick.dart new file mode 100644 index 00000000..53021393 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_divisor_label_tick.dart @@ -0,0 +1,134 @@ +///flutter package import +import 'package:flutter/material.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders the range slider with divisor, labels, ticks +class VerticalScaleRangeSliderPage extends SampleView { + /// Creates the range slider with divisor, labels, ticks + const VerticalScaleRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalScaleRangeSliderPageState createState() => + _VerticalScaleRangeSliderPageState(); +} + +class _VerticalScaleRangeSliderPageState extends SampleViewState { + _VerticalScaleRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _ScaleRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _ScaleRangeSlider extends SampleView { + @override + _ScaleRangeSliderState createState() => _ScaleRangeSliderState(); +} + +class _ScaleRangeSliderState extends SampleViewState { + SfRangeValues _divisonSliderValues = const SfRangeValues(20.0, 80.0); + SfRangeValues _tickSliderValues = const SfRangeValues(20.0, 80.0); + SfRangeValues _labelSliderValues = const SfRangeValues(20.0, 80.0); + + SfRangeSlider _sliderWithDivisor() { + return SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + interval: 20, + showDivisors: true, + values: _divisonSliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _divisonSliderValues = values; + }); + }); + } + + SfRangeSlider _sliderWithTick() { + return SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + interval: 20, + showLabels: true, + showTicks: true, + minorTicksPerInterval: 1, + labelPlacement: LabelPlacement.onTicks, + values: _tickSliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _tickSliderValues = values; + }); + }); + } + + SfRangeSlider _sliderWithLabel() { + return SfRangeSlider.vertical( + min: 0.0, + max: 100.0, + interval: 20, + showLabels: true, + values: _labelSliderValues, + onChanged: (SfRangeValues values) { + setState(() { + _labelSliderValues = values; + }); + }); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(0, padding, 0, padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column(children: [ + Expanded(child: _sliderWithDivisor()), + Text('Divisors') + ]), + Column(children: [ + Expanded(child: _sliderWithLabel()), + Text('Labels'), + ]), + Column(children: [ + Expanded(child: _sliderWithTick()), + Text('Ticks'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_interval_selection.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_interval_selection.dart new file mode 100644 index 00000000..c2a39784 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_interval_selection.dart @@ -0,0 +1,162 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders the range slider with interval selection +class VerticalRangeSliderIntervalSelectionPage extends SampleView { + /// Renders the range slider with interval selection + const VerticalRangeSliderIntervalSelectionPage(Key key) : super(key: key); + + @override + _VerticalRangeSliderIntervalSelectionPageState createState() => + _VerticalRangeSliderIntervalSelectionPageState(); +} + +class _VerticalRangeSliderIntervalSelectionPageState extends SampleViewState { + _VerticalRangeSliderIntervalSelectionPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _RangeSliderIntervalSelection(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _RangeSliderIntervalSelection extends SampleView { + @override + _RangeSliderIntervalSelectionState createState() => + _RangeSliderIntervalSelectionState(); +} + +class _RangeSliderIntervalSelectionState extends SampleViewState { + SfRangeValues _yearValues = + SfRangeValues(DateTime(2012, 1, 01), DateTime(2018, 1, 1)); + SfRangeValues _values = const SfRangeValues(20.0, 80.0); + + SfRangeSliderTheme _yearRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: DateTime(2010, 01, 01), + max: DateTime(2020, 01, 01), + //showDivisors: true, + interval: 2, + showLabels: true, + stepDuration: const SliderStepDuration(years: 2), + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.years, + enableIntervalSelection: true, + showTicks: true, + values: _yearValues, + onChanged: (SfRangeValues values) { + setState(() { + _yearValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfRangeSliderTheme _numericRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + showLabels: true, + interval: 20, + min: 0.0, + max: 100.0, + stepSize: 20, + showTicks: true, + enableIntervalSelection: true, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + enableTooltip: true)); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(padding, padding, padding, padding / 2), + child: Column(children: [ + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: EdgeInsets.only(bottom: padding / 2), + child: Column(children: [ + Expanded(child: _numericRangeSlider()), + Text('Numeric') + ])), + Padding( + padding: EdgeInsets.only(bottom: padding / 2), + child: Column(children: [ + Expanded(child: _yearRangeSlider()), + Text('DateTime'), + ])), + ], + ), + ), + Padding( + padding: EdgeInsets.only(bottom: padding / 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Icon(Icons.lightbulb_outline, + color: Colors.orange, size: 24.0), + Padding( + padding: EdgeInsets.only(left: 5), + child: Text('Tap on the interval to select it.'), + ) + ]), + ) + ])); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_step.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_step.dart new file mode 100644 index 00000000..d331bc57 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_step.dart @@ -0,0 +1,137 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders slider with step duration +class VerticalSliderStepDurationPage extends SampleView { + /// Creates slider with step duration + const VerticalSliderStepDurationPage(Key key) : super(key: key); + + @override + _VerticalSliderStepDurationPageState createState() => + _VerticalSliderStepDurationPageState(); +} + +class _VerticalSliderStepDurationPageState extends SampleViewState { + _VerticalSliderStepDurationPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _SliderStepDurationView(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _SliderStepDurationView extends SampleView { + @override + _SliderStepDurationState createState() => _SliderStepDurationState(); +} + +class _SliderStepDurationState extends SampleViewState { + SfRangeValues _yearValues = + SfRangeValues(DateTime(2005, 1, 01), DateTime(2015, 1, 1)); + SfRangeValues _values = const SfRangeValues(-25.0, 25.0); + + SfRangeSliderTheme _yearRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: DateTime(2000, 01, 01), + max: DateTime(2020, 01, 01), + showLabels: true, + interval: 5, + stepDuration: const SliderStepDuration(years: 5), + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.years, + showTicks: true, + values: _yearValues, + onChanged: (SfRangeValues values) { + setState(() { + _yearValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfRangeSliderTheme _numericRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + showLabels: true, + interval: 25, + min: -50.0, + max: 50.0, + stepSize: 25, + showTicks: true, + values: _values, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + enableTooltip: true)); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _numericRangeSlider()), + Text('Numeric') + ]), + Column(children: [ + Expanded(child: _yearRangeSlider()), + Text('DateTime') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart new file mode 100644 index 00000000..75faad06 --- /dev/null +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart @@ -0,0 +1,140 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders slider with tooltip range +class VerticalTooltipRangeSliderPage extends SampleView { + /// Creates slider with tooltip range + const VerticalTooltipRangeSliderPage(Key key) : super(key: key); + + @override + _VerticalTooltipRangeSliderPageState createState() => + _VerticalTooltipRangeSliderPageState(); +} + +class _VerticalTooltipRangeSliderPageState extends SampleViewState { + _VerticalTooltipRangeSliderPageState(); + + late Widget rangeSlider; + + @override + void initState() { + super.initState(); + rangeSlider = _TooltipRangeSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? rangeSlider + : SingleChildScrollView( + child: Container(height: 400, child: rangeSlider), + ); + } +} + +class _TooltipRangeSlider extends SampleView { + @override + _TooltipRangeSliderState createState() => _TooltipRangeSliderState(); +} + +class _TooltipRangeSliderState extends SampleViewState { + SfRangeValues _values = SfRangeValues(140.0, 160.0); + SfRangeValues _hourValues = SfRangeValues( + DateTime(2010, 01, 01, 13, 00, 00), DateTime(2010, 01, 01, 17, 00, 00)); + + SfRangeSliderTheme _yearRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor, + labelOffset: Offset(-40, 0), + tickOffset: Offset(-14, 0)), + child: SfRangeSlider.vertical( + min: 100.0, + max: 200.0, + showLabels: true, + interval: 20, + showTicks: true, + values: _values, + tooltipPosition: SliderTooltipPosition.right, + onChanged: (SfRangeValues values) { + setState(() { + _values = values; + }); + }, + enableTooltip: true, + )); + } + + SfRangeSliderTheme _hourRangeSlider() { + return SfRangeSliderTheme( + data: SfRangeSliderThemeData( + tooltipBackgroundColor: model.backgroundColor), + child: SfRangeSlider.vertical( + min: DateTime(2010, 01, 01, 9, 00, 00), + max: DateTime(2010, 01, 01, 21, 05, 00), + showLabels: true, + interval: 4, + showTicks: true, + minorTicksPerInterval: 3, + dateFormat: DateFormat('h a'), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.hours, + values: _hourValues, + onChanged: (SfRangeValues values) { + setState(() { + _hourValues = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat('h:mm a').format(actualLabel); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _yearRangeSlider()), + Text('Tooltip on the right') + ]), + Column(children: [ + Expanded(child: _hourRangeSlider()), + Text('Tooltip on the left'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/basic_features/default_vertical_slider.dart b/lib/samples/sliders/vertical_slider/basic_features/default_vertical_slider.dart new file mode 100644 index 00000000..46ca5451 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/basic_features/default_vertical_slider.dart @@ -0,0 +1,113 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders default slider widget +class DefaultVerticalSliderPage extends SampleView { + /// Creates default slider widget + const DefaultVerticalSliderPage(Key key) : super(key: key); + + @override + _DefaultVerticalSliderPageState createState() => + _DefaultVerticalSliderPageState(); +} + +class _DefaultVerticalSliderPageState extends SampleViewState { + _DefaultVerticalSliderPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _DefaultSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container( + height: 400, + child: Padding( + padding: EdgeInsets.only(top: 10.0), child: slider)), + ); + } +} + +class _DefaultSlider extends SampleView { + @override + _DefaultSliderState createState() => _DefaultSliderState(); +} + +class _DefaultSliderState extends SampleViewState { + final double _inactiveSliderValue = 50.0; + double _activeSliderValue = 50.0; + + SfSlider _inactiveSlider() { + //ignore: missing_required_param + return SfSlider.vertical( + min: 0.0, + max: 100.0, + value: _inactiveSliderValue, + onChanged: null, + ); + } + + SfSliderTheme _activeSlider() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + min: 0.0, + max: 100.0, + onChanged: (dynamic values) { + setState(() { + _activeSliderValue = values; + }); + }, + value: _activeSliderValue, + enableTooltip: true, + numberFormat: NumberFormat('#'), + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout())); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + children: [Expanded(child: _activeSlider()), Text('Enabled')]), + Column(children: [ + Expanded(child: _inactiveSlider()), + Text('Disabled') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_date_interval.dart b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_date_interval.dart new file mode 100644 index 00000000..951dabb2 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_date_interval.dart @@ -0,0 +1,148 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +///Render Slider with date intervals +class VerticalDateIntervalSliderPage extends SampleView { + ///Creates Slider with date intervals + const VerticalDateIntervalSliderPage(Key key) : super(key: key); + + @override + _VerticalDateIntervalSliderPageState createState() => + _VerticalDateIntervalSliderPageState(); +} + +class _VerticalDateIntervalSliderPageState extends SampleViewState { + _VerticalDateIntervalSliderPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _VerticalDateIntervalSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _VerticalDateIntervalSlider extends SampleView { + @override + _VerticalDateIntervalSliderState createState() => + _VerticalDateIntervalSliderState(); +} + +class _VerticalDateIntervalSliderState extends SampleViewState { + DateTime _yearValue = DateTime(2018, 01, 01); + DateTime _hourValue = DateTime(2020, 01, 01, 13, 00, 00); + + SfSliderTheme _yearSlider() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + min: DateTime(2016, 01, 01), + max: DateTime(2020, 01, 01), + showLabels: true, + interval: 1, + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.betweenTicks, + dateIntervalType: DateIntervalType.years, + showTicks: true, + value: _yearValue, + onChanged: (dynamic value) { + setState(() { + _yearValue = value; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfSliderTheme _hourSlider() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + min: DateTime(2020, 01, 01, 9, 00, 00), + max: DateTime(2020, 01, 01, 21, 05, 00), + showLabels: true, + interval: 4, + showTicks: true, + minorTicksPerInterval: 3, + dateFormat: DateFormat('h a'), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.hours, + value: _hourValue, + onChanged: (dynamic value) { + setState(() { + _hourValue = value; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat('h:mm a').format(actualLabel); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded( + flex: 4, + child: _yearSlider(), + ), + Text('Interval as year') + ]), + Column(children: [ + Expanded( + flex: 4, + child: _hourSlider(), + ), + Text('Interval as hour'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_divisor_label_tick.dart b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_divisor_label_tick.dart new file mode 100644 index 00000000..03ceb335 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_divisor_label_tick.dart @@ -0,0 +1,155 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +///Render Slider with customized labels +class VerticalSliderLabelCustomizationPage extends SampleView { + ///Render Slider with customized labels + const VerticalSliderLabelCustomizationPage(Key key) : super(key: key); + + @override + _VerticalSliderLabelCustomizationPageState createState() => + _VerticalSliderLabelCustomizationPageState(); +} + +class _VerticalSliderLabelCustomizationPageState extends SampleViewState { + _VerticalSliderLabelCustomizationPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _SliderLabelCustomization(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _SliderLabelCustomization extends SampleView { + @override + _SliderLabelCustomizationState createState() => + _SliderLabelCustomizationState(); +} + +class _SliderLabelCustomizationState extends SampleViewState { + double _labelSliderValue = 50; + double _tickSliderValue = 0; + double _divisorSliderValue = 50; + + SfSliderTheme _sliderWithLabelCustomization() { + return SfSliderTheme( + data: SfSliderThemeData( + tooltipBackgroundColor: model.backgroundColor, + labelOffset: Offset(8, 0)), + child: SfSlider.vertical( + showLabels: true, + interval: 20, + min: 10.0, + max: 90.0, + value: _labelSliderValue, + onChanged: (dynamic values) { + setState(() { + _labelSliderValue = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'), + )); + } + + SfSliderTheme _sliderWithTickCustomization() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + showLabels: true, + showTicks: true, + interval: 25, + min: -50.0, + max: 50.0, + value: _tickSliderValue, + onChanged: (dynamic values) { + setState(() { + _tickSliderValue = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'), + )); + } + + SfSliderTheme _sliderWithDivisorCustomization() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + interval: 25, + showDivisors: true, + min: 0.0, + max: 100.0, + value: _divisorSliderValue, + tooltipPosition: SliderTooltipPosition.right, + onChanged: (dynamic values) { + setState(() { + _divisorSliderValue = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'), + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(0, padding, 0, padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column(children: [ + Expanded(child: _sliderWithDivisorCustomization()), + Text('Divisors') + ]), + Column(children: [ + Expanded(child: _sliderWithLabelCustomization()), + Text('Labels'), + ]), + Column(children: [ + Expanded(child: _sliderWithTickCustomization()), + Text('Ticks') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_step.dart b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_step.dart new file mode 100644 index 00000000..e054a37c --- /dev/null +++ b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_step.dart @@ -0,0 +1,133 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +///Render Slider with step interval +class VerticalStepSliderPage extends SampleView { + ///Render Slider with step interval + const VerticalStepSliderPage(Key key) : super(key: key); + + @override + _VerticalStepSliderPageState createState() => _VerticalStepSliderPageState(); +} + +class _VerticalStepSliderPageState extends SampleViewState { + _VerticalStepSliderPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _StepSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _StepSlider extends SampleView { + @override + _StepSliderState createState() => _StepSliderState(); +} + +class _StepSliderState extends SampleViewState { + DateTime _yearValue = DateTime(2015, 1, 01); + double _stepSliderValue = 0; + + SfSliderTheme _sliderWithStepDurationCustomization() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + min: DateTime(2010, 01, 01), + max: DateTime(2020, 01, 01), + showLabels: true, + interval: 2, + stepDuration: const SliderStepDuration(years: 2), + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.years, + showTicks: true, + value: _yearValue, + onChanged: (dynamic values) { + setState(() { + _yearValue = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.y().format(actualLabel); + }, + )); + } + + SfSliderTheme _sliderWithStepCustomization() { + return SfSliderTheme( + data: SfSliderThemeData(tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + showLabels: true, + interval: 5, + min: -10.0, + max: 10.0, + stepSize: 5, + showTicks: true, + value: _stepSliderValue, + onChanged: (dynamic values) { + setState(() { + _stepSliderValue = values; + }); + }, + enableTooltip: true)); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _sliderWithStepCustomization()), + Text('Numeric') + ]), + Column(children: [ + Expanded(child: _sliderWithStepDurationCustomization()), + Text('DateTime') + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart new file mode 100644 index 00000000..002a88b8 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart @@ -0,0 +1,140 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../model/sample_view.dart'; + +/// Renders slider with different types of tooltips +class VerticalSliderTooltipTypeSliderPage extends SampleView { + /// Renders slider with different types of tooltips + const VerticalSliderTooltipTypeSliderPage(Key key) : super(key: key); + + @override + _VerticalSliderTooltipPageState createState() => + _VerticalSliderTooltipPageState(); +} + +class _VerticalSliderTooltipPageState extends SampleViewState { + _VerticalSliderTooltipPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _SliderTooltipType(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _SliderTooltipType extends SampleView { + @override + _SliderTooltipTypeState createState() => _SliderTooltipTypeState(); +} + +class _SliderTooltipTypeState extends SampleViewState { + DateTime _hourValue = DateTime(2020, 01, 01, 13, 00, 00); + double _sliderValue = 20; + + SfSliderTheme _numerical() { + return SfSliderTheme( + data: SfSliderThemeData( + tooltipBackgroundColor: model.backgroundColor, + labelOffset: Offset(-30, 0), + tickOffset: Offset(-15, 0)), + child: SfSlider.vertical( + showLabels: true, + interval: 10, + min: 10.0, + max: 40.0, + showTicks: true, + tooltipPosition: SliderTooltipPosition.right, + value: _sliderValue, + onChanged: (dynamic values) { + setState(() { + _sliderValue = values; + }); + }, + enableTooltip: true)); + } + + SfSliderTheme _dateTimeSlider() { + return SfSliderTheme( + data: SfSliderThemeData( + tooltipBackgroundColor: model.backgroundColor, + ), + child: SfSlider.vertical( + min: DateTime(2020, 01, 01, 9, 00, 00), + max: DateTime(2020, 01, 01, 21, 05, 00), + showLabels: true, + interval: 4, + showTicks: true, + minorTicksPerInterval: 3, + dateFormat: DateFormat('h a'), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.hours, + value: _hourValue, + onChanged: (dynamic value) { + setState(() { + _hourValue = value; + }); + }, + enableTooltip: true, + //tooltipShape: SfPaddleTooltipShape(), + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat('h:mm a').format(actualLabel); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _numerical()), + Text('Tooltip on the right') + ]), + Column(children: [ + Expanded(child: _dateTimeSlider()), + Text('Tooltip on the left'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/color_customization/vertical_slider_color_customization.dart b/lib/samples/sliders/vertical_slider/customization/color_customization/vertical_slider_color_customization.dart new file mode 100644 index 00000000..46b846b6 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/color_customization/vertical_slider_color_customization.dart @@ -0,0 +1,153 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized color +class VerticalSliderColorCustomizationPage extends SampleView { + ///Creates slider with customized color + const VerticalSliderColorCustomizationPage(Key key) : super(key: key); + + @override + _VerticalSliderColorCustomizationPageState createState() => + _VerticalSliderColorCustomizationPageState(); +} + +class _VerticalSliderColorCustomizationPageState extends SampleViewState { + _VerticalSliderColorCustomizationPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _SliderColorCustomization(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _SliderColorCustomization extends SampleView { + @override + _SliderColorCustomizationState createState() => + _SliderColorCustomizationState(); +} + +class _SliderColorCustomizationState extends SampleViewState { + double _trackSliderValue = 0; + double _thumbStrokeSliderValue = 50; + + SfSliderTheme _sliderWithTrackColorCustomization() { + return SfSliderTheme( + data: SfSliderThemeData( + activeTrackColor: Colors.teal, + inactiveTrackColor: Colors.teal.withOpacity(0.24), + thumbColor: Colors.teal, + tooltipBackgroundColor: Colors.teal, + overlayColor: Colors.teal.withOpacity(0.24)), + child: SfSlider.vertical( + showLabels: true, + showTicks: true, + interval: 25, + min: -50.0, + max: 50.0, + value: _trackSliderValue, + onChanged: (dynamic values) { + setState(() { + _trackSliderValue = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'))); + } + + SfSliderTheme _sliderWithThumbStrokeColorCustomization() { + return SfSliderTheme( + data: SfSliderThemeData( + inactiveDivisorColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, + activeDivisorColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, + activeDivisorStrokeWidth: 2, + activeDivisorStrokeColor: Colors.deepOrange.withOpacity(0.24), + inactiveDivisorStrokeWidth: 2, + inactiveDivisorStrokeColor: Colors.deepOrange, + activeDivisorRadius: 5.0, + inactiveDivisorRadius: 5.0, + activeTrackColor: Colors.deepOrange, + inactiveTrackColor: Colors.deepOrange.withOpacity(0.24), + overlayColor: Colors.deepOrange.withOpacity(0.12), + thumbColor: model.isWebFullView + ? model.webBackgroundColor + : model.cardThemeColor, + thumbStrokeWidth: 2.0, + tooltipBackgroundColor: Colors.deepOrange, + thumbStrokeColor: Colors.deepOrange), + child: SfSlider.vertical( + interval: 25, + showDivisors: true, + min: 0.0, + max: 100.0, + value: _thumbStrokeSliderValue, + onChanged: (dynamic values) { + setState(() { + _thumbStrokeSliderValue = values; + }); + }, + enableTooltip: true, + numberFormat: NumberFormat('#'))); + } + + Widget _buildWebLayout() { + return Container( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _sliderWithTrackColorCustomization()), + Text('Track color') + ]), + Column(children: [ + Expanded(child: _sliderWithThumbStrokeColorCustomization()), + Text('Stroke color'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_divisor_customization.dart b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_divisor_customization.dart new file mode 100644 index 00000000..5e98d65e --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_divisor_customization.dart @@ -0,0 +1,72 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/model.dart'; +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized divisor +class VerticalDivisorCustomizedSlider extends SampleView { + @override + _VerticalDivisorCustomizedSliderState createState() => + _VerticalDivisorCustomizedSliderState(); +} + +class _VerticalDivisorCustomizedSliderState extends SampleViewState { + double _value = 60.0; + + @override + Widget build(BuildContext context) { + return SfSlider.vertical( + min: 0.0, + max: 100.0, + value: _value, + onChanged: (dynamic values) { + setState(() { + _value = values; + }); + }, + interval: 10, + showDivisors: true, + numberFormat: NumberFormat('#'), + divisorShape: _DivisorShape(model), + ); + } +} + +class _DivisorShape extends SfDivisorShape { + _DivisorShape(this.model); + + SampleModel model; + + @override + void paint(PaintingContext context, Offset center, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Paint? paint, + Animation? enableAnimation, + TextDirection? textDirection}) { + bool isActive; + + isActive = center.dy >= thumbCenter!.dy; + + context.canvas.drawRect( + Rect.fromCenter(center: center, width: 10.0, height: 5.0), + Paint() + ..isAntiAlias = true + ..style = PaintingStyle.fill + ..color = isActive + ? themeData!.activeTrackColor! + : model.themeData.canvasColor); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_shape_customization.dart b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_shape_customization.dart new file mode 100644 index 00000000..968093dc --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_shape_customization.dart @@ -0,0 +1,224 @@ +///Dart import +import 'dart:ui'; + +///flutter package import +import 'package:flutter/material.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; +import 'vertical_slider_divisor_customization.dart'; +import 'vertical_slider_tick_customization.dart'; +import 'vertical_thumb_customization.dart'; + +///Renders slider with customized shapes +class VerticalShapeCustomizedSliderPage extends SampleView { + ///Renders slider with customized shapes + const VerticalShapeCustomizedSliderPage(Key key) : super(key: key); + + @override + _VerticalShapeCustomizedSliderPageState createState() => + _VerticalShapeCustomizedSliderPageState(); +} + +class _VerticalShapeCustomizedSliderPageState extends SampleViewState { + _VerticalShapeCustomizedSliderPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _ShapeCustomizedSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _ShapeCustomizedSlider extends SampleView { + @override + _ShapeCustomizedSliderState createState() => _ShapeCustomizedSliderState(); +} + +class _ShapeCustomizedSliderState extends SampleViewState { + _ShapeCustomizedSliderState(); + + double _value = 60.0; + final double _min = 0.0; + final double _max = 100.0; + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.fromLTRB(0, padding, 0, padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column(children: [ + Expanded( + child: SfSliderTheme( + data: SfSliderThemeData( + overlayColor: Colors.transparent, + ), + child: SfSlider.vertical( + min: _min, + max: _max, + value: _value, + interval: 20.0, + showLabels: true, + showTicks: true, + trackShape: _SfTrackShape(_min, _max), + thumbShape: _SfThumbShape(_min, _max), + tooltipPosition: SliderTooltipPosition.right, + onChanged: (dynamic value) { + setState(() { + _value = value; + }); + }, + )), + ), + Text('Track') + ]), + Column(children: [ + Expanded(child: VerticalDivisorCustomizedSlider()), + Text('Divisor'), + ]), + Column(children: [ + Expanded(child: VerticalThumbCustomizedSlider()), + Text('Thumb'), + ]), + Column(children: [ + Expanded(child: VerticalTickCustomizedSlider()), + Padding( + padding: EdgeInsets.only(right: 10.0), child: Text('Tick')), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} + +class _SfTrackShape extends SfTrackShape { + _SfTrackShape(dynamic min, dynamic max) { + this.min = min.runtimeType == DateTime + ? min.millisecondsSinceEpoch.toDouble() + : min; + this.max = max.runtimeType == DateTime + ? max.millisecondsSinceEpoch.toDouble() + : max; + } + late double min; + late double max; + double? trackIntermediatePos; + + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {required RenderBox parentBox, + required themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Animation enableAnimation, + required Paint? inactivePaint, + required Paint? activePaint, + required TextDirection textDirection}) { + final Rect trackRect = getPreferredRect(parentBox, themeData, offset); + final double actualValue = currentValues.runtimeType == DateTime + ? currentValue.millisecondsSinceEpoch.toDouble() + : currentValue; + final double actualValueInPercent = + ((actualValue - min) * 100) / (max - min); + trackIntermediatePos = _getTrackIntermediatePosition(trackRect); + + // low volume track. + final Paint trackPaint = Paint(); + trackPaint.color = actualValueInPercent <= 80.0 ? Colors.green : Colors.red; + final Rect lowVolumeRect = Rect.fromLTRB(trackRect.left, + trackIntermediatePos!, trackRect.right, trackRect.bottom); + context.canvas.drawRect(lowVolumeRect, trackPaint); + + // high volume track. + trackPaint.color = Colors.red; + final Rect highVolumeRect = Rect.fromLTRB( + trackRect.left, trackRect.top, trackRect.right, trackIntermediatePos!); + context.canvas.drawRect(highVolumeRect, trackPaint); + } + + double _getTrackIntermediatePosition(Rect trackRect) { + final double actualValue = ((80 * (max - min)) + min) / 100; + return trackRect.bottom - + (((actualValue - min) / (max - min)) * trackRect.height); + } +} + +class _SfThumbShape extends SfThumbShape { + _SfThumbShape(dynamic min, dynamic max) { + this.min = min.runtimeType == DateTime + ? min.millisecondsSinceEpoch.toDouble() + : min; + this.max = max.runtimeType == DateTime + ? max.millisecondsSinceEpoch.toDouble() + : max; + } + late double min; + late double max; + + @override + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required RenderBox? child, + required themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { + final double actualValue = currentValues.runtimeType == DateTime + ? currentValue.millisecondsSinceEpoch.toDouble() + : currentValue; + + final double actualValueInPercent = + ((actualValue - min) * 100) / (max - min); + + paint = Paint(); + paint.color = actualValueInPercent <= 80 ? Colors.green : Colors.red; + + super.paint(context, center, + parentBox: parentBox, + themeData: themeData, + currentValue: currentValue, + paint: paint, + enableAnimation: enableAnimation, + textDirection: textDirection, + thumb: thumb, + child: child); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_tick_customization.dart b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_tick_customization.dart new file mode 100644 index 00000000..2f7beb98 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_slider_tick_customization.dart @@ -0,0 +1,145 @@ +///Dart import +import 'dart:math' as math; + +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized ticks +class VerticalTickCustomizedSlider extends SampleView { + @override + _VerticalTickCustomizedSliderState createState() => + _VerticalTickCustomizedSliderState(); +} + +class _VerticalTickCustomizedSliderState extends SampleViewState { + double _value = 60.0; + final Color _inactiveColor = const Color.fromARGB(255, 194, 194, 194); + final Color _activeColor = Colors.blue; + + @override + Widget build(BuildContext context) { + return SfSliderTheme( + data: SfSliderThemeData( + inactiveTrackColor: _inactiveColor.withOpacity(0.5), + activeTrackColor: _activeColor, + inactiveTickColor: _inactiveColor.withOpacity(0.8), + activeTickColor: _activeColor, + inactiveMinorTickColor: _inactiveColor, + activeMinorTickColor: _activeColor, + thumbColor: _activeColor, + overlayColor: _activeColor.withOpacity(0.24), + tickOffset: const Offset(-4, 0), + tooltipBackgroundColor: _activeColor), + child: SfSlider.vertical( + min: 0.0, + max: 100.0, + value: _value, + onChanged: (dynamic values) { + setState(() { + _value = values; + }); + }, + interval: 10, + minorTicksPerInterval: 3, + showTicks: true, + enableTooltip: true, + numberFormat: NumberFormat('#'), + tickShape: _TickShape(), + minorTickShape: _MinorTickShape(), + ), + ); + } +} + +class _TickShape extends SfTickShape { + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Animation? enableAnimation, + TextDirection? textDirection}) { + final Size tickSize = getPreferredSize(themeData!); + final bool isTickRightOfThumb = offset.dy < thumbCenter!.dy; + final Color begin = isTickRightOfThumb + ? themeData.disabledInactiveTickColor + : themeData.disabledActiveTickColor; + final Color end = isTickRightOfThumb + ? themeData.inactiveTickColor + : themeData.activeTickColor; + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = tickSize.height + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation!)!; + + context.canvas.drawLine( + Offset( + offset.dx - + 2 * themeData.tickOffset!.dy - + math.max( + themeData.activeTrackHeight, themeData.inactiveTrackHeight), + offset.dy), + Offset( + offset.dx - + 2 * themeData.tickOffset!.dy - + math.max(themeData.activeTrackHeight, + themeData.inactiveTrackHeight) - + tickSize.width, + offset.dy), + paint); + } +} + +class _MinorTickShape extends SfTickShape { + @override + void paint(PaintingContext context, Offset offset, Offset? thumbCenter, + Offset? startThumbCenter, Offset? endThumbCenter, + {RenderBox? parentBox, + SfSliderThemeData? themeData, + SfRangeValues? currentValues, + dynamic currentValue, + Animation? enableAnimation, + TextDirection? textDirection}) { + final Size minorTickSize = getPreferredSize(themeData!); + final bool isMinorTickRightOfThumb = offset.dy < thumbCenter!.dy; + + final Color begin = isMinorTickRightOfThumb + ? themeData.disabledInactiveMinorTickColor + : themeData.disabledActiveMinorTickColor; + final Color end = isMinorTickRightOfThumb + ? themeData.inactiveMinorTickColor + : themeData.activeMinorTickColor; + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = minorTickSize.height + ..color = ColorTween(begin: begin, end: end).evaluate(enableAnimation!)!; + + context.canvas.drawLine( + Offset( + offset.dx - + 2 * themeData.tickOffset!.dy - + math.max( + themeData.activeTrackHeight, themeData.inactiveTrackHeight), + offset.dy), + Offset( + offset.dx - + 2 * themeData.tickOffset!.dy - + math.max(themeData.activeTrackHeight, + themeData.inactiveTrackHeight) - + minorTickSize.width, + offset.dy), + paint); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_thumb_customization.dart b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_thumb_customization.dart new file mode 100644 index 00000000..f77c3388 --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/shape_customization/vertical_thumb_customization.dart @@ -0,0 +1,97 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' show NumberFormat; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized thumb +class VerticalThumbCustomizedSlider extends SampleView { + @override + _VerticalThumbCustomizedSliderState createState() => + _VerticalThumbCustomizedSliderState(); +} + +class _VerticalThumbCustomizedSliderState extends SampleViewState { + double _sliderValue = 60.0; + final Color _activeColor = const Color.fromARGB(255, 255, 0, 58); + + SfSliderTheme _thumbCustomizedSlider() { + return SfSliderTheme( + data: SfSliderThemeData( + inactiveTrackColor: _activeColor.withOpacity(0.40), + activeTrackColor: _activeColor, + thumbColor: Colors.transparent, + tickOffset: const Offset(0, 13), + overlayColor: Colors.transparent, + tooltipBackgroundColor: _activeColor, + activeDivisorColor: _activeColor, + inactiveDivisorColor: _activeColor.withOpacity(0.80), + activeDivisorRadius: 2.0, + inactiveDivisorRadius: 2.0), + child: SfSlider.vertical( + min: 0.0, + max: 100.0, + value: _sliderValue, + onChanged: (dynamic values) { + setState(() { + _sliderValue = values; + }); + }, + interval: 10, + showDivisors: true, + enableTooltip: true, + numberFormat: NumberFormat('#'), + thumbShape: _RectThumbShape(), + ), + ); + } + + @override + Widget build(BuildContext context) { + return _thumbCustomizedSlider(); + } +} + +class _RectThumbShape extends SfThumbShape { + @override + void paint(PaintingContext context, Offset center, + {required RenderBox parentBox, + required RenderBox? child, + required SfSliderThemeData themeData, + SfRangeValues? currentValues, + dynamic currentValue, + required Paint? paint, + required Animation enableAnimation, + required TextDirection textDirection, + required SfThumb? thumb}) { + super.paint(context, center, + parentBox: parentBox, + child: child, + themeData: themeData, + currentValue: currentValue, + paint: paint, + enableAnimation: enableAnimation, + textDirection: textDirection, + thumb: thumb); + + final Path path = Path(); + + path.moveTo(center.dx, center.dy); + path.lineTo(center.dx + 20, center.dy - 15); + path.lineTo(center.dx + 20, center.dy + 15); + path.close(); + context.canvas.drawPath( + path, + Paint() + ..color = themeData.activeTrackColor! + ..style = PaintingStyle.fill + ..strokeWidth = 2); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/size_customization/vertical_slider_size_customization.dart b/lib/samples/sliders/vertical_slider/customization/size_customization/vertical_slider_size_customization.dart new file mode 100644 index 00000000..4d4747cf --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/size_customization/vertical_slider_size_customization.dart @@ -0,0 +1,147 @@ +///flutter package import +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized size +class VerticalSliderSizeCustomizationPage extends SampleView { + ///Creates slider with customized size + const VerticalSliderSizeCustomizationPage(Key key) : super(key: key); + + @override + _VerticalSliderSizeCustomizationPageState createState() => + _VerticalSliderSizeCustomizationPageState(); +} + +class _VerticalSliderSizeCustomizationPageState extends SampleViewState { + _VerticalSliderSizeCustomizationPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _SfSliderSizeCustomization(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _SfSliderSizeCustomization extends SampleView { + @override + _SfSliderSizeCustomizationState createState() => + _SfSliderSizeCustomizationState(); +} + +class _SfSliderSizeCustomizationState extends SampleViewState { + DateTime _yearValue = DateTime(2010, 1, 01); + double _value = 0.0; + + SfSliderTheme _sliderWithdivisorCustomization() { + return SfSliderTheme( + data: SfSliderThemeData( + activeDivisorRadius: 6.0, + inactiveDivisorRadius: 3.0, + inactiveDivisorColor: Colors.deepOrangeAccent.withOpacity(0.24), + activeDivisorColor: Colors.deepOrangeAccent, + activeTrackColor: Colors.deepOrangeAccent, + thumbColor: Colors.deepOrangeAccent, + tooltipBackgroundColor: Colors.deepOrangeAccent, + inactiveTrackColor: Colors.deepOrangeAccent.withOpacity(0.24), + overlayColor: Colors.deepOrangeAccent.withOpacity(0.12)), + child: SfSlider.vertical( + min: DateTime(2000, 01, 01), + max: DateTime(2020, 01, 01), + showLabels: true, + interval: 5, + stepDuration: const SliderStepDuration(years: 5), + dateFormat: DateFormat.y(), + labelPlacement: LabelPlacement.onTicks, + dateIntervalType: DateIntervalType.years, + showDivisors: true, + value: _yearValue, + onChanged: (dynamic values) { + setState(() { + _yearValue = values; + }); + }, + enableTooltip: true, + tooltipTextFormatterCallback: + (dynamic actualLabel, String formattedText) { + return DateFormat.yMMM().format(actualLabel); + }, + )); + } + + SfSliderTheme _sliderWithTrackCustomization() { + return SfSliderTheme( + data: SfSliderThemeData( + activeTrackHeight: 10.0, + inactiveTrackHeight: 4.0, + trackCornerRadius: 6.0, + tooltipBackgroundColor: model.backgroundColor), + child: SfSlider.vertical( + showLabels: true, + interval: 10, + min: -20.0, + max: 20.0, + stepSize: 10, + value: _value, + onChanged: (dynamic values) { + setState(() { + _value = values; + }); + }, + enableTooltip: true)); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _sliderWithTrackCustomization()), + Text('Track') + ]), + Column(children: [ + Expanded(child: _sliderWithdivisorCustomization()), + Text('Divisor'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sliders/vertical_slider/customization/thumb_customization/vertical_slider_thumb_icon_customization.dart b/lib/samples/sliders/vertical_slider/customization/thumb_customization/vertical_slider_thumb_icon_customization.dart new file mode 100644 index 00000000..2674478a --- /dev/null +++ b/lib/samples/sliders/vertical_slider/customization/thumb_customization/vertical_slider_thumb_icon_customization.dart @@ -0,0 +1,154 @@ +///flutter package import +import 'package:flutter/material.dart'; + +///Core theme import +import 'package:syncfusion_flutter_core/theme.dart'; + +///Slider import +import 'package:syncfusion_flutter_sliders/sliders.dart'; + +///Local imports +import '../../../../../model/sample_view.dart'; + +///Renders slider with customized thumb +class VerticalThumbCustomizationSliderPage extends SampleView { + ///Creates slider with customized thumb + const VerticalThumbCustomizationSliderPage(Key key) : super(key: key); + + @override + _VerticalThumbCustomizationSliderPageState createState() => + _VerticalThumbCustomizationSliderPageState(); +} + +class _VerticalThumbCustomizationSliderPageState extends SampleViewState { + _VerticalThumbCustomizationSliderPageState(); + + late Widget slider; + + @override + void initState() { + super.initState(); + slider = _ThumbCustomizationSlider(); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.of(context).orientation == Orientation.portrait || + model.isWebFullView + ? slider + : SingleChildScrollView( + child: Container(height: 400, child: slider), + ); + } +} + +class _ThumbCustomizationSlider extends SampleView { + @override + _ThumbCustomizationSliderState createState() => + _ThumbCustomizationSliderState(); +} + +class _ThumbCustomizationSliderState extends SampleViewState { + double _thumbValue = 4.0; + final double _thumbMin = 0.0; + final double _thumbMax = 10.0; + double _value = 4.0; + + SfSliderTheme _thumbIconSlider() { + return SfSliderTheme( + data: SfSliderThemeData( + thumbRadius: 16, + tooltipBackgroundColor: model.backgroundColor, + ), + child: SfSlider.vertical( + interval: 2.0, + min: _thumbMin, + max: _thumbMax, + thumbIcon: _thumbView(), + minorTicksPerInterval: 1, + showTicks: true, + value: _thumbValue, + onChanged: (dynamic values) { + setState(() { + _thumbValue = values; + }); + }, + )); + } + + Widget _thumbView() { + if (_thumbValue == _thumbMin) { + return Icon(Icons.keyboard_arrow_up_outlined, + color: Colors.white, size: 12.0); + } else if (_thumbValue == _thumbMax) { + return Icon(Icons.keyboard_arrow_down_outlined, + color: Colors.white, size: 12.0); + } else { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: const [ + Icon(Icons.keyboard_arrow_up_outlined, + color: Colors.white, size: 16.0), + Icon(Icons.keyboard_arrow_down_outlined, + color: Colors.white, size: 16.0), + ]); + } + } + + SfSliderTheme _thumbCustomizationSlider() { + return SfSliderTheme( + data: SfSliderThemeData(thumbRadius: 14), + child: SfSlider.vertical( + interval: 2.0, + min: 0.0, + max: 10.0, + thumbIcon: Container( + alignment: Alignment.center, + child: Text( + _value.toInt().toString(), + style: const TextStyle(color: Colors.white), + textAlign: TextAlign.center, + )), + value: _value, + onChanged: (dynamic values) { + setState(() { + _value = values; + }); + }, + )); + } + + Widget _buildWebLayout() { + return Center( + child: Container( + alignment: Alignment.center, + width: MediaQuery.of(context).size.width >= 1000 ? 550 : 440, + child: _buildMobileLayout(), + ), + ); + } + + Widget _buildMobileLayout() { + final double padding = MediaQuery.of(context).size.height / 10.0; + return Padding( + padding: EdgeInsets.all(padding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column(children: [ + Expanded(child: _thumbCustomizationSlider()), + Text('Text view') + ]), + Column(children: [ + Expanded(child: _thumbIconSlider()), + Text('Icon view'), + ]), + ], + )); + } + + @override + Widget build(BuildContext context) { + return model.isWebFullView ? _buildWebLayout() : _buildMobileLayout(); + } +} diff --git a/lib/samples/sparkline/axis_types.dart b/lib/samples/sparkline/axis_types.dart index 652bcf9a..01495d55 100644 --- a/lib/samples/sparkline/axis_types.dart +++ b/lib/samples/sparkline/axis_types.dart @@ -1,13 +1,12 @@ /// Package import import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/sparkcharts.dart'; /// Chart import /// Local import import '../../model/sample_view.dart'; -import 'package:syncfusion_flutter_charts/sparkcharts.dart'; - ///Renders default line series chart class SparklineAxesTypes extends SampleView { ///Creates default line series chart @@ -21,65 +20,65 @@ class _SparklineAxesTypesState extends SampleViewState { _SparklineAxesTypesState(); double _size = 150; bool _isVertical = false; - final List _dateTimeChartData = [ - SalesData(xval: DateTime(2018, 0, 1), yval: 4), - SalesData(xval: DateTime(2018, 0, 2), yval: 4.5), - SalesData(xval: DateTime(2018, 0, 3), yval: 8), - SalesData(xval: DateTime(2018, 0, 4), yval: 7), - SalesData(xval: DateTime(2018, 0, 5), yval: 6), - SalesData(xval: DateTime(2018, 0, 8), yval: 8), - SalesData(xval: DateTime(2018, 0, 9), yval: 8), - SalesData(xval: DateTime(2018, 0, 10), yval: 6.5), - SalesData(xval: DateTime(2018, 0, 11), yval: 4), - SalesData(xval: DateTime(2018, 0, 12), yval: 5.5), - SalesData(xval: DateTime(2018, 0, 15), yval: 8), - SalesData(xval: DateTime(2018, 0, 16), yval: 6), - SalesData(xval: DateTime(2018, 0, 17), yval: 6.5), - SalesData(xval: DateTime(2018, 0, 18), yval: 7.5), - SalesData(xval: DateTime(2018, 0, 19), yval: 7.5), - SalesData(xval: DateTime(2018, 0, 22), yval: 4), - SalesData(xval: DateTime(2018, 0, 23), yval: 8), - SalesData(xval: DateTime(2018, 0, 24), yval: 6), - SalesData(xval: DateTime(2018, 0, 25), yval: 7.5), - SalesData(xval: DateTime(2018, 0, 26), yval: 4.5), - SalesData(xval: DateTime(2018, 0, 29), yval: 6), - SalesData(xval: DateTime(2018, 0, 30), yval: 5), - SalesData(xval: DateTime(2018, 0, 31), yval: 7), + final List<_SalesData> _dateTimeChartData = [ + _SalesData(xval: DateTime(2018, 0, 1), yval: 4), + _SalesData(xval: DateTime(2018, 0, 2), yval: 4.5), + _SalesData(xval: DateTime(2018, 0, 3), yval: 8), + _SalesData(xval: DateTime(2018, 0, 4), yval: 7), + _SalesData(xval: DateTime(2018, 0, 5), yval: 6), + _SalesData(xval: DateTime(2018, 0, 8), yval: 8), + _SalesData(xval: DateTime(2018, 0, 9), yval: 8), + _SalesData(xval: DateTime(2018, 0, 10), yval: 6.5), + _SalesData(xval: DateTime(2018, 0, 11), yval: 4), + _SalesData(xval: DateTime(2018, 0, 12), yval: 5.5), + _SalesData(xval: DateTime(2018, 0, 15), yval: 8), + _SalesData(xval: DateTime(2018, 0, 16), yval: 6), + _SalesData(xval: DateTime(2018, 0, 17), yval: 6.5), + _SalesData(xval: DateTime(2018, 0, 18), yval: 7.5), + _SalesData(xval: DateTime(2018, 0, 19), yval: 7.5), + _SalesData(xval: DateTime(2018, 0, 22), yval: 4), + _SalesData(xval: DateTime(2018, 0, 23), yval: 8), + _SalesData(xval: DateTime(2018, 0, 24), yval: 6), + _SalesData(xval: DateTime(2018, 0, 25), yval: 7.5), + _SalesData(xval: DateTime(2018, 0, 26), yval: 4.5), + _SalesData(xval: DateTime(2018, 0, 29), yval: 6), + _SalesData(xval: DateTime(2018, 0, 30), yval: 5), + _SalesData(xval: DateTime(2018, 0, 31), yval: 7), ]; - final List _numericdata = [ - SalesData(xval: 1, yval: 190), - SalesData(xval: 2, yval: 165), - SalesData(xval: 3, yval: 158), - SalesData(xval: 4, yval: 175), - SalesData(xval: 5, yval: 200), - SalesData(xval: 6, yval: 180), - SalesData(xval: 7, yval: 210), + final List<_SalesData> _numericdata = [ + _SalesData(xval: 1, yval: 190), + _SalesData(xval: 2, yval: 165), + _SalesData(xval: 3, yval: 158), + _SalesData(xval: 4, yval: 175), + _SalesData(xval: 5, yval: 200), + _SalesData(xval: 6, yval: 180), + _SalesData(xval: 7, yval: 210), ]; - final List _categorydata = [ - SalesData(xval: 'Robert', yval: 60), - SalesData(xval: 'Andrew', yval: 65), - SalesData(xval: 'Suyama', yval: 70), - SalesData(xval: 'Michael', yval: 80), - SalesData(xval: 'Janet', yval: 55), - SalesData(xval: 'Davolio', yval: 90), - SalesData(xval: 'Fuller', yval: 75), - SalesData(xval: 'Nancy', yval: 85), - SalesData(xval: 'Margaret', yval: 77), - SalesData(xval: 'Steven', yval: 68), - SalesData(xval: 'Laura', yval: 96), - SalesData(xval: 'Elizabeth', yval: 57) + final List<_SalesData> _categorydata = [ + _SalesData(xval: 'Robert', yval: 60), + _SalesData(xval: 'Andrew', yval: 65), + _SalesData(xval: 'Suyama', yval: 70), + _SalesData(xval: 'Michael', yval: 80), + _SalesData(xval: 'Janet', yval: 55), + _SalesData(xval: 'Davolio', yval: 90), + _SalesData(xval: 'Fuller', yval: 75), + _SalesData(xval: 'Nancy', yval: 85), + _SalesData(xval: 'Margaret', yval: 77), + _SalesData(xval: 'Steven', yval: 68), + _SalesData(xval: 'Laura', yval: 96), + _SalesData(xval: 'Elizabeth', yval: 57) ]; @override Widget build(BuildContext context) { _isVertical = MediaQuery.of(context).size.height > MediaQuery.of(context).size.width; if (_isVertical) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 5 : MediaQuery.of(context).size.height / 4.5; - return model.isWeb && model.isMobileResolution + return model.isWebFullView && model.isMobileResolution ? Container( child: SingleChildScrollView( child: Column( @@ -89,15 +88,15 @@ class _SparklineAxesTypesState extends SampleViewState { Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkNumericChart(), + _buildSparkNumericChart(), Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkCategoryChart(), + _buildSparkCategoryChart(), Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkDatetimeChart(), + _buildSparkDatetimeChart(), ]))) : Center( child: Column( @@ -107,15 +106,15 @@ class _SparklineAxesTypesState extends SampleViewState { Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkNumericChart(), + _buildSparkNumericChart(), Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkCategoryChart(), + _buildSparkCategoryChart(), Padding( padding: EdgeInsets.fromLTRB(0, 0, 0, 5), ), - _getSparkDatetimeChart(), + _buildSparkDatetimeChart(), ])); } else { _size = MediaQuery.of(context).size.width / 4.5; @@ -124,21 +123,21 @@ class _SparklineAxesTypesState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getSparkNumericChart(), + _buildSparkNumericChart(), Padding( padding: EdgeInsets.fromLTRB(20, 0, 0, 0), ), - _getSparkCategoryChart(), + _buildSparkCategoryChart(), Padding( padding: EdgeInsets.fromLTRB(20, 0, 0, 0), ), - _getSparkDatetimeChart(), + _buildSparkDatetimeChart(), ])); } } // Get the cartesian chart with default line series - Widget _getSparkDatetimeChart() { + Widget _buildSparkDatetimeChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -159,10 +158,10 @@ class _SparklineAxesTypesState extends SampleViewState { child: SfSparkBarChart.custom( axisLineWidth: 0, dataCount: 23, - xValueMapper: (num index) => + xValueMapper: (int index) => _dateTimeChartData[index].xval, - yValueMapper: (num index) => - _dateTimeChartData[index].yval, + yValueMapper: (int index) => + _dateTimeChartData[index].yval!, trackball: SparkChartTrackball( activationMode: SparkChartActivationMode.tap))), Padding(padding: EdgeInsets.fromLTRB(0, 2, 0, 0)), @@ -173,7 +172,7 @@ class _SparklineAxesTypesState extends SampleViewState { } // Get the cartesian chart with default line series - Widget _getSparkCategoryChart() { + Widget _buildSparkCategoryChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -194,12 +193,12 @@ class _SparklineAxesTypesState extends SampleViewState { child: SfSparkBarChart.custom( axisLineWidth: 0, dataCount: 12, - xValueMapper: (num index) => _categorydata[index].xval, - yValueMapper: (num index) => _categorydata[index].yval, + xValueMapper: (int index) => _categorydata[index].xval, + yValueMapper: (int index) => _categorydata[index].yval!, trackball: SparkChartTrackball( tooltipFormatter: (TooltipFormatterDetails details) { - String _labelText = + final String _labelText = '${details.x} : ${details.y}%'; return _labelText; }, @@ -212,7 +211,7 @@ class _SparklineAxesTypesState extends SampleViewState { } // Get the cartesian chart with default line series - Widget _getSparkNumericChart() { + Widget _buildSparkNumericChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -233,12 +232,12 @@ class _SparklineAxesTypesState extends SampleViewState { child: SfSparkBarChart.custom( axisLineWidth: 0, dataCount: 7, - xValueMapper: (num index) => _numericdata[index].xval, - yValueMapper: (num index) => _numericdata[index].yval, + xValueMapper: (int index) => _numericdata[index].xval, + yValueMapper: (int index) => _numericdata[index].yval!, trackball: SparkChartTrackball( tooltipFormatter: (TooltipFormatterDetails details) { - String _labelText = + final String _labelText = '${details.x} : \$${details.y}'; return _labelText; }, @@ -251,8 +250,8 @@ class _SparklineAxesTypesState extends SampleViewState { } } -class SalesData { - SalesData({this.xval, this.yval}); +class _SalesData { + _SalesData({this.xval, this.yval}); final dynamic xval; - final double yval; + final double? yval; } diff --git a/lib/samples/sparkline/chart_types.dart b/lib/samples/sparkline/chart_types.dart index 1a58143d..93a4ee44 100644 --- a/lib/samples/sparkline/chart_types.dart +++ b/lib/samples/sparkline/chart_types.dart @@ -1,13 +1,12 @@ /// Package import import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/sparkcharts.dart'; /// Chart import /// Local import import '../../model/sample_view.dart'; -import 'package:syncfusion_flutter_charts/sparkcharts.dart'; - ///Renders default line series chart class SparklineSeriesTypes extends SampleView { ///Creates default line series chart @@ -28,10 +27,10 @@ class _SparklineSeriesTypesState extends SampleViewState { _isVertical = MediaQuery.of(context).size.height > MediaQuery.of(context).size.width; if (_isVertical) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 6 : MediaQuery.of(context).size.height / 6; - return model.isWeb && model.isMobileResolution + return model.isWebFullView && model.isMobileResolution ? Container( child: SingleChildScrollView( child: Column( @@ -39,13 +38,13 @@ class _SparklineSeriesTypesState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding(padding: EdgeInsets.all(5)), - _getSparkLineChart(), + _buildSparkLineChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkAreaChart(), + _buildSparkAreaChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkBarChart(), + _buildSparkBarChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkWinlossChart(), + _buildSparkWinlossChart(), ], ))) : Center( @@ -54,13 +53,13 @@ class _SparklineSeriesTypesState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding(padding: EdgeInsets.all(5)), - Expanded(child: _getSparkLineChart()), + Expanded(child: _buildSparkLineChart()), Padding(padding: EdgeInsets.all(5)), - Expanded(child: _getSparkAreaChart()), + Expanded(child: _buildSparkAreaChart()), Padding(padding: EdgeInsets.all(5)), - Expanded(child: _getSparkBarChart()), + Expanded(child: _buildSparkBarChart()), Padding(padding: EdgeInsets.all(5)), - Expanded(child: _getSparkWinlossChart()), + Expanded(child: _buildSparkWinlossChart()), ], )); } else { @@ -70,19 +69,19 @@ class _SparklineSeriesTypesState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.center, children: [ Padding(padding: EdgeInsets.all(5)), - _getSparkLineChart(), + _buildSparkLineChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkAreaChart(), + _buildSparkAreaChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkBarChart(), + _buildSparkBarChart(), Padding(padding: EdgeInsets.all(5)), - _getSparkWinlossChart(), + _buildSparkWinlossChart(), ], )); } } - Widget _getSparkLineChart() { + Widget _buildSparkLineChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -140,7 +139,7 @@ class _SparklineSeriesTypesState extends SampleViewState { ]); } - Widget _getSparkAreaChart() { + Widget _buildSparkAreaChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -171,10 +170,10 @@ class _SparklineSeriesTypesState extends SampleViewState { 30, 29 ], - color: Color.fromRGBO(178, 207, 255, 1), + color: Color.fromRGBO(68, 150, 236, 0.3), axisLineWidth: 0, borderWidth: 2, - borderColor: Color.fromRGBO(60, 120, 239, 1))), + borderColor: Color.fromRGBO(68, 150, 236, 1))), Padding(padding: EdgeInsets.fromLTRB(0, 2, 0, 0)), Text('Spark Area Chart', style: TextStyle(fontStyle: FontStyle.italic)), @@ -183,7 +182,7 @@ class _SparklineSeriesTypesState extends SampleViewState { } /// Get the cartesian chart with default line series - Widget _getSparkBarChart() { + Widget _buildSparkBarChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -224,7 +223,7 @@ class _SparklineSeriesTypesState extends SampleViewState { } /// Get the cartesian chart with default line series - Widget _getSparkWinlossChart() { + Widget _buildSparkWinlossChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/samples/sparkline/customization.dart b/lib/samples/sparkline/customization.dart index 62aecbf9..d87c5b76 100644 --- a/lib/samples/sparkline/customization.dart +++ b/lib/samples/sparkline/customization.dart @@ -1,5 +1,6 @@ /// Package import import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/sparkcharts.dart'; /// Chart import @@ -7,9 +8,9 @@ import 'package:flutter/material.dart'; import '../../model/sample_view.dart'; import '../../widgets/custom_button.dart'; -import 'package:syncfusion_flutter_charts/sparkcharts.dart'; - +/// Renders the sparkline custamization sample class SparklineCustomization extends SampleView { + /// Creates the sparkline custamization sample const SparklineCustomization(Key key) : super(key: key); @override @@ -50,15 +51,15 @@ class _SparklineCustomizationState extends SampleViewState { return Center( child: Container( height: MediaQuery.of(context).size.height / 3, - width: model.isWeb || + width: model.isWebFullView || MediaQuery.of(context).orientation == Orientation.landscape ? MediaQuery.of(context).size.width / 2.5 : MediaQuery.of(context).size.width / 1.2, - child: _getSparkBarCustomizationChart(), + child: _buildSparkBarCustomizationChart(), )); } - SfSparkLineChart _getSparkBarCustomizationChart() { + SfSparkLineChart _buildSparkBarCustomizationChart() { return SfSparkLineChart( data: [1, 5, -6, 0, 1, -2, 7, -7, -4, -10, 13, -6, 7, 5, 11, 5, 3], labelDisplayMode: _dataLabelDisplayMode, @@ -85,7 +86,7 @@ class _SparklineCustomizationState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( - shrinkWrap: !model.isWeb, + shrinkWrap: !model.isWebFullView, children: [ Container( child: Row( @@ -108,7 +109,7 @@ class _SparklineCustomizationState extends SampleViewState { child: Text('$value', style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onMarkerDisplayModeChange(value.toString()); stateSetter(() {}); }), @@ -137,7 +138,7 @@ class _SparklineCustomizationState extends SampleViewState { child: Text('$value', style: TextStyle(color: model.textColor))); }).toList(), - onChanged: (String value) { + onChanged: (String? value) { _onDatalabelDisplayModeChange(value.toString()); stateSetter(() {}); }), @@ -159,9 +160,9 @@ class _SparklineCustomizationState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _enableTrackLine, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _enableTrackLine = value; + _enableTrackLine = value!; stateSetter(() {}); }); })) @@ -218,9 +219,9 @@ class _SparklineCustomizationState extends SampleViewState { child: CheckboxListTile( activeColor: model.backgroundColor, value: _enablePlotband, - onChanged: (bool value) { + onChanged: (bool? value) { setState(() { - _enablePlotband = value; + _enablePlotband = value!; stateSetter(() {}); }); })) diff --git a/lib/samples/sparkline/live_update.dart b/lib/samples/sparkline/live_update.dart index 38e64c44..ba2a801d 100644 --- a/lib/samples/sparkline/live_update.dart +++ b/lib/samples/sparkline/live_update.dart @@ -4,14 +4,14 @@ import 'dart:math'; ///Package imports import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/sparkcharts.dart'; ///Local import import '../../model/sample_view.dart'; -import 'package:syncfusion_flutter_charts/sparkcharts.dart'; - /// Widget of the AgendaView Calendar. class SparklineLiveUpdate extends SampleView { + /// Creates the sparkline live update chart. const SparklineLiveUpdate(Key key) : super(key: key); @override @@ -22,7 +22,7 @@ class _SparklineLiveUpdateState extends SampleViewState { _SparklineLiveUpdateState(); double _size = 140; - Timer _timer; + late Timer _timer; bool _isVertical = false; String _cpuValue = ''; String _diskValue = ''; @@ -76,29 +76,29 @@ class _SparklineLiveUpdateState extends SampleViewState { _isVertical = MediaQuery.of(context).size.height > MediaQuery.of(context).size.width; if (_isVertical) { - _size = model.isWeb + _size = model.isWebFullView ? MediaQuery.of(context).size.height / 6.5 : MediaQuery.of(context).size.height / 6; - return model.isWeb && model.isMobileResolution + return model.isWebFullView && model.isMobileResolution ? Container( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _getCPUDataChart(), + _buildCPUDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getDiskDataChart(), + _buildDiskDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getMemoryDataChart(), + _buildMemoryDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getEthernetDataChart(), + _buildEthernetDataChart(), ], )), ) @@ -107,19 +107,19 @@ class _SparklineLiveUpdateState extends SampleViewState { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - _getCPUDataChart(), + _buildCPUDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getDiskDataChart(), + _buildDiskDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getMemoryDataChart(), + _buildMemoryDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 10), ), - _getEthernetDataChart(), + _buildEthernetDataChart(), ], ), ); @@ -129,26 +129,26 @@ class _SparklineLiveUpdateState extends SampleViewState { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - _getCPUDataChart(), + _buildCPUDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 0), ), - _getDiskDataChart(), + _buildDiskDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 0), ), - _getMemoryDataChart(), + _buildMemoryDataChart(), Padding( padding: EdgeInsets.fromLTRB(10, 0, 0, 0), ), - _getEthernetDataChart(), + _buildEthernetDataChart(), ], ), ); } } - Widget _getCPUDataChart() { + Widget _buildCPUDataChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -172,25 +172,25 @@ class _SparklineLiveUpdateState extends SampleViewState { Container( padding: EdgeInsets.fromLTRB(5, 0, 0, 0), child: Text( - '${_cpuValue}' + - '%' + - ' ' + - '${int.parse(_cpuValue) / 5}' + - ' GHz', + '$_cpuValue' + '%' + ' ' + '${int.parse(_cpuValue) / 5}' + ' GHz', textAlign: TextAlign.left, style: TextStyle( fontSize: 12, color: model.themeData.brightness == Brightness.dark - ? Color.fromRGBO(232, 242, 252, 1) - : Color.fromRGBO(3, 88, 160, 1)))), + ? Color.fromRGBO(212, 135, 215, 1) + : Color.fromRGBO(110, 43, 113, 1)))), Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 10)), Expanded( child: SfSparkAreaChart( data: _cpuData, axisLineWidth: 0, - color: Color.fromRGBO(232, 242, 252, 1), - borderColor: Color.fromRGBO(3, 88, 160, 1), + color: Color.fromRGBO(184, 71, 189, 0.35), + borderColor: Color.fromRGBO(184, 71, 189, 1), borderWidth: 1, )) ]), @@ -198,7 +198,7 @@ class _SparklineLiveUpdateState extends SampleViewState { ]); } - Widget _getDiskDataChart() { + Widget _buildDiskDataChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -221,13 +221,13 @@ class _SparklineLiveUpdateState extends SampleViewState { fontWeight: FontWeight.bold, fontSize: 16))), Container( padding: EdgeInsets.fromLTRB(5, 0, 0, 0), - child: Text('${_diskValue}' + '%', + child: Text('$_diskValue' '%', textAlign: TextAlign.left, style: TextStyle( fontSize: 12, color: model.themeData.brightness == Brightness.dark - ? Color.fromRGBO(245, 232, 252, 1) - : Color.fromRGBO(178, 71, 198, 1), + ? Color.fromRGBO(169, 144, 253, 1) + : Color.fromRGBO(34, 15, 132, 1), ))), Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 10)), Expanded( @@ -235,8 +235,8 @@ class _SparklineLiveUpdateState extends SampleViewState { data: _diskData, axisCrossesAt: 0, axisLineWidth: 0, - color: Color.fromRGBO(245, 232, 252, 1), - borderColor: Color.fromRGBO(178, 71, 198, 1), + color: Color.fromRGBO(128, 94, 246, 0.3), + borderColor: Color.fromRGBO(128, 94, 246, 1), borderWidth: 1, )) ]), @@ -244,7 +244,7 @@ class _SparklineLiveUpdateState extends SampleViewState { ]); } - Widget _getMemoryDataChart() { + Widget _buildMemoryDataChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -268,20 +268,20 @@ class _SparklineLiveUpdateState extends SampleViewState { Container( padding: EdgeInsets.fromLTRB(5, 0, 0, 0), child: Text( - '${int.parse(_memoryValue) / 10}' + - '/' + - '15.8 GB ' + - '(' + - '${(((int.parse(_memoryValue) / 10) / 15.8) * 100).round()}' + - '%' + - ')', + '${int.parse(_memoryValue) / 10}' + '/' + '15.8 GB ' + '(' + '${(((int.parse(_memoryValue) / 10) / 15.8) * 100).round()}' + '%' + ')', textAlign: TextAlign.left, style: TextStyle( fontSize: 12, color: model.themeData.brightness == Brightness.dark - ? Color.fromRGBO(224, 249, 209, 1) - : Color.fromRGBO(39, 173, 102, 1), + ? Color.fromRGBO(89, 176, 227, 1) + : Color.fromRGBO(23, 118, 217, 1), ))), Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 10)), Expanded( @@ -289,14 +289,14 @@ class _SparklineLiveUpdateState extends SampleViewState { data: _memoryData, axisCrossesAt: 0, axisLineWidth: 0, - color: Color.fromRGBO(224, 249, 209, 1), - borderColor: Color.fromRGBO(39, 173, 102, 1), + color: Color.fromRGBO(89, 176, 227, 0.3), + borderColor: Color.fromRGBO(89, 176, 227, 1), borderWidth: 1)) ])), ]); } - Widget _getEthernetDataChart() { + Widget _buildEthernetDataChart() { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -319,24 +319,24 @@ class _SparklineLiveUpdateState extends SampleViewState { fontWeight: FontWeight.bold, fontSize: 16))), Container( padding: EdgeInsets.fromLTRB(5, 0, 0, 0), - child: Text( - 'R: ' + '${int.parse(_ethernetValue)}' + ' Kbps', - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 12, - color: - model.themeData.brightness == Brightness.dark - ? Color.fromRGBO(242, 216, 199, 1) - : Color.fromRGBO(170, 144, 122, 1), - ))), + child: + Text('R: ' '${int.parse(_ethernetValue)}' ' Kbps', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 12, + color: model.themeData.brightness == + Brightness.dark + ? Color.fromRGBO(89, 190, 103, 1) + : Color.fromRGBO(40, 144, 90, 1), + ))), Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 10)), Expanded( child: SfSparkAreaChart( data: _ethernetData, axisCrossesAt: 0, axisLineWidth: 0, - color: Color.fromRGBO(242, 216, 199, 1), - borderColor: Color.fromRGBO(170, 144, 122, 1), + color: Color.fromRGBO(89, 190, 103, 0.3), + borderColor: Color.fromRGBO(89, 190, 103, 1), borderWidth: 1, )) ])), @@ -344,7 +344,7 @@ class _SparklineLiveUpdateState extends SampleViewState { } ///Get random value - num _getRandomInt(num _min, num _max) { + double _getRandomInt(int _min, int _max) { final Random _random = Random(); return _min + _random.nextInt(_max - _min).toDouble(); } @@ -400,9 +400,3 @@ class _SparklineLiveUpdateState extends SampleViewState { return _ethernetData; } } - -class ChartData { - ChartData(this.x, this.y); - final num x; - final num y; -} diff --git a/lib/samples/sparkline/sparkline_in_grid.dart b/lib/samples/sparkline/sparkline_in_grid.dart index f7583061..7e6a4a7f 100644 --- a/lib/samples/sparkline/sparkline_in_grid.dart +++ b/lib/samples/sparkline/sparkline_in_grid.dart @@ -3,7 +3,7 @@ import 'dart:math' as math; /// Package imports import 'package:flutter/material.dart'; -// import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_charts/sparkcharts.dart'; /// Barcode imports import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @@ -11,8 +11,6 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; /// Local imports import '../../model/sample_view.dart'; -import 'package:syncfusion_flutter_charts/sparkcharts.dart'; - /// Renders column type data grid class SparkLineGrid extends SampleView { /// Creates column type data grid @@ -22,16 +20,13 @@ class SparkLineGrid extends SampleView { _SparkLineGridState createState() => _SparkLineGridState(); } -List<_Employee> _employeeData; - class _SparkLineGridState extends SampleViewState { _SparkLineGridState(); //ignore: unused_field final math.Random _random = math.Random(); - bool _isLandscapeInMobileView; + late bool _isLandscapeInMobileView; - final _ColumnTypesDataGridSource _columnTypesDataGridSource = - _ColumnTypesDataGridSource(); + late _ColumnTypesDataGridSource _columnTypesDataGridSource; List<_Employee> _generateList(int _count) { final List<_Employee> _employeeData = <_Employee>[]; @@ -353,93 +348,70 @@ class _SparkLineGridState extends SampleViewState { 'Germany', ]; - SfDataGrid _getDataGrid() { + SfDataGrid _buildDataGrid() { return SfDataGrid( source: _columnTypesDataGridSource, - columnWidthMode: model.isWeb + columnWidthMode: model.isWebFullView ? ColumnWidthMode.fill : _isLandscapeInMobileView ? ColumnWidthMode.fill - : ColumnWidthMode.auto, - cellBuilder: (BuildContext context, GridColumn column, int rowIndex) { - Widget widget; - if (column.mappingName == 'tax') { - widget = Container( - padding: const EdgeInsets.all(3), - child: _employeeData[rowIndex].tax, - ); - } - if (column.mappingName == 'column') { - widget = Container( - padding: const EdgeInsets.all(3), - child: _employeeData[rowIndex].column, - ); - } - if (column.mappingName == 'winloss') { - widget = Container( - padding: const EdgeInsets.all(3), - child: _employeeData[rowIndex].winloss, - ); - } - return widget; - }, + : ColumnWidthMode.none, columns: [ - GridNumericColumn( - mappingName: 'id', - headerText: ' ID', - columnWidthMode: ColumnWidthMode.header, - headerTextAlignment: Alignment.centerRight), GridTextColumn( - mappingName: 'name', - headerText: 'Name', - columnWidthMode: (model.isWeb || _isLandscapeInMobileView) - ? ColumnWidthMode.none - : ColumnWidthMode.cells, - headerTextAlignment: Alignment.centerLeft), + columnName: 'id', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text('ID')), + width: 50), + GridTextColumn( + columnName: 'name', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text('Name')), + ), + GridTextColumn( + columnName: 'shipCountry', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text('Ship country')), + ), + GridTextColumn( + columnName: 'tax', + width: model.isWebFullView ? double.nan : 130, + label: Container( + alignment: Alignment.center, child: Text('Tax per annum'))), GridTextColumn( - mappingName: 'shipCountry', - headerText: 'Ship country', - columnWidthMode: (model.isWeb || _isLandscapeInMobileView) - ? ColumnWidthMode.none - : ColumnWidthMode.header, - headerTextAlignment: Alignment.centerLeft), - GridWidgetColumn( - columnWidthMode: (model.isWeb || _isLandscapeInMobileView) - ? ColumnWidthMode.none - : ColumnWidthMode.header, - mappingName: 'tax', - headerText: 'Tax per annum'), - GridWidgetColumn( - columnWidthMode: (model.isWeb || _isLandscapeInMobileView) - ? ColumnWidthMode.none - : ColumnWidthMode.header, - mappingName: 'column', - headerText: 'One day index'), - GridWidgetColumn( - columnWidthMode: (model.isWeb || _isLandscapeInMobileView) - ? ColumnWidthMode.none - : ColumnWidthMode.header, - mappingName: 'winloss', - headerText: 'Year GR'), + columnName: 'column', + width: model.isWebFullView ? double.nan : 130, + label: Container( + alignment: Alignment.center, child: Text('One day index'))), + GridTextColumn( + columnName: 'winloss', + label: Container( + alignment: Alignment.center, child: Text('Year GR'))), ]); } @override void initState() { super.initState(); - _employeeData = _generateList(20); + _columnTypesDataGridSource = + _ColumnTypesDataGridSource(_generateList(20), model.isWebFullView); } @override void didChangeDependencies() { super.didChangeDependencies(); - _isLandscapeInMobileView = !model.isWeb && + _isLandscapeInMobileView = !model.isWebFullView && MediaQuery.of(context).orientation == Orientation.landscape; } @override Widget build(BuildContext context) { - return Scaffold(body: _getDataGrid()); + return Scaffold(body: _buildDataGrid()); } } @@ -454,34 +426,58 @@ class _Employee { final Widget winloss; } -class _ColumnTypesDataGridSource extends DataGridSource<_Employee> { - _ColumnTypesDataGridSource(); +class _ColumnTypesDataGridSource extends DataGridSource { + _ColumnTypesDataGridSource(List<_Employee> employees, this.isWeb) { + _employeeData = employees + .map((e) => DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: e.id), + DataGridCell(columnName: 'name', value: e.name), + DataGridCell( + columnName: 'shipCountry', value: e.shipCountry), + DataGridCell(columnName: 'tax', value: e.tax), + DataGridCell(columnName: 'column', value: e.column), + DataGridCell(columnName: 'winloss', value: e.winloss), + ])) + .toList(); + } + + late List _employeeData; + + final bool isWeb; + @override - List<_Employee> get dataSource => _employeeData; + List get rows => _employeeData; + @override - Object getValue(_Employee _employee, String columnName) { - switch (columnName) { - case 'id': - return _employee.id; - break; - case 'name': - return _employee.name; - break; - case 'shipCountry': - return _employee.shipCountry; - break; - case 'tax': - return _employee.tax; - break; - case 'column': - return _employee.column; - break; - case 'winloss': - return _employee.winloss; - break; - default: - return 'empty'; - break; - } + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter(cells: [ + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.all((8.0)), + child: Text(row.getCells()[0].value.toString()), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all((8.0)), + child: Text(row.getCells()[1].value), + ), + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.all((8.0)), + child: Text(row.getCells()[2].value), + ), + Container( + padding: const EdgeInsets.all(3), + child: row.getCells()[3].value, + ), + Container( + padding: const EdgeInsets.all(3), + child: row.getCells()[4].value, + ), + Container( + padding: const EdgeInsets.all(3), + child: row.getCells()[5].value, + ) + ]); } } diff --git a/lib/samples/treemap/custom_background/custom_background.dart b/lib/samples/treemap/custom_background/custom_background.dart new file mode 100644 index 00000000..54385f41 --- /dev/null +++ b/lib/samples/treemap/custom_background/custom_background.dart @@ -0,0 +1,581 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// This sample demonstrates how to add a background content to the tile. +class TreemapCustomBackgroundSample extends SampleView { + /// Creates [TreemapCustomBackgroundSample]. + const TreemapCustomBackgroundSample(Key key) : super(key: key); + + @override + _TreemapCustomBackgroundSampleState createState() => + _TreemapCustomBackgroundSampleState(); +} + +class _TreemapCustomBackgroundSampleState extends SampleViewState { + late List<_MedalDetails> _topRioOlympicCountries; + + @override + void initState() { + // Data source to the treemap. + // + // [medalCount] is used to get each tile's weight. + // [country] is the first level grouping key. + // [medal] is the second level grouping key. + // [category] is the third level grouping key. + _topRioOlympicCountries = <_MedalDetails>[ + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Swimming', + medalCount: 16, + icon: Icons.pool), + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Athletics', + medalCount: 13, + icon: Icons.directions_run), + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Gymnastics', + medalCount: 4, + icon: Icons.accessibility), + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Cycling', + medalCount: 2, + icon: Icons.directions_bike), + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Wrestling', + medalCount: 2, + icon: Icons.sports_kabaddi_outlined), + _MedalDetails( + country: 'United States', + medal: 'Gold', + category: 'Basketball', + medalCount: 2, + icon: Icons.sports_basketball), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Swimming', + medalCount: 8, + icon: Icons.pool), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Athletics', + medalCount: 10, + icon: Icons.directions_run), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Gymnastics', + medalCount: 6, + icon: Icons.accessibility), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Cycling', + medalCount: 3, + icon: Icons.directions_bike), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Fencing', + medalCount: 2, + icon: Icons.colorize_rounded, + ), + _MedalDetails( + country: 'United States', + medal: 'Silver', + category: 'Diving', + medalCount: 2, + icon: Icons.emoji_people, + ), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Swimming', + medalCount: 9, + icon: Icons.pool), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Athletics', + medalCount: 9, + icon: Icons.directions_run), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Gymnastics', + medalCount: 2, + icon: Icons.accessibility), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Volleyball', + medalCount: 3, + icon: Icons.sports_volleyball_rounded), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Fencing', + medalCount: 2, + icon: Icons.colorize_rounded, + ), + _MedalDetails( + country: 'United States', + medal: 'Bronze', + category: 'Shooting', + medalCount: 2, + icon: Icons.gps_fixed), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Cycling', + medalCount: 6, + icon: Icons.directions_bike), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Rowing', + medalCount: 3, + icon: Icons.rowing), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Gymnastics', + medalCount: 2, + icon: Icons.accessibility), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Athletics', + medalCount: 2, + icon: Icons.directions_run), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Canoeing', + medalCount: 2, + icon: Icons.rowing), + _MedalDetails( + country: 'United Kingdom', + medal: 'Gold', + category: 'Swimming', + medalCount: 1, + icon: Icons.pool), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Swimming', + medalCount: 5, + icon: Icons.pool), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Athletics', + medalCount: 1, + icon: Icons.directions_run), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Gymnastics', + medalCount: 2, + icon: Icons.accessibility), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Cycling', + medalCount: 4, + icon: Icons.directions_bike), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Rowing', + medalCount: 2, + icon: Icons.rowing), + _MedalDetails( + country: 'United Kingdom', + medal: 'Silver', + category: 'Canoeing', + medalCount: 2, + icon: Icons.rowing), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Boxing', + medalCount: 1, + icon: Icons.sports_mma), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Athletics', + medalCount: 4, + icon: Icons.directions_run), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Gymnastics', + medalCount: 3, + icon: Icons.accessibility), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Shooting', + medalCount: 2, + icon: Icons.gps_fixed), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Cycling', + medalCount: 2, + icon: Icons.directions_bike), + _MedalDetails( + country: 'United Kingdom', + medal: 'Bronze', + category: 'Diving', + medalCount: 1, + icon: Icons.emoji_people, + ), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Diving', + medalCount: 7, + icon: Icons.emoji_people), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Weightlifting', + medalCount: 5, + icon: Icons.fitness_center), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Table tennis', + medalCount: 2, + icon: Icons.sports_tennis), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Athletics', + medalCount: 4, + icon: Icons.directions_run), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Badminton', + medalCount: 2, + icon: Icons.sports_tennis), + _MedalDetails( + country: 'China', + medal: 'Gold', + category: 'Swimming', + medalCount: 1, + icon: Icons.pool), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Diving', + medalCount: 2, + icon: Icons.emoji_people, + ), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Weightlifting', + medalCount: 2, + icon: Icons.fitness_center), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Table tennis', + medalCount: 2, + icon: Icons.sports_tennis), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Athletics', + medalCount: 2, + icon: Icons.directions_run), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Boxing', + medalCount: 1, + icon: Icons.sports_mma), + _MedalDetails( + country: 'China', + medal: 'Silver', + category: 'Wrestling', + medalCount: 1, + icon: Icons.sports_kabaddi_outlined), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Swimming', + medalCount: 3, + icon: Icons.pool), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Athletics', + medalCount: 4, + icon: Icons.directions_run), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Wrestling', + medalCount: 2, + icon: Icons.sports_kabaddi_outlined), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Shooting', + medalCount: 4, + icon: Icons.gps_fixed), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Boxing', + medalCount: 3, + icon: Icons.sports_mma), + _MedalDetails( + country: 'China', + medal: 'Bronze', + category: 'Rowing', + medalCount: 2, + icon: Icons.rowing), + ]; + + super.initState(); + } + + @override + void dispose() { + _topRioOlympicCountries.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + final bool isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + return Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + isDesktop + ? const EdgeInsets.all(12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + 'Top 3 Winningest Countries in Rio Olympics 2016', + style: Theme.of(context).textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 12.5), + child: SfTreemap( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _topRioOlympicCountries.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _topRioOlympicCountries[index].medalCount; + }, + tooltipSettings: const TreemapTooltipSettings( + color: Color.fromRGBO(57, 65, 9, 1.0), + borderRadius: BorderRadius.all( + Radius.circular(2.0), + ), + ), + levels: _getTreemapLevels(), + ), + ), + ), + ], + ), + ), + ); + } + + List _getTreemapLevels() { + final ThemeData themeData = Theme.of(context); + return [ + TreemapLevel( + color: Colors.transparent, + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder], [tooltipBuilder], + // [colorValueMapper], and [itemBuilder] callbacks respectively. + groupMapper: (int index) => _topRioOlympicCountries[index].country, + // Padding around the tile. + padding: const EdgeInsets.all(2.0), + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + final Brightness brightness = + ThemeData.estimateBrightnessForColor(tile.color); + final Color color = + brightness == Brightness.dark ? Colors.white : Colors.black; + return ColoredBox( + color: const Color.fromRGBO(121, 137, 27, 1.0), + child: Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: + const EdgeInsets.only(left: 4.0, top: 2.0, bottom: 2.0), + child: Text( + tile.group, + style: + themeData.textTheme.bodyText2!.copyWith(color: color), + overflow: TextOverflow.ellipsis, + ), + ), + )); + }, + // Returns a widget for each tile's tooltip. + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: EdgeInsets.zero, + child: Text( + '${tile.group}' '\nMedals : ${tile.weight.round()}', + style: TextStyle(color: Colors.white), + ), + ); + }, + ), + TreemapLevel( + groupMapper: (int index) => _topRioOlympicCountries[index].medal, + padding: EdgeInsets.zero, + colorValueMapper: (TreemapTile tile) { + if (tile.group == 'Gold') { + return const Color.fromRGBO(237, 176, 62, 1.0); + } else if (tile.group == 'Silver') { + return const Color.fromRGBO(207, 212, 216, 1.0); + } else { + return const Color.fromRGBO(189, 126, 64, 1.0); + } + }, + // Returns a widget for each tile's content. + itemBuilder: (BuildContext context, TreemapTile tile) { + return Center( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Image.asset( + 'images/treemap_medal.png', + fit: BoxFit.contain, + ), + )); + }, + ), + TreemapLevel( + color: Colors.transparent, + padding: EdgeInsets.zero, + border: RoundedRectangleBorder( + side: BorderSide( + color: (themeData.brightness == Brightness.light + ? const Color.fromRGBO(255, 255, 255, 1.0) + : const Color.fromRGBO(0, 0, 0, 1.0)), + width: 0.5), + ), + groupMapper: (int index) { + return _topRioOlympicCountries[index].category; + }, + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return _buildTooltip(tile); + }, + labelBuilder: (BuildContext context, TreemapTile tile) { + Color color; + if (_topRioOlympicCountries[tile.indices[0]].medal == 'Bronze') { + color = const Color.fromRGBO(255, 255, 255, 1.0); + } else { + color = const Color.fromRGBO(72, 72, 72, 1.0); + } + + return Padding( + padding: const EdgeInsets.only(left: 2.0, top: 2.0, bottom: 2.0), + child: Align( + alignment: Alignment.bottomLeft, + child: Text( + tile.group, + style: themeData.textTheme.caption!.copyWith(color: color), + overflow: TextOverflow.ellipsis, + ), + ), + ); + }, + ), + ]; + } + + Widget _buildTooltip(TreemapTile tile) { + return Container( + padding: const EdgeInsets.all(10), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Transform.translate( + offset: const Offset(-3, 0), + child: Icon( + _topRioOlympicCountries[tile.indices[0]].icon, + color: Colors.white, + size: 15, + ), + ), + const SizedBox(height: 5), + Text(tile.group, style: const TextStyle(color: Colors.white)), + ], + ), + const SizedBox(height: 5), + Text( + _topRioOlympicCountries[tile.indices[0]].medal! + + ' : ' + + tile.weight.round().toString(), + style: const TextStyle(color: Colors.white), + ), + ], + ), + ); + } +} + +class _MedalDetails { + const _MedalDetails({ + required this.medalCount, + this.country, + this.medal, + this.category, + this.icon, + }); + + final String? country; + final String? medal; + final String? category; + final double medalCount; + final IconData? icon; +} diff --git a/lib/samples/treemap/flat/flat.dart b/lib/samples/treemap/flat/flat.dart new file mode 100644 index 00000000..a070ae03 --- /dev/null +++ b/lib/samples/treemap/flat/flat.dart @@ -0,0 +1,380 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// The [SfTreemap]'s layout type. +enum LayoutType { + /// slice layout. + slice, + + /// dice layout. + dice, + + /// squarified layout. + squarified +} + +/// This sample demonstrates how to add a different layout in the treemap. +class TreemapLayoutSample extends SampleView { + /// Creates [TreemapLayoutSample]. + const TreemapLayoutSample(Key key, this.layoutType) : super(key: key); + + /// Defines the layout type. + final LayoutType layoutType; + + @override + _TreemapLayoutSampleState createState() => _TreemapLayoutSampleState(); +} + +class _TreemapLayoutSampleState extends State { + late List<_MovieDetails> _topTenMovies; + late bool _isLightTheme; + late bool _isDesktop; + + @override + void initState() { + // Data source to the treemap. + // + // [boxOffice] is used to get each tile's weight. + // [movie] is the flat level grouping key. + _topTenMovies = <_MovieDetails>[ + _MovieDetails( + movie: 'Avengers: Endgame', + director: 'Anthony and Joe Russo', + boxOffice: 2.798, + color: Color.fromRGBO(111, 194, 250, 1.0)), + _MovieDetails( + movie: 'Avatar', + director: 'James Cameron', + boxOffice: 2.834, + color: Color.fromRGBO(71, 94, 209, 1.0)), + _MovieDetails( + movie: 'Titanic', + director: 'James Cameron', + boxOffice: 2.195, + color: Color.fromRGBO(236, 105, 85, 1.0)), + _MovieDetails( + movie: 'Star Wars: The Force Awakens', + director: 'J. J. Abrams', + boxOffice: 2.068, + color: Color.fromRGBO(112, 74, 211, 1.0)), + _MovieDetails( + movie: 'Avengers: Infinity War', + director: 'Anthony and Joe Russo', + boxOffice: 2.048, + color: Color.fromRGBO(78, 198, 125, 1.0)), + _MovieDetails( + movie: 'Jurassic World', + director: 'Colin Trevorrow', + boxOffice: 1.670, + color: Color.fromRGBO(118, 196, 79, 1.0)), + _MovieDetails( + movie: 'The Lion King', + director: 'Jon Favreau', + boxOffice: 1.657, + color: Color.fromRGBO(240, 140, 86, 1.0)), + _MovieDetails( + movie: 'The Avengers', + director: 'Joss Whedon', + boxOffice: 1.519, + color: Color.fromRGBO(84, 114, 246, 1.0)), + _MovieDetails( + movie: 'Furious 7', + director: 'James Wan', + boxOffice: 1.516, + color: Color.fromRGBO(143, 86, 245, 1.0)), + _MovieDetails( + movie: 'Frozen II', + director: 'Chris Buck', + boxOffice: 1.450, + color: Color.fromRGBO(255, 128, 170, 1.0)), + ]; + super.initState(); + } + + @override + void dispose() { + _topTenMovies.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + _isLightTheme = themeData.brightness == Brightness.light; + final Widget current = Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + _isDesktop + ? const EdgeInsets.all(12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + 'Top 10 Highest-Grossing Movies Worldwide', + style: Theme.of(context).textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 12.5), + child: _buildTreemap(themeData), + ), + ), + ], + ), + ), + ); + + return widget.layoutType != LayoutType.slice || + MediaQuery.of(context).orientation == Orientation.portrait || + _isDesktop + ? current + : SingleChildScrollView(child: Container(height: 450, child: current)); + } + + Widget _buildTreemap(ThemeData themeData) { + if (widget.layoutType == LayoutType.slice) { + return SfTreemap.slice( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _topTenMovies.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _topTenMovies[index].boxOffice; + }, + tooltipSettings: TreemapTooltipSettings( + color: _isLightTheme + ? const Color.fromRGBO(45, 45, 45, 1) + : const Color.fromRGBO(242, 242, 242, 1), + ), + levels: _getTreemapLevels(themeData), + ); + } else if (widget.layoutType == LayoutType.dice) { + return SfTreemap.dice( + dataCount: _topTenMovies.length, + weightValueMapper: (int index) { + return _topTenMovies[index].boxOffice; + }, + tooltipSettings: TreemapTooltipSettings( + color: _isLightTheme + ? const Color.fromRGBO(45, 45, 45, 1) + : const Color.fromRGBO(242, 242, 242, 1), + ), + levels: _getTreemapLevels(themeData), + ); + } else { + return SfTreemap( + dataCount: _topTenMovies.length, + weightValueMapper: (int index) { + return _topTenMovies[index].boxOffice; + }, + tooltipSettings: TreemapTooltipSettings( + color: _isLightTheme + ? const Color.fromRGBO(45, 45, 45, 1) + : const Color.fromRGBO(242, 242, 242, 1), + ), + levels: _getTreemapLevels(themeData), + ); + } + } + + List _getTreemapLevels(ThemeData themeData) { + return [ + TreemapLevel( + color: Colors.red, + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder], [tooltipBuilder], and + // [itemBuilder] callbacks respectively. + groupMapper: (int index) => _topTenMovies[index].movie, + // Padding around the tile. + padding: const EdgeInsets.all(1.0), + // Border around the tile. + border: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(2.0))), + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + return _buildLabelBuilder(tile); + }, + // Returns a widget for each tile's content. + itemBuilder: (BuildContext context, TreemapTile tile) { + if (widget.layoutType == LayoutType.dice) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: [0, 1.0], + colors: [ + (_isLightTheme + ? const Color.fromRGBO(76, 187, 220, 1.0) + : const Color.fromRGBO(76, 187, 220, 1.0)), + const Color.fromRGBO(50, 128, 214, 1.0), + ], + ), + ), + ); + } else if (widget.layoutType == LayoutType.slice) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + stops: [0, 1.0], + colors: [ + const Color.fromRGBO(50, 128, 214, 1.0), + (_isLightTheme + ? const Color.fromRGBO(76, 187, 220, 1.0) + : const Color.fromRGBO(76, 187, 220, 1.0)), + ], + ), + ), + ); + } else { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + stops: [0.0, 1.0], + colors: [ + const Color.fromRGBO(50, 128, 214, 1.0), + (_isLightTheme + ? const Color.fromRGBO(76, 187, 220, 1.0) + : const Color.fromRGBO(76, 187, 220, 1.0)), + ], + ), + ), + ); + } + }, + // Returns a widget for each tile's tooltip. + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return _buildTooltipBuilder(tile, themeData); + }, + ), + ]; + } + + Widget _buildLabelBuilder(TreemapTile tile) { + if (widget.layoutType == LayoutType.slice) { + return Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + tile.group, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: Colors.white), + ), + ), + ); + } else if (widget.layoutType == LayoutType.dice) { + return Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: _isDesktop + ? const EdgeInsets.only(bottom: 10.0) + : const EdgeInsets.only(bottom: 6.0), + child: RotatedBox( + quarterTurns: 3, + child: Text( + tile.group, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: Colors.white), + ), + ), + ), + ); + } else { + return Align( + alignment: Alignment.center, + child: Text( + tile.group, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: Colors.white), + ), + ); + } + } + + Widget _buildTooltipBuilder(TreemapTile tile, ThemeData themeData) { + final _MovieDetails movieDetails = _topTenMovies[tile.indices[0]]; + return Padding( + padding: const EdgeInsets.fromLTRB(10.0, 7.0, 10.0, 8.5), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + child: RichText( + text: TextSpan( + text: 'Director', + style: themeData.textTheme.caption!.copyWith( + height: 1.5, + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 0.75) + : const Color.fromRGBO(10, 10, 10, 0.75), + ), + children: [ + TextSpan(text: '\nBox office'), + ], + ), + ), + ), + const SizedBox(width: 15.0), + SizedBox( + child: RichText( + text: TextSpan( + text: '${movieDetails.director}', + style: themeData.textTheme.caption!.copyWith( + height: 1.5, + fontWeight: FontWeight.bold, + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1), + ), + children: [ + TextSpan(text: '\n\$${movieDetails.boxOffice}B'), + ], + ), + ), + ) + ], + ), + ); + } +} + +class _MovieDetails { + const _MovieDetails({ + required this.boxOffice, + this.movie, + this.director, + this.releaseDate, + this.budget, + this.color, + }); + + final String? movie; + final String? director; + final String? releaseDate; + final double? budget; + final double boxOffice; + final Color? color; +} diff --git a/lib/samples/treemap/hierarchical/hierarchical.dart b/lib/samples/treemap/hierarchical/hierarchical.dart new file mode 100644 index 00000000..7013f673 --- /dev/null +++ b/lib/samples/treemap/hierarchical/hierarchical.dart @@ -0,0 +1,200 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// This sample demonstrates how to add a multiple level tiles in the treemap. +class HierarchicalTreemapSample extends SampleView { + /// Creates [HierarchicalTreemapSample]. + const HierarchicalTreemapSample(Key key) : super(key: key); + + @override + _HierarchicalTreemapSampleState createState() => + _HierarchicalTreemapSampleState(); +} + +class _HierarchicalTreemapSampleState extends SampleViewState { + late List<_FootballTeamDetails> _europeanCupAndUEFALeagueWinners; + + @override + void initState() { + // Data source to the treemap. + // + // [titles] is used to get each tile's weight. + // [nation] is the first level grouping key. + // [team] is the second level grouping key. + _europeanCupAndUEFALeagueWinners = <_FootballTeamDetails>[ + _FootballTeamDetails(nation: 'ESP', team: 'Real Madrid', titles: 13), + _FootballTeamDetails(nation: 'ITA', team: 'Milan', titles: 7), + _FootballTeamDetails(nation: 'GER', team: 'Bayern Munich', titles: 6), + _FootballTeamDetails(nation: 'ENG', team: 'Liverpool', titles: 6), + _FootballTeamDetails(nation: 'ESP', team: 'Barcelona', titles: 5), + _FootballTeamDetails(nation: 'NED', team: 'Ajax', titles: 4), + _FootballTeamDetails(nation: 'ENG', team: 'Manchester United', titles: 3), + _FootballTeamDetails(nation: 'ITA', team: 'Inter Milan', titles: 3), + _FootballTeamDetails(nation: 'ITA', team: 'Juventus', titles: 2), + _FootballTeamDetails(nation: 'POR', team: 'Benfica', titles: 2), + _FootballTeamDetails(nation: 'ENG', team: 'Nottingham Forest', titles: 2), + _FootballTeamDetails(nation: 'POR', team: 'Porto', titles: 2), + _FootballTeamDetails(nation: 'SCO', team: 'Celtic', titles: 1), + _FootballTeamDetails(nation: 'GER', team: 'Hamburger SV', titles: 1), + _FootballTeamDetails(nation: 'ROU', team: 'Steaua București', titles: 1), + _FootballTeamDetails(nation: 'FRA', team: 'Marseille', titles: 1), + _FootballTeamDetails(nation: 'GER', team: 'Borussia Dortmund', titles: 1), + _FootballTeamDetails(nation: 'ENG', team: 'Chelsea', titles: 1), + _FootballTeamDetails(nation: 'NED', team: 'Feyenoord', titles: 1), + _FootballTeamDetails(nation: 'ENG', team: 'Aston Villa', titles: 1), + _FootballTeamDetails(nation: 'NED', team: 'PSV Eindhoven', titles: 1), + _FootballTeamDetails(nation: 'YUG', team: 'Red Star Belgrade', titles: 1), + ]; + + super.initState(); + } + + @override + void dispose() { + _europeanCupAndUEFALeagueWinners.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + final bool isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + return Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + isDesktop + ? const EdgeInsets.all(12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + 'European Cup and UEFA Champions League Winners', + style: themeData.textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 12.5), + child: SfTreemap( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _europeanCupAndUEFALeagueWinners.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _europeanCupAndUEFALeagueWinners[index].titles; + }, + tooltipSettings: const TreemapTooltipSettings( + color: Color.fromRGBO(2, 99, 103, 1.0), + ), + levels: _getTreemapLevels(themeData), + ), + ), + ), + ], + ), + ), + ); + } + + List _getTreemapLevels(ThemeData themeData) { + return [ + TreemapLevel( + color: const Color.fromRGBO(1, 166, 172, 1.0), + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder] and [tooltipBuilder] + // callbacks respectively. + groupMapper: (int index) => + _europeanCupAndUEFALeagueWinners[index].nation, + // Padding around the tile. + padding: const EdgeInsets.all(1.5), + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: const EdgeInsets.only(left: 6, top: 4.0), + child: Text( + tile.group, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.white, + fontSize: Theme.of(context).textTheme.caption!.fontSize), + ), + ); + }, + ), + TreemapLevel( + color: const Color.fromRGBO(103, 206, 208, 1.0), + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder] and [tooltipBuilder] + // callbacks respectively. + groupMapper: (int index) => + _europeanCupAndUEFALeagueWinners[index].team, + // Padding around the tile. + padding: const EdgeInsets.all(1.0), + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: const EdgeInsets.only(left: 4.0, top: 2.0), + child: Text( + tile.group, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Colors.black, + fontSize: Theme.of(context).textTheme.caption!.fontSize), + ), + ); + }, + // Returns a widget for each tile's tooltip. + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: RichText( + text: TextSpan( + text: tile.group, + style: themeData.textTheme.caption!.copyWith( + fontWeight: FontWeight.bold, + color: Colors.white, + height: 1.5), + children: [ + TextSpan( + text: '\nTitles : ${tile.weight.round()}', + style: themeData.textTheme.caption!.copyWith( + color: Colors.white, fontWeight: FontWeight.normal), + ), + ], + ), + ), + ); + }, + ), + ]; + } +} + +class _FootballTeamDetails { + const _FootballTeamDetails({ + required this.titles, + this.nation, + this.team, + }); + + final String? nation; + final String? team; + final double titles; +} diff --git a/lib/samples/treemap/range_color_mapping/range_color_mapping.dart b/lib/samples/treemap/range_color_mapping/range_color_mapping.dart new file mode 100644 index 00000000..3cb64976 --- /dev/null +++ b/lib/samples/treemap/range_color_mapping/range_color_mapping.dart @@ -0,0 +1,639 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// This sample demonstrates how to apply color to a tile based on the range +/// of values. +class TreemapRangeColorMappingSample extends SampleView { + /// Creates [TreemapRangeColorMappingSample]. + const TreemapRangeColorMappingSample(Key key) : super(key: key); + + @override + _TreemapRangeColorMappingSampleState createState() => + _TreemapRangeColorMappingSampleState(); +} + +class _TreemapRangeColorMappingSampleState extends SampleViewState { + late List<_StateElectionDetails> _stateWiseElectionResult; + late List _colorMappers; + late bool _isLightTheme; + + @override + void initState() { + // Data source to the treemap. + // + // [totalVoters] is used to get each tile's weight. + // [state] is the flat level grouping key. + _stateWiseElectionResult = <_StateElectionDetails>[ + _StateElectionDetails( + state: 'Washington', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 4087631, + votes: 2369612, + percentage: 57.97), + _StateElectionDetails( + state: 'Oregon', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 2374321, + votes: 1340383, + percentage: 56.45), + _StateElectionDetails( + state: 'Alabama', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 2323282, + votes: 1441170, + percentage: 62.03), + _StateElectionDetails( + state: 'Alaska', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 359530, + votes: 189951, + percentage: 52.83), + _StateElectionDetails( + state: 'Arizona', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3387326, + votes: 1672143, + percentage: 49.36), + _StateElectionDetails( + state: 'Arkansas', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1219069, + votes: 760647, + percentage: 62.40), + _StateElectionDetails( + state: 'California', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 17500881, + votes: 11110250, + percentage: 63.48), + _StateElectionDetails( + state: 'Colorado', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3256980, + votes: 1804352, + percentage: 55.40), + _StateElectionDetails( + state: 'Connecticut', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 1823857, + votes: 1080831, + percentage: 59.26), + _StateElectionDetails( + state: 'Delaware', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 504346, + votes: 296268, + percentage: 58.74), + _StateElectionDetails( + state: 'District of Columbia', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 344356, + votes: 317323, + percentage: 92.15), + _StateElectionDetails( + state: 'Florida', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 11067456, + votes: 5668731, + percentage: 51.22), + _StateElectionDetails( + state: 'Georgia', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 4999960, + votes: 2473633, + percentage: 49.47), + _StateElectionDetails( + state: 'Hawaii', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 574469, + votes: 366130, + percentage: 63.73), + _StateElectionDetails( + state: 'Idaho', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 868014, + votes: 554119, + percentage: 63.84), + _StateElectionDetails( + state: 'Illinois', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 6033744, + votes: 3471915, + percentage: 57.54), + _StateElectionDetails( + state: 'Indiana', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 3033121, + votes: 1729519, + percentage: 57.02), + _StateElectionDetails( + state: 'Iowa', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1690871, + votes: 897672, + percentage: 53.09), + _StateElectionDetails( + state: 'Kansas', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1372303, + votes: 771406, + percentage: 56.21), + _StateElectionDetails( + state: 'Kentucky', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 2136768, + votes: 1326646, + percentage: 62.09), + _StateElectionDetails( + state: 'Louisiana', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 2148062, + votes: 1255776, + percentage: 58.46), + _StateElectionDetails( + state: 'Maine-1', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 443112, + votes: 266376, + percentage: 60.11), + _StateElectionDetails( + state: 'Maine-2', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 376349, + votes: 196692, + percentage: 52.26), + _StateElectionDetails( + state: 'Maryland', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3037030, + votes: 1985023, + percentage: 65.36), + _StateElectionDetails( + state: 'Massachusetts', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3631402, + votes: 2382202, + percentage: 65.60), + _StateElectionDetails( + state: 'Michigan', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 5539302, + votes: 2804040, + percentage: 50.62), + _StateElectionDetails( + state: 'Minnesota', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3277171, + votes: 1717077, + percentage: 52.40), + _StateElectionDetails( + state: 'Mississippi', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1313759, + votes: 756764, + percentage: 57.60), + _StateElectionDetails( + state: 'Missouri', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 3025962, + votes: 1718736, + percentage: 56.80), + _StateElectionDetails( + state: 'Montana', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 603674, + votes: 343602, + percentage: 56.92), + _StateElectionDetails( + state: 'Nebraska-1', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 321886, + votes: 180290, + percentage: 56.01), + _StateElectionDetails( + state: 'Nebraska-2', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 339666, + votes: 176468, + percentage: 51.95), + _StateElectionDetails( + state: 'Nebraska-3', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 294831, + votes: 222179, + percentage: 75.36), + _StateElectionDetails( + state: 'Nevada', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 1405376, + votes: 703486, + percentage: 50.06), + _StateElectionDetails( + state: 'New Hampshire', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 806205, + votes: 424937, + percentage: 52.71), + _StateElectionDetails( + state: 'New Jersey', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 4549353, + votes: 2608335, + percentage: 57.33), + _StateElectionDetails( + state: 'New Mexico', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 923965, + votes: 501614, + percentage: 54.29), + _StateElectionDetails( + state: 'New York', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 8594826, + votes: 5230985, + percentage: 60.86), + _StateElectionDetails( + state: 'North Carolina', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 5524804, + votes: 2758775, + percentage: 49.93), + _StateElectionDetails( + state: 'North Dakota', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 361819, + votes: 235595, + percentage: 65.11), + _StateElectionDetails( + state: 'Ohio', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 5922202, + votes: 3154834, + percentage: 53.27), + _StateElectionDetails( + state: 'Oklahoma', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1560699, + votes: 1020280, + percentage: 65.37), + _StateElectionDetails( + state: 'Pennsylvania', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 6915283, + votes: 3458229, + percentage: 50.01), + _StateElectionDetails( + state: 'Rhode Island', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 517757, + votes: 307486, + percentage: 59.39), + _StateElectionDetails( + state: 'South Carolina', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 2513329, + votes: 1385103, + percentage: 55.11), + _StateElectionDetails( + state: 'South Dakota', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 422609, + votes: 261043, + percentage: 61.77), + _StateElectionDetails( + state: 'Tennessee', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 3053851, + votes: 1852475, + percentage: 60.66), + _StateElectionDetails( + state: 'Texas', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 11315056, + votes: 5890347, + percentage: 52.06), + _StateElectionDetails( + state: 'Utah', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 1488289, + votes: 865140, + percentage: 58.13), + _StateElectionDetails( + state: 'Vermont', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 367428, + votes: 242820, + percentage: 66.09), + _StateElectionDetails( + state: 'Virginia', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 4460524, + votes: 2413568, + percentage: 54.11), + _StateElectionDetails( + state: 'West Virginia', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 794731, + votes: 235984, + percentage: 68.62), + _StateElectionDetails( + state: 'Wisconsin', + candidate: 'Joe Biden', + party: 'Democratic', + totalVoters: 3298041, + votes: 1610184, + percentage: 49.45), + _StateElectionDetails( + state: 'Wyoming', + candidate: 'Donald Trump', + party: 'Republican', + totalVoters: 276765, + votes: 193559, + percentage: 69.94), + ]; + + _colorMappers = [ + TreemapColorMapper.range( + from: 80, + to: 100, + color: Color.fromRGBO(0, 0, 81, 1.0), + name: '{Democratic},{}'), + TreemapColorMapper.range( + from: 75, to: 80, color: Color.fromRGBO(0, 43, 132, 1.0), name: ''), + TreemapColorMapper.range( + from: 70, to: 75, color: Color.fromRGBO(6, 69, 180, 1.0), name: ''), + TreemapColorMapper.range( + from: 65, to: 70, color: Color.fromRGBO(22, 102, 203, 1.0), name: ''), + TreemapColorMapper.range( + from: 60, to: 65, color: Color.fromRGBO(67, 137, 227, 1.0), name: ''), + TreemapColorMapper.range( + from: 55, to: 60, color: Color.fromRGBO(80, 154, 242, 1.0), name: ''), + TreemapColorMapper.range( + from: 45, + to: 55, + color: Color.fromRGBO(134, 182, 242, 1.0), + name: ''), + TreemapColorMapper.range( + from: -55, + to: -45, + color: Color.fromRGBO(255, 178, 178, 1.0), + name: ''), + TreemapColorMapper.range( + from: -60, + to: -55, + color: Color.fromRGBO(255, 127, 127, 1.0), + name: ''), + TreemapColorMapper.range( + from: -65, + to: -60, + color: Color.fromRGBO(255, 76, 76, 1.0), + name: ''), + TreemapColorMapper.range( + from: -70, + to: -65, + color: Color.fromRGBO(255, 50, 50, 1.0), + name: ''), + TreemapColorMapper.range( + from: -75, to: -70, color: Color.fromRGBO(178, 0, 0, 1.0), name: ''), + TreemapColorMapper.range( + from: -80, to: -75, color: Color.fromRGBO(127, 0, 0, 1.0), name: ''), + TreemapColorMapper.range( + from: -100, + to: -80, + color: Color.fromRGBO(102, 0, 0, 1.0), + name: 'Republican'), + ]; + + super.initState(); + } + + @override + void dispose() { + _stateWiseElectionResult.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isLightTheme = themeData.brightness == Brightness.light; + final bool isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final Size size = Size(constraints.maxWidth, constraints.maxHeight); + return Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + isDesktop + ? const EdgeInsets.all(12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + '2020 US Election Results', + style: Theme.of(context).textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: SfTreemap( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _stateWiseElectionResult.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _stateWiseElectionResult[index].totalVoters; + }, + tooltipSettings: TreemapTooltipSettings( + color: _isLightTheme + ? const Color.fromRGBO(45, 45, 45, 1) + : const Color.fromRGBO(242, 242, 242, 1), + ), + colorMappers: _colorMappers, + levels: _getTreemapLevels(themeData), + legend: TreemapLegend.bar( + segmentSize: isDesktop + ? const Size(25, 12) + : Size( + (size.width * 0.80) / _colorMappers.length, 12.0), + edgeLabelsPlacement: + TreemapLegendEdgeLabelsPlacement.inside, + labelOverflow: TreemapLabelOverflow.visible, + spacing: 0.0, + textStyle: const TextStyle(fontSize: 10), + ), + ), + ), + ), + ], + ), + ), + ); + }); + } + + List _getTreemapLevels(ThemeData themeData) { + return [ + TreemapLevel( + color: Colors.red, + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder], [tooltipBuilder], and + // [colorValueMapper] callbacks respectively. + groupMapper: (int index) => _stateWiseElectionResult[index].state, + // Padding around the tile. + padding: const EdgeInsets.all(0.5), + // The value returned in the callback will specify the + // color of each tile. + colorValueMapper: (TreemapTile tile) { + if (_stateWiseElectionResult[tile.indices[0]].candidate == + 'Joe Biden') { + return _stateWiseElectionResult[tile.indices[0]].percentage; + } else { + return -(_stateWiseElectionResult[tile.indices[0]].percentage!); + } + }, + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + final Brightness brightness = + ThemeData.estimateBrightnessForColor(tile.color); + final Color color = + brightness == Brightness.dark ? Colors.white : Colors.black; + return Padding( + padding: const EdgeInsets.only(left: 4.0, top: 4.0), + child: Text( + tile.group, + style: themeData.textTheme.caption!.copyWith( + fontSize: 11, + color: color, + ), + overflow: TextOverflow.ellipsis, + ), + ); + }, + // Returns a widget for each tile's tooltip. + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: RichText( + text: TextSpan( + text: _stateWiseElectionResult[tile.indices[0]].candidate, + style: themeData.textTheme.caption!.copyWith( + height: 1.5, + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1), + ), + children: [ + TextSpan( + text: '\n${tile.group}', + style: themeData.textTheme.caption!.copyWith( + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1), + )), + TextSpan( + text: '\nWon percentage : ' + + _stateWiseElectionResult[tile.indices[0]] + .percentage + .toString() + + '%', + style: themeData.textTheme.caption!.copyWith( + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1), + ), + ), + ], + ), + ), + ); + }, + ), + ]; + } +} + +class _StateElectionDetails { + const _StateElectionDetails( + {required this.totalVoters, + this.state, + this.party, + this.candidate, + this.votes, + this.percentage}); + + final String? state; + final double totalVoters; + final String? party; + final String? candidate; + final double? votes; + final double? percentage; +} diff --git a/lib/samples/treemap/selection/selection.dart b/lib/samples/treemap/selection/selection.dart new file mode 100644 index 00000000..30ba5c6a --- /dev/null +++ b/lib/samples/treemap/selection/selection.dart @@ -0,0 +1,338 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// This sample demonstrates how to select a particular tile in the treemap. +class TreemapSelectionSample extends SampleView { + /// Creates [TreemapSelectionSample]. + const TreemapSelectionSample(Key key) : super(key: key); + + @override + _TreemapSelectionSampleState createState() => _TreemapSelectionSampleState(); +} + +class _TreemapSelectionSampleState extends SampleViewState { + late List<_ImportAndExportDetails> _topImportsAndExports; + late TextEditingController _importTextEditingController; + late TextEditingController _exportTextEditingController; + TreemapTile? _selectedTile; + + @override + void initState() { + // Data source to the treemap. + // + // [valueInBillions] is used to get each tile's weight. + // [type] is the first level grouping key. + // [product] is the second level grouping key. + _topImportsAndExports = <_ImportAndExportDetails>[ + _ImportAndExportDetails( + type: 'Import', + product: 'Cars', + valueInBillions: 145.66, + color: Color.fromRGBO(64, 116, 218, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'PC, optical readers', + valueInBillions: 104.95, + color: Color.fromRGBO(85, 126, 213, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Phone devices', + valueInBillions: 102.55, + color: Color.fromRGBO(98, 136, 217, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Medication', + valueInBillions: 95.18, + color: Color.fromRGBO(109, 145, 219, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Crude oil', + valueInBillions: 81.86, + color: Color.fromRGBO(121, 154, 222, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Automobile parts', + valueInBillions: 81.63, + color: Color.fromRGBO(134, 163, 225, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Blood fractions', + valueInBillions: 60.04, + color: Color.fromRGBO(158, 181, 230, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Petroleum oils', + valueInBillions: 51.38, + color: Color.fromRGBO(171, 191, 234, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'Gold', + valueInBillions: 36.32, + color: Color.fromRGBO(182, 200, 236, 1.0)), + _ImportAndExportDetails( + type: 'Import', + product: 'IC', + valueInBillions: 34.69, + color: Color.fromRGBO(202, 215, 241, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Petroleum oils', + valueInBillions: 60.71, + color: Color.fromRGBO(83, 192, 83, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Crude oil', + valueInBillions: 50.29, + color: Color.fromRGBO(121, 193, 106, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Cars', + valueInBillions: 45.64, + color: Color.fromRGBO(129, 197, 115, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'IC', + valueInBillions: 44.21, + color: Color.fromRGBO(138, 201, 126, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Petroleum gases', + valueInBillions: 33.34, + color: Color.fromRGBO(147, 205, 136, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Automobile parts', + valueInBillions: 33.17, + color: Color.fromRGBO(156, 210, 146, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Phone devices', + valueInBillions: 28.09, + color: Color.fromRGBO(165, 214, 156, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Electro-medical', + valueInBillions: 28.02, + color: Color.fromRGBO(174, 218, 166, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Blood fractions', + valueInBillions: 26.09, + color: Color.fromRGBO(184, 222, 177, 1.0)), + _ImportAndExportDetails( + type: 'Export', + product: 'Soya beans', + valueInBillions: 25.85, + color: Color.fromRGBO(202, 231, 198, 1.0)), + ]; + + super.initState(); + } + + @override + void dispose() { + _topImportsAndExports.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + final bool isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + return Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + isDesktop + ? const EdgeInsets.all(12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + 'Top 10 Imports and Exports of USA 2020', + style: Theme.of(context).textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 12.5), + child: SfTreemap( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _topImportsAndExports.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _topImportsAndExports[index].valueInBillions; + }, + // The callback will be called while doing selection on the + // tile. + onSelectionChanged: (TreemapTile tile) { + setState( + () { + _updateLabelBuilderText(tile); + }, + ); + }, + levels: _getTreemapLevels(), + ), + ), + ), + ], + ), + ), + ); + } + + void _updateLabelBuilderText(TreemapTile tile) { + if (tile != _selectedTile) { + _selectedTile = tile; + if (_topImportsAndExports[tile.indices[0]].type == 'Import') { + _importTextEditingController.text = tile.group == 'Import' + ? 'Import - ${tile.weight.toStringAsFixed(2)}B' + : 'Import - ${tile.group} (${tile.weight.toStringAsFixed(2)}B)'; + _exportTextEditingController.text = 'Export'; + } else { + _exportTextEditingController.text = tile.group == 'Export' + ? 'Export - ${tile.weight.toStringAsFixed(2)}B' + : 'Export - ${tile.group} (${tile.weight.toStringAsFixed(2)}B)'; + _importTextEditingController.text = 'Import'; + } + } else { + _selectedTile = null; + if (_topImportsAndExports[tile.indices[0]].type == 'Import') { + _importTextEditingController.text = + _topImportsAndExports[tile.indices[0]].type!; + } else { + _exportTextEditingController.text = + _topImportsAndExports[tile.indices[0]].type!; + } + } + } + + List _getTreemapLevels() { + return [ + TreemapLevel( + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder] and [colorValueMapper] + // callbacks respectively. + groupMapper: (int index) { + return _topImportsAndExports[index].type; + }, + // Padding around the tile. + padding: const EdgeInsets.all(2.0), + color: Colors.transparent, + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + final Brightness brightness = + ThemeData.estimateBrightnessForColor(tile.color); + final Color color = + brightness == Brightness.dark ? Colors.white : Colors.black; + if (tile.group == 'Import') { + _importTextEditingController = + TextEditingController(text: tile.group); + return IgnorePointer( + child: ColoredBox( + color: const Color.fromRGBO(52, 94, 176, 1.0), + child: Center( + child: TextField( + controller: _importTextEditingController, + enabled: false, + textAlign: TextAlign.center, + style: TextStyle(color: color), + decoration: const InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + ), + ), + ), + ), + ); + } else { + _exportTextEditingController = + TextEditingController(text: tile.group); + return IgnorePointer( + child: Container( + color: const Color.fromRGBO(67, 156, 67, 1.0), + child: Center( + child: TextField( + controller: _exportTextEditingController, + enabled: false, + textAlign: TextAlign.center, + style: TextStyle(color: color), + decoration: const InputDecoration( + border: InputBorder.none, + ), + ), + ), + ), + ); + } + }, + ), + TreemapLevel( + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder] and [colorValueMapper] + // callbacks respectively. + groupMapper: (int index) { + return _topImportsAndExports[index].product; + }, + // Padding around the tile. + padding: const EdgeInsets.only(top: 2.0, left: 1.0, right: 1.0), + // The value returned in the callback will specify the + // color of each tile. + colorValueMapper: (TreemapTile tile) { + return _topImportsAndExports[tile.indices[0]].color; + }, + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + final Brightness brightness = + ThemeData.estimateBrightnessForColor(tile.color); + final Color color = + brightness == Brightness.dark ? Colors.white : Colors.black; + return IgnorePointer( + child: Padding( + padding: const EdgeInsets.all(5.0), + child: Center( + child: Text( + tile.group, + style: TextStyle(color: color), + overflow: TextOverflow.ellipsis, + ), + ), + ), + ); + }, + ), + ]; + } +} + +class _ImportAndExportDetails { + const _ImportAndExportDetails({ + required this.valueInBillions, + this.type, + this.product, + this.color, + }); + + final String? type; + final String? product; + final double valueInBillions; + final Color? color; +} diff --git a/lib/samples/treemap/value_color_mapping/value_color_mapping.dart b/lib/samples/treemap/value_color_mapping/value_color_mapping.dart new file mode 100644 index 00000000..1cc0daf3 --- /dev/null +++ b/lib/samples/treemap/value_color_mapping/value_color_mapping.dart @@ -0,0 +1,214 @@ +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Treemap import. +import 'package:syncfusion_flutter_treemap/treemap.dart'; + +/// Local import. +import '../../../model/sample_view.dart'; + +/// This sample demonstrates how to apply color to the tiles based on the +/// specific value. +class TreemapValueColorMappingSample extends SampleView { + /// Creates [TreemapValueColorMappingSample]. + const TreemapValueColorMappingSample(Key key) : super(key: key); + + @override + _TreemapValueColorMappingSampleState createState() => + _TreemapValueColorMappingSampleState(); +} + +class _TreemapValueColorMappingSampleState extends SampleViewState { + late List<_MarketPlace> _topOnlineMarketPlaces; + late List _colorMappers; + late bool _isLightTheme; + + @override + void initState() { + // Data source to the treemap. + // + // [visitorsInBillions] is used to get each tile's weight. + // [name] is the flat level grouping key. + _topOnlineMarketPlaces = <_MarketPlace>[ + _MarketPlace(country: 'USA', name: 'Amazon', visitorsInBillions: 5.7), + _MarketPlace( + country: 'Japan', name: 'PayPay Mall', visitorsInBillions: 2.1), + _MarketPlace(country: 'USA', name: 'eBay', visitorsInBillions: 1.6), + _MarketPlace( + country: 'Argentina', + name: 'Mercado Libre', + visitorsInBillions: 0.6617), + _MarketPlace( + country: 'China', name: 'AliExpress', visitorsInBillions: 0.6391), + _MarketPlace( + country: 'Japan', name: 'Rakuten', visitorsInBillions: 0.6215), + _MarketPlace( + country: 'China', name: 'Taobao', visitorsInBillions: 0.5452), + _MarketPlace( + country: 'USA', name: 'Walmart.com', visitorsInBillions: 0.469), + _MarketPlace( + country: 'China', name: 'JD.com', visitorsInBillions: 0.3182), + _MarketPlace(country: 'USA', name: 'Etsy', visitorsInBillions: 0.2663), + ]; + + _colorMappers = [ + TreemapColorMapper.value( + value: 'USA', color: Color.fromRGBO(71, 94, 209, 1.0)), + TreemapColorMapper.value( + value: 'Japan', color: Color.fromRGBO(236, 105, 85, 1.0)), + TreemapColorMapper.value( + value: 'Argentina', color: Color.fromRGBO(78, 198, 125, 1.0)), + TreemapColorMapper.value( + value: 'China', color: Color.fromRGBO(240, 140, 86, 1.0)), + ]; + + super.initState(); + } + + @override + void dispose() { + _topOnlineMarketPlaces.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + _isLightTheme = themeData.brightness == Brightness.light; + final bool isDesktop = kIsWeb || + themeData.platform == TargetPlatform.macOS || + themeData.platform == TargetPlatform.linux || + themeData.platform == TargetPlatform.windows; + + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final Size size = Size(constraints.maxWidth, constraints.maxHeight); + return Center( + child: Padding( + padding: MediaQuery.of(context).orientation == Orientation.portrait || + isDesktop + ? const EdgeInsets.only(left: 12.5, right: 12.5, top: 12.5) + : const EdgeInsets.all(10.0), + child: Column( + children: [ + Text( + 'Top 10 Online Marketplaces', + style: Theme.of(context).textTheme.subtitle1, + textAlign: TextAlign.center, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: SfTreemap( + // The number of data in your data source collection. + // + // The callback for the [weightValueMapper] and + // [TreemapLevel.groupMapper] will be called + // the number of times equal to the [dataCount]. + dataCount: _topOnlineMarketPlaces.length, + // The value returned in the callback will specify the + // weight of each tile. + weightValueMapper: (int index) { + return _topOnlineMarketPlaces[index].visitorsInBillions; + }, + tooltipSettings: TreemapTooltipSettings( + color: _isLightTheme + ? const Color.fromRGBO(45, 45, 45, 1) + : const Color.fromRGBO(242, 242, 242, 1), + ), + levels: _getTreemapLevels(themeData), + colorMappers: _colorMappers, + legend: TreemapLegend.bar( + position: TreemapLegendPosition.bottom, + segmentSize: isDesktop + ? const Size(80.0, 12.0) + : Size( + (size.width * 0.80) / _colorMappers.length, 12.0), + ), + ), + ), + ), + ], + ), + ), + ); + }); + } + + List _getTreemapLevels(ThemeData themeData) { + return [ + TreemapLevel( + color: Colors.cyan, + // Used for grouping the tiles based on the value returned from + // this callback. + // + // Once grouped, we will get [labelBuilder], [tooltipBuilder], and + // [colorValueMapper] callbacks respectively. + groupMapper: (int index) => _topOnlineMarketPlaces[index].name, + // Padding around the tile. + padding: const EdgeInsets.all(1.0), + // The value returned in the callback will specify the + // color of each tile. + colorValueMapper: (TreemapTile tile) { + return _topOnlineMarketPlaces[tile.indices[0]].country; + }, + // Returns a widget for each tile's data label. + labelBuilder: (BuildContext context, TreemapTile tile) { + final Brightness brightness = + ThemeData.estimateBrightnessForColor(tile.color); + final Color color = + brightness == Brightness.dark ? Colors.white : Colors.black; + return Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + tile.group, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: color, + fontSize: Theme.of(context).textTheme.caption!.fontSize), + ), + ); + }, + // Returns a widget for each tile's tooltip. + tooltipBuilder: (BuildContext context, TreemapTile tile) { + return Padding( + padding: const EdgeInsets.all(10.0), + child: RichText( + text: TextSpan( + text: + 'Country : ${_topOnlineMarketPlaces[tile.indices[0]].country}', + style: themeData.textTheme.caption!.copyWith( + height: 1.5, + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1), + ), + children: [ + TextSpan( + text: '\nVisitors : ${tile.weight}B', + style: themeData.textTheme.caption!.copyWith( + color: _isLightTheme + ? const Color.fromRGBO(255, 255, 255, 1) + : const Color.fromRGBO(10, 10, 10, 1)), + ), + ], + ), + ), + ); + }, + ), + ]; + } +} + +class _MarketPlace { + const _MarketPlace({ + required this.visitorsInBillions, + required this.country, + required this.name, + }); + + final String country; + final String name; + final double visitorsInBillions; +} diff --git a/lib/samples/xlsio/attendance_tracker/attendance_tracker.dart b/lib/samples/xlsio/attendance_tracker/attendance_tracker.dart new file mode 100644 index 00000000..f0db14a8 --- /dev/null +++ b/lib/samples/xlsio/attendance_tracker/attendance_tracker.dart @@ -0,0 +1,644 @@ +///Package imports +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +///XlsIO import +import 'package:syncfusion_flutter_xlsio/xlsio.dart' hide Column, Alignment; + +///Local imports +import '../../../model/sample_view.dart'; +import '../helper/save_file_mobile.dart' + if (dart.library.html) '../helper/save_file_web.dart'; + +/// Render XlsIO of balance sheet +class AttendanceTrackerXlsIO extends SampleView { + /// Render XlsIO of balance sheet + const AttendanceTrackerXlsIO(Key key) : super(key: key); + @override + _AttendanceTrackerXlsIOState createState() => _AttendanceTrackerXlsIOState(); +} + +class _AttendanceTrackerXlsIOState extends SampleViewState { + _AttendanceTrackerXlsIOState(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: model.cardThemeColor, + body: Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Attendance tracker or attendance sheet is essential to any organization. This attendance tracker is designed to keep one month data. In this application, Employee Name, Supervisor, Present Count, Absent Count, Leave Count, Unplanned%, Planned% and dates for a particular month are available.\r\n\r\nThis sample demonstrates following features:\r\n\r\n * Import data from a string collection (List) to Excel worksheet\r\n\r\n * Advanced options of conditional formatting in Excel such as, color scales, data bars', + style: TextStyle(fontSize: 16, color: model.textColor)), + const SizedBox(height: 20, width: 30), + Align( + alignment: Alignment.center, + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generateExcel, + child: const Text('Generate Excel', + style: TextStyle(color: Colors.white)), + )) + ], + ), + ), + ), + ); + } + + Future _generateExcel() async { + //Creating a workbook. + final Workbook workbook = Workbook(); + //Accessing via index + final Worksheet sheet = workbook.worksheets[0]; + final DateTime datetime = DateTime.now().toLocal(); + final DateFormat formatter = DateFormat('MMM'); + sheet.name = formatter.format(datetime) + '-' + datetime.year.toString(); + + // Enable sheet calculation. + sheet.enableSheetCalculations(); + + final List heading = [ + 'Employee Name', + 'Supervisor', + DateTime(2019, 1, 1), + DateTime(2019, 1, 2), + DateTime(2019, 1, 3), + DateTime(2019, 1, 4), + DateTime(2019, 1, 5), + DateTime(2019, 1, 6), + DateTime(2019, 1, 7), + DateTime(2019, 1, 8), + DateTime(2019, 1, 9), + DateTime(2019, 1, 10), + DateTime(2019, 1, 11), + DateTime(2019, 1, 12), + DateTime(2019, 1, 13), + DateTime(2019, 1, 14), + DateTime(2019, 1, 15), + DateTime(2019, 1, 16), + DateTime(2019, 1, 17), + DateTime(2019, 1, 18), + DateTime(2019, 1, 19), + DateTime(2019, 1, 20), + DateTime(2019, 1, 21), + DateTime(2019, 1, 22), + DateTime(2019, 1, 23), + DateTime(2019, 1, 24), + DateTime(2019, 1, 25), + DateTime(2019, 1, 26), + DateTime(2019, 1, 27), + DateTime(2019, 1, 28), + DateTime(2019, 1, 29), + DateTime(2019, 1, 30), + DateTime(2019, 1, 31) + ]; + sheet.importList(heading, 1, 1, false); + + final List attendance_1 = [ + 'Maria Anders', + 'Michael Holz', + 'P', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'P', + 'A', + 'P', + 'A', + 'A', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'P', + 'A', + 'WE', + 'WE', + 'P', + 'P', + 'L', + 'A', + 'L', + 'WE', + 'WE', + 'P', + 'P', + 'A', + 'L' + ]; + final List attendance_2 = [ + 'Ana Trujillo', + 'Michael Holz', + 'P', + 'P', + 'P', + 'L', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'P', + 'A', + 'WE', + 'WE', + 'P', + 'P', + 'L', + 'L', + 'P', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'P', + 'L', + 'WE', + 'WE', + 'P', + 'P', + 'L', + 'P' + ]; + final List attendance_3 = [ + 'Antonio Moreno', + 'Liz Nixon', + 'A', + 'P', + 'L', + 'L', + 'WE', + 'WE', + 'P', + 'A', + 'A', + 'P', + 'L', + 'WE', + 'WE', + 'A', + 'P', + 'L', + 'A', + 'P', + 'WE', + 'WE', + 'P', + 'L', + 'L', + 'P', + 'P', + 'WE', + 'WE', + 'L', + 'P', + 'A', + 'A' + ]; + final List attendance_4 = [ + 'Thomas Hardy', + 'Liu Wong', + 'L', + 'A', + 'L', + 'p', + 'WE', + 'WE', + 'P', + 'A', + 'A', + 'P', + 'A', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'L', + 'P', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'L', + 'P', + 'WE', + 'WE', + 'L', + 'A', + 'P', + 'P' + ]; + final List attendance_5 = [ + 'Christina Berglund', + 'Mary Saveley', + 'P', + 'P', + 'P', + 'L', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'L', + 'P', + 'WE', + 'WE', + 'A', + 'A', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'A', + 'A', + 'P', + 'P' + ]; + final List attendance_6 = [ + 'Hanna Moos', + 'Liu Wong', + 'L', + 'P', + 'P', + 'A', + 'WE', + 'WE', + 'P', + 'P', + 'A', + 'P', + 'L', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'L', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'P', + 'L', + 'WE', + 'WE', + 'P', + 'L', + 'L', + 'P' + ]; + final List attendance_7 = [ + 'Frederique Citeaux', + 'Mary Saveley', + 'A', + 'A', + 'A', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'L', + 'A', + 'P', + 'WE', + 'WE', + 'P', + 'P', + 'L', + 'P', + 'P', + 'WE', + 'WE', + 'A', + 'A', + 'P', + 'P', + 'L', + 'WE', + 'WE', + 'L', + 'P', + 'A', + 'A' + ]; + final List attendance_8 = [ + 'Martin Sommer', + 'Michael Holz', + 'L', + 'P', + 'L', + 'A', + 'WE', + 'WE', + 'P', + 'L', + 'P', + 'L', + 'A', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'A', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'A', + 'P', + 'L', + 'WE', + 'WE', + 'A', + 'L', + 'L', + 'L' + ]; + final List attendance_9 = [ + 'Laurence Lebihan', + 'Mary Saveley', + 'P', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'P', + 'P', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'P', + 'P', + 'WE', + 'WE', + 'A', + 'P', + 'P', + 'P', + 'A', + 'WE', + 'WE', + 'L', + 'P', + 'P', + 'P' + ]; + // Import data to sheet. + sheet.importList(attendance_1, 2, 1, false); + sheet.importList(attendance_2, 3, 1, false); + sheet.importList(attendance_3, 4, 1, false); + sheet.importList(attendance_4, 5, 1, false); + sheet.importList(attendance_5, 6, 1, false); + sheet.importList(attendance_6, 7, 1, false); + sheet.importList(attendance_7, 8, 1, false); + sheet.importList(attendance_8, 9, 1, false); + sheet.importList(attendance_9, 10, 1, false); + + // Insert column + sheet.insertColumn(3, 5); + + sheet.getRangeByName('C1').setText('Present Count'); + sheet.getRangeByName('C2').setFormula('=COUNTIFS(H2:AL2,\'P\')'); + sheet.getRangeByName('C3').setFormula('=COUNTIFS(H3:AL3,\'P\')'); + sheet.getRangeByName('C4').setFormula('=COUNTIFS(H4:AL4,\'P\')'); + sheet.getRangeByName('C5').setFormula('=COUNTIFS(H5:AL5,\'P\')'); + sheet.getRangeByName('C6').setFormula('=COUNTIFS(H6:AL6,\'P\')'); + sheet.getRangeByName('C7').setFormula('=COUNTIFS(H7:AL7,\'P\')'); + sheet.getRangeByName('C8').setFormula('=COUNTIFS(H8:AL8,\'P\')'); + sheet.getRangeByName('C9').setFormula('=COUNTIFS(H9:AL9,\'P\')'); + sheet.getRangeByName('C10').setFormula('=COUNTIFS(H10:AL10,\'P\')'); + + sheet.getRangeByName('D1').setText('Leave Count'); + sheet.getRangeByName('D2').setFormula('=COUNTIFS(H2:AL2,\'L\')'); + sheet.getRangeByName('D3').setFormula('=COUNTIFS(H3:AL3,\'L\')'); + sheet.getRangeByName('D4').setFormula('=COUNTIFS(H4:AL4,\'L\')'); + sheet.getRangeByName('D5').setFormula('=COUNTIFS(H5:AL5,\'L\')'); + sheet.getRangeByName('D6').setFormula('=COUNTIFS(H6:AL6,\'L\')'); + sheet.getRangeByName('D7').setFormula('=COUNTIFS(H7:AL7,\'L\')'); + sheet.getRangeByName('D8').setFormula('=COUNTIFS(H8:AL8,\'L\')'); + sheet.getRangeByName('D9').setFormula('=COUNTIFS(H9:AL9,\'L\')'); + sheet.getRangeByName('D10').setFormula('=COUNTIFS(H10:AL10,\'L\')'); + + sheet.getRangeByName('E1').setText('Absent Count'); + sheet.getRangeByName('E2').setFormula('=COUNTIFS(H2:AL2,\'A\')'); + sheet.getRangeByName('E3').setFormula('=COUNTIFS(H3:AL3,\'A\')'); + sheet.getRangeByName('E4').setFormula('=COUNTIFS(H4:AL4,\'A\')'); + sheet.getRangeByName('E5').setFormula('=COUNTIFS(H5:AL5,\'A\')'); + sheet.getRangeByName('E6').setFormula('=COUNTIFS(H6:AL6,\'A\')'); + sheet.getRangeByName('E7').setFormula('=COUNTIFS(H7:AL7,\'A\')'); + sheet.getRangeByName('E8').setFormula('=COUNTIFS(H8:AL8,\'A\')'); + sheet.getRangeByName('E9').setFormula('=COUNTIFS(H9:AL9,\'A\')'); + sheet.getRangeByName('E10').setFormula('=COUNTIFS(H10:AL10,\'A\')'); + + sheet.getRangeByName('F1').setText('Unplanned %'); + sheet.getRangeByName('F2').setFormula('=E2/(C2+D2+E2)'); + sheet.getRangeByName('F3').setFormula('=E3/(C3+D3+E3)'); + sheet.getRangeByName('F4').setFormula('=E4/(C4+D4+E4)'); + sheet.getRangeByName('F5').setFormula('=E5/(C5+D5+E5)'); + sheet.getRangeByName('F6').setFormula('=E6/(C6+D6+E6)'); + sheet.getRangeByName('F7').setFormula('=E7/(C7+D7+E7)'); + sheet.getRangeByName('F8').setFormula('=E8/(C8+D8+E8)'); + sheet.getRangeByName('F9').setFormula('=E9/(C9+D9+E9)'); + sheet.getRangeByName('F10').setFormula('=E10/(C10+D10+E10)'); + + sheet.getRangeByName('G1').setText('Planned %'); + sheet.getRangeByName('G2').setFormula('=D2/(C2+D2+E2)'); + sheet.getRangeByName('G3').setFormula('=D3/(C3+D3+E3)'); + sheet.getRangeByName('G4').setFormula('=D4/(C4+D4+E4)'); + sheet.getRangeByName('G5').setFormula('=D5/(C5+D5+E5)'); + sheet.getRangeByName('G6').setFormula('=D6/(C6+D6+E6)'); + sheet.getRangeByName('G7').setFormula('=D7/(C7+D7+E7)'); + sheet.getRangeByName('G8').setFormula('=D8/(C8+D8+E8)'); + sheet.getRangeByName('G9').setFormula('=D9/(C9+D9+E9)'); + sheet.getRangeByName('G10').setFormula('=D10/(C10+D10+E10)'); + + //Apply conditional Formatting. + ConditionalFormats statusCondition = + sheet.getRangeByName('H2:AL10').conditionalFormats; + + ConditionalFormat leaveCondition = statusCondition.addCondition(); + leaveCondition.formatType = ExcelCFType.cellValue; + leaveCondition.operator = ExcelComparisonOperator.equal; + leaveCondition.firstFormula = '\"L\"'; + leaveCondition.backColorRgb = Color.fromARGB(255, 253, 167, 92); + + ConditionalFormat absentCondition = statusCondition.addCondition(); + absentCondition.formatType = ExcelCFType.cellValue; + absentCondition.operator = ExcelComparisonOperator.equal; + absentCondition.firstFormula = '\"A\"'; + absentCondition.backColorRgb = Color.fromARGB(255, 255, 105, 124); + + ConditionalFormat presentCondition = statusCondition.addCondition(); + presentCondition.formatType = ExcelCFType.cellValue; + presentCondition.operator = ExcelComparisonOperator.equal; + presentCondition.firstFormula = '\"P\"'; + presentCondition.backColorRgb = Color.fromARGB(255, 67, 233, 123); + + ConditionalFormat weekendCondition = statusCondition.addCondition(); + weekendCondition.formatType = ExcelCFType.cellValue; + weekendCondition.operator = ExcelComparisonOperator.equal; + weekendCondition.firstFormula = '\"WE\"'; + weekendCondition.backColorRgb = Color.fromARGB(255, 240, 240, 240); + + final ConditionalFormats presentSummaryCF = + sheet.getRangeByName('C2:C10').conditionalFormats; + final ConditionalFormat presentCountCF = presentSummaryCF.addCondition(); + presentCountCF.formatType = ExcelCFType.dataBar; + DataBar dataBar = presentCountCF.dataBar!; + dataBar.barColorRgb = Color.fromARGB(255, 61, 242, 142); + + final ConditionalFormats leaveSummaryCF = + sheet.getRangeByName('D2:D10').conditionalFormats; + final ConditionalFormat leaveCountCF = leaveSummaryCF.addCondition(); + leaveCountCF.formatType = ExcelCFType.dataBar; + dataBar = leaveCountCF.dataBar!; + dataBar.barColorRgb = Color.fromARGB(255, 242, 71, 23); + + final ConditionalFormats absentSummaryCF = + sheet.getRangeByName('E2:E10').conditionalFormats; + final ConditionalFormat absentCountCF = absentSummaryCF.addCondition(); + absentCountCF.formatType = ExcelCFType.dataBar; + dataBar = absentCountCF.dataBar!; + dataBar.barColorRgb = Color.fromARGB(255, 255, 10, 69); + + final ConditionalFormats unplannedSummaryCF = + sheet.getRangeByName('F2:F10').conditionalFormats; + final ConditionalFormat unplannedCountCF = + unplannedSummaryCF.addCondition(); + unplannedCountCF.formatType = ExcelCFType.dataBar; + dataBar = unplannedCountCF.dataBar!; + dataBar.maxPoint.type = ConditionValueType.highestValue; + dataBar.barColorRgb = Color.fromARGB(255, 142, 142, 142); + + final ConditionalFormats plannedSummaryCF = + sheet.getRangeByName('G2:G10').conditionalFormats; + final ConditionalFormat plannedCountCF = plannedSummaryCF.addCondition(); + plannedCountCF.formatType = ExcelCFType.dataBar; + dataBar = plannedCountCF.dataBar!; + dataBar.maxPoint.type = ConditionValueType.highestValue; + dataBar.barColorRgb = Color.fromARGB(255, 56, 136, 254); + + statusCondition = sheet.getRangeByName('C12:C18').conditionalFormats; + leaveCondition = statusCondition.addCondition(); + leaveCondition.formatType = ExcelCFType.cellValue; + leaveCondition.operator = ExcelComparisonOperator.equal; + leaveCondition.firstFormula = '\"L\"'; + leaveCondition.backColorRgb = Color.fromARGB(255, 253, 167, 92); + + absentCondition = statusCondition.addCondition(); + absentCondition.formatType = ExcelCFType.cellValue; + absentCondition.operator = ExcelComparisonOperator.equal; + absentCondition.firstFormula = '\"A\"'; + absentCondition.backColorRgb = Color.fromARGB(255, 255, 105, 124); + + presentCondition = statusCondition.addCondition(); + presentCondition.formatType = ExcelCFType.cellValue; + presentCondition.operator = ExcelComparisonOperator.equal; + presentCondition.firstFormula = '\"P\"'; + presentCondition.backColorRgb = Color.fromARGB(255, 67, 233, 123); + + weekendCondition = statusCondition.addCondition(); + weekendCondition.formatType = ExcelCFType.cellValue; + weekendCondition.operator = ExcelComparisonOperator.equal; + weekendCondition.firstFormula = '\"WE\"'; + weekendCondition.backColorRgb = Color.fromARGB(255, 240, 240, 240); + + sheet.getRangeByIndex(12, 3).setText('P'); + sheet.getRangeByIndex(14, 3).setText('L'); + sheet.getRangeByIndex(16, 3).setText('A'); + sheet.getRangeByIndex(18, 3).setText('WE'); + sheet.getRangeByIndex(12, 4).setText('Present'); + sheet.getRangeByIndex(14, 4).setText('Leave'); + sheet.getRangeByIndex(16, 4).setText('Absent'); + sheet.getRangeByIndex(18, 4).setText('Weekend'); + + // Row height and column width. + sheet.getRangeByName('A1:AL1').rowHeight = 24; + sheet.getRangeByName('A2:AL10').rowHeight = 20; + sheet.getRangeByName('A1:B1').columnWidth = 20.37; + sheet.getRangeByName('C1:G1').columnWidth = 16.37; + sheet.getRangeByName('H1:AL10').columnWidth = 4.37; + sheet.getRangeByIndex(13, 1).rowHeight = 3.8; + sheet.getRangeByIndex(15, 1).rowHeight = 3.8; + sheet.getRangeByIndex(17, 1).rowHeight = 3.8; + + //Apply styles + final Style style = workbook.styles.add('Style'); + style.fontSize = 12; + style.fontColorRgb = Color.fromARGB(255, 64, 64, 64); + style.bold = true; + style.borders.all.lineStyle = LineStyle.medium; + style.borders.all.colorRgb = Color.fromARGB(255, 195, 195, 195); + style.vAlign = VAlignType.center; + style.hAlign = HAlignType.left; + + sheet.getRangeByName('A1:AL10').cellStyle = style; + + sheet.getRangeByName('A1:AL1').cellStyle.backColorRgb = + Color.fromARGB(255, 58, 56, 56); + sheet.getRangeByName('A1:AL1').cellStyle.fontColorRgb = + Color.fromARGB(255, 255, 255, 255); + + sheet.getRangeByName('C2:AL10').cellStyle.hAlign = HAlignType.center; + sheet.getRangeByName('H1:AL1').cellStyle.hAlign = HAlignType.center; + + sheet.getRangeByName('A2:B10').cellStyle.indent = 1; + sheet.getRangeByName('A1:G1').cellStyle.indent = 1; + + sheet.getRangeByName('H1:AL1').numberFormat = 'd'; + sheet.getRangeByName('H2:AL10').cellStyle.borders.all.colorRgb = + Color.fromARGB(255, 255, 255, 255); + + sheet.getRangeByName('F2:G10').numberFormat = '.00%'; + + sheet.getRangeByName('C12:C18').cellStyle = style; + sheet.getRangeByName('C12:C18').cellStyle.hAlign = HAlignType.center; + sheet.getRangeByName('C12:C18').cellStyle.borders.all.lineStyle = + LineStyle.none; + + final List? bytes = workbook.saveAsStream(); + workbook.dispose(); + + //Launch file. + await FileSaveHelper.saveAndLaunchFile(bytes!, 'AttendanceTracker.xlsx'); + } +} diff --git a/lib/samples/xlsio/balance_sheet/balance_sheet.dart b/lib/samples/xlsio/balance_sheet/balance_sheet.dart index 5d2e56d6..318ebe7e 100644 --- a/lib/samples/xlsio/balance_sheet/balance_sheet.dart +++ b/lib/samples/xlsio/balance_sheet/balance_sheet.dart @@ -13,9 +13,9 @@ import '../../../model/sample_view.dart'; import '../helper/save_file_mobile.dart' if (dart.library.html) '../helper/save_file_web.dart'; -/// Create balance sheet Excel report +/// Render XlsIO of balance sheet class BalanceSheetXlsIO extends SampleView { - /// Create balance sheet Excel report + /// Render XlsIO of balance sheet const BalanceSheetXlsIO(Key key) : super(key: key); @override _BalanceSheetXlsIOState createState() => _BalanceSheetXlsIOState(); @@ -36,16 +36,24 @@ class _BalanceSheetXlsIOState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'This sample showcases how to create a simple balance sheet in Excel with formulas, autofit rows and columns, image hyperlinks, and workbook/worksheet protection using XlsIO.', + 'This sample showcases on how to create a simple Excel report for balance sheet with data, autofit, image hyperlink, and protection using XlsIO.', style: TextStyle(fontSize: 16, color: model.textColor)), const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate Excel', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generateExcel)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generateExcel, + child: const Text('Generate Excel', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -126,7 +134,9 @@ class _BalanceSheetXlsIOState extends SampleViewState { sheet.getRangeByName('D14:E14').cellStyle = styles[9]; sheet.getRangeByName('B14').text = 'Balance'; - sheet.getRangeByName('D4:E14').autoFitColumns(); + sheet.getRangeByName('D1').columnWidth = 11.10; + sheet.getRangeByName('E1').columnWidth = 14.00; + // sheet.getRangeByName('D4:E14').autoFitColumns(); // Sheet2 sheet2.getRangeByName('A1').columnWidth = 1.69; @@ -192,9 +202,11 @@ class _BalanceSheetXlsIOState extends SampleViewState { sheet2.getRangeByName('E12').number = -46500; sheet2.getRangeByName('E13').number = 4000; - sheet2.getRangeByName('C3:C13').autoFitRows(); - sheet2.autoFitColumn(4); - sheet2.autoFitColumn(5); + sheet2.getRangeByName('D1').columnWidth = 11.10; + sheet2.getRangeByName('E1').columnWidth = 14.00; + // sheet2.getRangeByName('C3:C13').autoFitRows(); + // sheet2.autoFitColumn(4); + // sheet2.autoFitColumn(5); // sheet3 sheet3.getRangeByName('A1').columnWidth = 1.69; @@ -203,7 +215,8 @@ class _BalanceSheetXlsIOState extends SampleViewState { sheet3.getRangeByName('B1').text = 'Liabilities'; sheet3.getRangeByName('B1:E1').cellStyle = styles[0]; - sheet3.autoFitColumn(2); + sheet3.getRangeByName('B1').columnWidth = 22.10; + // sheet3.autoFitColumn(2); range1 = sheet3.getRangeByName('D2'); range1.cellStyle = styles[5]; @@ -256,9 +269,11 @@ class _BalanceSheetXlsIOState extends SampleViewState { sheet3.getRangeByName('E11').number = 12500; sheet3.getRangeByName('E12').number = 20700; - sheet3.getRangeByName('C3:C12').autoFitRows(); - sheet3.autoFitColumn(4); - sheet3.autoFitColumn(5); + sheet3.getRangeByName('D1').columnWidth = 11.10; + sheet3.getRangeByName('E1').columnWidth = 14.00; + // sheet3.getRangeByName('C3:C12').autoFitRows(); + // sheet3.autoFitColumn(4); + // sheet3.autoFitColumn(5); // sheet4 sheet4.getRangeByName('A1').columnWidth = 1.69; @@ -333,11 +348,11 @@ class _BalanceSheetXlsIOState extends SampleViewState { workbook.protect(true, true, 'Syncfusion'); - final List bytes = workbook.saveAsStream(); + final List? bytes = workbook.saveAsStream(); workbook.dispose(); //Launch file. - await FileSaveHelper.saveAndLaunchFile(bytes, 'BalanceSheet.xlsx'); + await FileSaveHelper.saveAndLaunchFile(bytes!, 'BalanceSheet.xlsx'); } // Create styles for worksheet diff --git a/lib/samples/xlsio/expenses_report/expenses_report.dart b/lib/samples/xlsio/expenses_report/expenses_report.dart index c8a721de..846bc312 100644 --- a/lib/samples/xlsio/expenses_report/expenses_report.dart +++ b/lib/samples/xlsio/expenses_report/expenses_report.dart @@ -10,9 +10,9 @@ import '../../../model/sample_view.dart'; import '../helper/save_file_mobile.dart' if (dart.library.html) '../helper/save_file_web.dart'; -/// Create expenses report Excel report +/// Render xlsio of expenses report class ExpensesReportXlsIO extends SampleView { - /// Create expenses report Excel report + /// Render xlsio of expenses report const ExpensesReportXlsIO(Key key) : super(key: key); @override _ExpensesReportXlsIOState createState() => _ExpensesReportXlsIOState(); @@ -33,16 +33,24 @@ class _ExpensesReportXlsIOState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'The XlsIO package is a non-UI and reusable Flutter library to create Excel reports programmatically with formatted text, numbers, date time, number formats, cell styles, images, charts, and more.\r\n\r\nThis sample showcases how to create a simple Excel report for expenses with data, charts, formulas, and cell formatting using XlsIO.', + 'The XlsIO package is a non-UI and reusable flutter library to create Excel reports programmatically with formatted text, numbers, datetime, number formats, cell styles, images, charts and more.\r\n\r\nThis sample showcases on how to create a simple Excel report for expenses with data, chart, formulas, and cell formatting using XlsIO.', style: TextStyle(fontSize: 16, color: model.textColor)), const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate Excel', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generateExcel)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generateExcel, + child: const Text('Generate Excel', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -68,13 +76,13 @@ class _ExpensesReportXlsIOState extends SampleViewState { sheet1.getRangeByName('A1:A18').rowHeight = 20.2; //Adding cell style. - final CellStyle style1 = workbook.styles.add('Style1'); + final Style style1 = workbook.styles.add('Style1'); style1.backColor = '#D9E1F2'; style1.hAlign = HAlignType.left; style1.vAlign = VAlignType.center; style1.bold = true; - final CellStyle style2 = workbook.styles.add('Style2'); + final Style style2 = workbook.styles.add('Style2'); style2.backColor = '#8EA9DB'; style2.vAlign = VAlignType.center; style2.numberFormat = '[Red](\$#,###)'; @@ -157,10 +165,10 @@ class _ExpensesReportXlsIOState extends SampleViewState { chart.rightColumn = 5; sheet1.charts = charts; - final List bytes = workbook.saveAsStream(); + final List? bytes = workbook.saveAsStream(); workbook.dispose(); //Launch file. - await FileSaveHelper.saveAndLaunchFile(bytes, 'ExpensesReport.xlsx'); + await FileSaveHelper.saveAndLaunchFile(bytes!, 'ExpensesReport.xlsx'); } } diff --git a/lib/samples/xlsio/helper/save_file_mobile.dart b/lib/samples/xlsio/helper/save_file_mobile.dart index ac7a5941..e482728c 100644 --- a/lib/samples/xlsio/helper/save_file_mobile.dart +++ b/lib/samples/xlsio/helper/save_file_mobile.dart @@ -4,6 +4,7 @@ import 'dart:io'; ///Package imports import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; ///To save the Excel file in the device class FileSaveHelper { @@ -12,19 +13,36 @@ class FileSaveHelper { ///To save the Excel file in the device static Future saveAndLaunchFile( List bytes, String fileName) async { - final Directory directory = await getApplicationDocumentsDirectory(); - final String path = directory.path; - final File file = File('$path/$fileName'); + String? path; + if (Platform.isAndroid || + Platform.isIOS || + Platform.isLinux || + Platform.isWindows) { + final Directory directory = await getApplicationSupportDirectory(); + path = directory.path; + } else { + path = await PathProviderPlatform.instance.getApplicationSupportPath(); + } + final File file = + File(Platform.isWindows ? '$path\\$fileName' : '$path/$fileName'); await file.writeAsBytes(bytes, flush: true); - final Map argument = { - 'file_path': '$path/$fileName' - }; - try { - //ignore: unused_local_variable - final Future> result = - _platformCall.invokeMethod('viewExcel', argument); - } catch (e) { - throw Exception(e); + if (Platform.isAndroid || Platform.isIOS) { + final Map argument = { + 'file_path': '$path/$fileName' + }; + try { + //ignore: unused_local_variable + final Future?> result = + _platformCall.invokeMethod('viewExcel', argument); + } catch (e) { + throw Exception(e); + } + } else if (Platform.isWindows) { + await Process.run('start', ['$path\\$fileName'], runInShell: true); + } else if (Platform.isMacOS) { + await Process.run('open', ['$path/$fileName'], runInShell: true); + } else if (Platform.isLinux) { + await Process.run('xdg-open', ['$path/$fileName'], runInShell: true); } } } diff --git a/lib/samples/xlsio/helper/save_file_web.dart b/lib/samples/xlsio/helper/save_file_web.dart index b368ad8a..9c804223 100644 --- a/lib/samples/xlsio/helper/save_file_web.dart +++ b/lib/samples/xlsio/helper/save_file_web.dart @@ -1,18 +1,18 @@ ///Dart imports import 'dart:async'; import 'dart:convert'; -//ignore: avoid_web_libraries_in_flutter -import 'dart:js' as js; +// ignore: avoid_web_libraries_in_flutter +import 'dart:html'; ///To save the Excel file in the device class FileSaveHelper { ///To save the Excel file in the device static Future saveAndLaunchFile( List bytes, String fileName) async { - js.context['exceldata'] = base64.encode(bytes); - js.context['filename'] = fileName; - Timer.run(() { - js.context.callMethod('downloadExcel'); - }); + AnchorElement( + href: + 'data:application/octet-stream;charset=utf-16le;base64,${base64.encode(bytes)}') + ..setAttribute('download', fileName) + ..click(); } } diff --git a/lib/samples/xlsio/invoice/invoice.dart b/lib/samples/xlsio/invoice/invoice.dart index f22cbb08..2e41a2d6 100644 --- a/lib/samples/xlsio/invoice/invoice.dart +++ b/lib/samples/xlsio/invoice/invoice.dart @@ -13,9 +13,9 @@ import '../../../model/sample_view.dart'; import '../helper/save_file_mobile.dart' if (dart.library.html) '../helper/save_file_web.dart'; -/// Create invoice Excel report +/// Render XlsIO of invoice class InvoiceXlsIO extends SampleView { - /// Create invoice Excel report + /// Render XlsIO of invoice const InvoiceXlsIO(Key key) : super(key: key); @override _InvoiceXlsIOState createState() => _InvoiceXlsIOState(); @@ -36,16 +36,24 @@ class _InvoiceXlsIOState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'This sample showcases how to create a simple Excel invoice with data, images, formulas, and cell formatting using XlsIO.', + 'This sample showcases on how to create a simple Excel invoice with data, image, formulas, and cell formatting using XlsIO.', style: TextStyle(fontSize: 16, color: model.textColor)), const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate Excel', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generateExcel)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generateExcel, + child: const Text('Generate Excel', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -80,7 +88,7 @@ class _InvoiceXlsIOState extends SampleViewState { sheet.getRangeByName('B4').cellStyle.bold = true; sheet.getRangeByName('B4').cellStyle.fontSize = 32; - final CellStyle style1 = workbook.styles.add('style1'); + final Style style1 = workbook.styles.add('style1'); style1.borders.bottom.lineStyle = LineStyle.medium; style1.borders.bottom.color = '#AEAAAA'; @@ -221,16 +229,16 @@ class _InvoiceXlsIOState extends SampleViewState { range9.cellStyle.hAlign = HAlignType.center; range9.cellStyle.vAlign = VAlignType.center; - Picture picture = + final Picture picture = sheet.pictures.addStream(3, 4, await _readImageData('invoice.jpeg')); picture.lastRow = 7; picture.lastColumn = 8; - final List bytes = workbook.saveAsStream(); + final List? bytes = workbook.saveAsStream(); workbook.dispose(); //Launch file. - await FileSaveHelper.saveAndLaunchFile(bytes, 'Invoice.xlsx'); + await FileSaveHelper.saveAndLaunchFile(bytes!, 'Invoice.xlsx'); } Future> _readImageData(String name) async { diff --git a/lib/samples/xlsio/yearly_sales/yearly_sales.dart b/lib/samples/xlsio/yearly_sales/yearly_sales.dart index edcf81f8..1cd6dc6e 100644 --- a/lib/samples/xlsio/yearly_sales/yearly_sales.dart +++ b/lib/samples/xlsio/yearly_sales/yearly_sales.dart @@ -10,9 +10,9 @@ import '../../../model/sample_view.dart'; import '../helper/save_file_mobile.dart' if (dart.library.html) '../helper/save_file_web.dart'; -/// Create yearly sales Excel report +/// Render XlsIO of yearly sales class YearlySalesXlsIO extends SampleView { - /// Create yearly sales Excel report + /// Render XlsIO of yearly sales const YearlySalesXlsIO(Key key) : super(key: key); @override _YearlySalesXlsIOState createState() => _YearlySalesXlsIOState(); @@ -33,16 +33,24 @@ class _YearlySalesXlsIOState extends SampleViewState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'This sample showcases how to create a simple Excel report for yearly sales with data, charts, formulas, and cell formatting using XlsIO.', + 'This sample showcases on how to create a simple Excel report for yearly sales with data, chart, formulas, and cell formatting using XlsIO.', style: TextStyle(fontSize: 16, color: model.textColor)), const SizedBox(height: 20, width: 30), Align( alignment: Alignment.center, - child: FlatButton( - child: const Text('Generate Excel', - style: TextStyle(color: Colors.white)), - color: model.backgroundColor, - onPressed: _generateExcel)) + child: TextButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + model.backgroundColor), + padding: model.isMobile + ? null + : MaterialStateProperty.all(EdgeInsets.symmetric( + vertical: 15, horizontal: 15)), + ), + onPressed: _generateExcel, + child: const Text('Generate Excel', + style: TextStyle(color: Colors.white)), + )) ], ), ), @@ -233,7 +241,7 @@ class _YearlySalesXlsIOState extends SampleViewState { chart1.isSeriesInRows = false; chart1.chartTitleArea.bold = true; chart1.chartTitleArea.size = 12; - chart1.legend.position = ExcelLegendPosition.bottom; + chart1.legend!.position = ExcelLegendPosition.bottom; chart1.primaryValueAxis.numberFormat = '\$#,###'; chart1.primaryValueAxis.hasMajorGridLines = false; chart1.topRow = 2; @@ -249,9 +257,9 @@ class _YearlySalesXlsIOState extends SampleViewState { chart2.chartTitleArea.size = 11; chart2.chartTitleArea.color = '#595959'; chart2.chartTitleArea.text = 'Internet Sales vs Reseller Sales'; - chart2.legend.position = ExcelLegendPosition.bottom; - chart2.legend.textArea.size = 9; - chart2.legend.textArea.color = '#595959'; + chart2.legend!.position = ExcelLegendPosition.bottom; + chart2.legend!.textArea.size = 9; + chart2.legend!.textArea.color = '#595959'; chart2.topRow = 20; chart2.bottomRow = 32; chart2.leftColumn = 1; @@ -265,16 +273,16 @@ class _YearlySalesXlsIOState extends SampleViewState { sheet.charts = charts; - final List bytes = workbook.saveAsStream(); + final List? bytes = workbook.saveAsStream(); workbook.dispose(); //Launch file. - await FileSaveHelper.saveAndLaunchFile(bytes, 'YearlySale.xlsx'); + await FileSaveHelper.saveAndLaunchFile(bytes!, 'YearlySale.xlsx'); } // Create styles for worksheet List createStyles(Workbook workbook) { - final CellStyle style1 = workbook.styles.add('style1'); + final Style style1 = workbook.styles.add('style1'); style1.backColor = '#9BC2E6'; style1.fontSize = 18; style1.bold = true; @@ -288,7 +296,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style1.borders.left.lineStyle = LineStyle.thin; style1.borders.left.color = '#757171'; - final CellStyle style2 = workbook.styles.add('style2'); + final Style style2 = workbook.styles.add('style2'); style2.backColor = '#F4B084'; style2.fontSize = 18; style2.bold = true; @@ -302,7 +310,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style2.borders.left.lineStyle = LineStyle.thin; style2.borders.left.color = '#757171'; - final CellStyle style3 = workbook.styles.add('style3'); + final Style style3 = workbook.styles.add('style3'); style3.backColor = '#FFD966'; style3.fontSize = 18; style3.bold = true; @@ -316,7 +324,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style3.borders.left.lineStyle = LineStyle.thin; style3.borders.left.color = '#757171'; - final CellStyle style4 = workbook.styles.add('style4'); + final Style style4 = workbook.styles.add('style4'); style4.backColor = '#A9D08E'; style4.fontSize = 18; style4.bold = true; @@ -330,7 +338,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style4.borders.left.lineStyle = LineStyle.thin; style4.borders.left.color = '#757171'; - final CellStyle style5 = workbook.styles.add('style5'); + final Style style5 = workbook.styles.add('style5'); style5.backColor = '#9BC2E6'; style5.fontColor = '#757171'; style5.hAlign = HAlignType.center; @@ -342,7 +350,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style5.borders.left.lineStyle = LineStyle.thin; style5.borders.left.color = '#757171'; - final CellStyle style6 = workbook.styles.add('style6'); + final Style style6 = workbook.styles.add('style6'); style6.backColor = '#F4B084'; style6.fontColor = '#757171'; style6.hAlign = HAlignType.center; @@ -354,7 +362,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style6.borders.left.lineStyle = LineStyle.thin; style6.borders.left.color = '#757171'; - final CellStyle style7 = workbook.styles.add('style7'); + final Style style7 = workbook.styles.add('style7'); style7.backColor = '#FFD966'; style7.fontColor = '#757171'; style7.hAlign = HAlignType.center; @@ -366,7 +374,7 @@ class _YearlySalesXlsIOState extends SampleViewState { style7.borders.left.lineStyle = LineStyle.thin; style7.borders.left.color = '#757171'; - final CellStyle style8 = workbook.styles.add('style8'); + final Style style8 = workbook.styles.add('style8'); style8.backColor = '#A9D08E'; style8.fontColor = '#757171'; style8.hAlign = HAlignType.center; diff --git a/lib/widgets/animate_opacity_widget.dart b/lib/widgets/animate_opacity_widget.dart index 589e9931..c518b6f1 100644 --- a/lib/widgets/animate_opacity_widget.dart +++ b/lib/widgets/animate_opacity_widget.dart @@ -4,36 +4,35 @@ import 'package:flutter/material.dart'; /// Creates a widget that makes its child partially transparent. class AnimateOpacityWidget extends StatefulWidget { /// Holds custom opacity widget information - const AnimateOpacityWidget( - {@required this.opacity, @required this.child, this.controller}) + const AnimateOpacityWidget({this.opacity, this.child, this.controller}) : assert(opacity != null), assert(child != null); /// The fraction to scale the child's alpha value. - final double opacity; + final double? opacity; /// Creates a widget that makes its child partially transparent. - final Widget child; + final Widget? child; ///[controller] Controls a scrollable widget. - final ScrollController controller; + final ScrollController? controller; @override _AnimateOpacityWidgetState createState() => _AnimateOpacityWidgetState(); } class _AnimateOpacityWidgetState extends State { - double _opacity; + late double? _opacity; @override void initState() { _opacity = widget.opacity; - widget.controller.addListener(_onScroll); + widget.controller!.addListener(_onScroll); super.initState(); } void _onScroll() { - final num opacity = widget.controller.offset * 0.01; + final double opacity = widget.controller!.offset * 0.01; if (opacity >= 0 && opacity <= 1) { setState(() { _opacity = opacity; @@ -44,13 +43,13 @@ class _AnimateOpacityWidgetState extends State { @override Widget build(BuildContext context) { return Container( - child: Opacity(opacity: _opacity, child: widget.child), + child: Opacity(opacity: _opacity!, child: widget.child), ); } @override void dispose() { super.dispose(); - widget.controller.removeListener(_onScroll); + widget.controller!.removeListener(_onScroll); } } diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 5ce6bfb3..42d80011 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -5,9 +5,9 @@ import 'package:flutter/material.dart'; import '../model/model.dart'; /// To show the setting panel content on the bottom sheet -Future showRoundedModalBottomSheet({ - @required BuildContext context, - @required WidgetBuilder builder, +Future showRoundedModalBottomSheet({ + required BuildContext context, + required WidgetBuilder builder, Color color = Colors.white, bool dismissOnTap = false, }) { @@ -35,10 +35,7 @@ const double _kCloseProgressThreshold = 0.5; class CustomBottomSheet extends StatefulWidget { /// holds the informtion of customized bottom sheet const CustomBottomSheet( - {Key key, - this.animationController, - @required this.onClosing, - @required this.builder}) + {Key? key, this.animationController, this.onClosing, this.builder}) : assert(onClosing != null), assert(builder != null), super(key: key); @@ -47,20 +44,20 @@ class CustomBottomSheet extends StatefulWidget { /// /// The BottomSheet widget will manipulate the position of this animation, it /// is not just a passive observer. - final AnimationController animationController; + final AnimationController? animationController; /// Called when the bottom sheet begins to close. /// /// A bottom sheet might be be prevented from closing (e.g., by user /// interaction) even after this callback is called. For this reason, this /// callback might be call multiple times for a given bottom sheet. - final VoidCallback onClosing; + final VoidCallback? onClosing; /// A builder for the contents of the sheet. /// /// The bottom sheet will wrap the widget produced by this builder in a /// [Material] widget. - final WidgetBuilder builder; + final WidgetBuilder? builder; @override _CustomBottomSheetState createState() => _CustomBottomSheetState(); @@ -79,20 +76,21 @@ class CustomBottomSheet extends StatefulWidget { class _CustomBottomSheetState extends State { final GlobalKey _childKey = GlobalKey(debugLabel: 'RoundedBottomSheet child'); - double get _childHeight { - final RenderBox renderBox = _childKey.currentContext.findRenderObject(); + double? get _childHeight { + final RenderBox renderBox = + _childKey.currentContext!.findRenderObject() as RenderBox; return renderBox.size.height; } bool get _dismissUnderway => - widget.animationController.status == AnimationStatus.reverse; + widget.animationController!.status == AnimationStatus.reverse; void _handleDragUpdate(DragUpdateDetails details) { if (_dismissUnderway) { return; } - widget.animationController.value -= - details.primaryDelta / (_childHeight ?? details.primaryDelta); + widget.animationController!.value -= + details.primaryDelta! / (_childHeight ?? details.primaryDelta!); } void _handleDragEnd(DragEndDetails details) { @@ -101,20 +99,20 @@ class _CustomBottomSheetState extends State { } if (details.velocity.pixelsPerSecond.dy > _kMinFlingVelocity) { final double flingVelocity = - -details.velocity.pixelsPerSecond.dy / _childHeight; - if (widget.animationController.value > 0.0) { - widget.animationController.fling(velocity: flingVelocity); + -details.velocity.pixelsPerSecond.dy / _childHeight!; + if (widget.animationController!.value > 0.0) { + widget.animationController!.fling(velocity: flingVelocity); } if (flingVelocity < 0.0) { - widget.onClosing(); + widget.onClosing!(); } - } else if (widget.animationController.value < _kCloseProgressThreshold) { - if (widget.animationController.value > 0.0) { - widget.animationController.fling(velocity: -1.0); + } else if (widget.animationController!.value < _kCloseProgressThreshold) { + if (widget.animationController!.value > 0.0) { + widget.animationController!.fling(velocity: -1.0); } - widget.onClosing(); + widget.onClosing!(); } else { - widget.animationController.forward(); + widget.animationController!.forward(); } } @@ -125,7 +123,7 @@ class _CustomBottomSheetState extends State { onVerticalDragEnd: _handleDragEnd, child: Material( key: _childKey, - child: widget.builder(context), + child: widget.builder!(context), ), ); } @@ -165,13 +163,13 @@ class _RoundedCornerModalRoute extends PopupRoute { this.color, this.autoResize = false, this.dismissOnTap = true, - RouteSettings settings, + RouteSettings? settings, }) : super(settings: settings); - final WidgetBuilder builder; - final Color color; - final bool autoResize; - final bool dismissOnTap; + final WidgetBuilder? builder; + final Color? color; + final bool? autoResize; + final bool? dismissOnTap; @override Duration get transitionDuration => _kRoundedBottomSheetDuration; @@ -189,16 +187,16 @@ class _RoundedCornerModalRoute extends PopupRoute { bool get maintainState => false; @override - String barrierLabel; + String? barrierLabel; - AnimationController animationController; + AnimationController? animationController; @override AnimationController createAnimationController() { assert(animationController == null); animationController = - BottomSheet.createAnimationController(navigator.overlay); - return animationController; + BottomSheet.createAnimationController(navigator!.overlay!); + return animationController!; } @override @@ -217,9 +215,9 @@ class _RoundedCornerModalRoute extends PopupRoute { } class _RoundedModalBottomSheet extends StatefulWidget { - const _RoundedModalBottomSheet({Key key, this.route}) : super(key: key); + const _RoundedModalBottomSheet({Key? key, this.route}) : super(key: key); - final _RoundedCornerModalRoute route; + final _RoundedCornerModalRoute? route; @override _RoundedModalBottomSheetState createState() => @@ -255,27 +253,27 @@ class _RoundedModalBottomSheetState Widget build(BuildContext context) { return GestureDetector( child: AnimatedBuilder( - animation: widget.route.animation, - builder: (BuildContext context, Widget child) => + animation: widget.route!.animation!, + builder: (BuildContext context, Widget? child) => CustomSingleChildLayout( delegate: _RoundedModalBottomSheetLayout( - widget.route.autoResize + widget.route!.autoResize! ? MediaQuery.of(context).viewInsets.bottom : 0.0, - widget.route.animation.value), + widget.route!.animation!.value), child: CustomBottomSheet( - animationController: widget.route.animationController, + animationController: widget.route!.animationController, onClosing: () => Navigator.pop(context), builder: (BuildContext context) => Container( decoration: BoxDecoration( - color: widget.route.color, + color: widget.route!.color, borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), ), ), child: SafeArea( - child: Builder(builder: widget.route.builder), + child: Builder(builder: widget.route!.builder!), ), ), ), diff --git a/lib/widgets/custom_button.dart b/lib/widgets/custom_button.dart index 0a148ed9..32d62767 100644 --- a/lib/widgets/custom_button.dart +++ b/lib/widgets/custom_button.dart @@ -5,11 +5,11 @@ import 'package:flutter/material.dart'; class CustomDirectionalButtons extends StatefulWidget { /// direction arrows surronding in text widget const CustomDirectionalButtons({ - Key key, + Key? key, this.minValue = 0, - @required this.maxValue, - @required this.initialValue, - @required this.onChanged, + this.maxValue, + this.initialValue, + this.onChanged, this.step = 1, this.loop = false, this.horizontal = true, @@ -23,43 +23,43 @@ class CustomDirectionalButtons extends StatefulWidget { assert(step != null), assert(loop != null), assert(padding != null), - assert(iconColor != null), - assert(initialValue >= minValue && initialValue <= maxValue), - assert(minValue < maxValue); + assert(iconColor != null); + // assert(initialValue >= minValue && initialValue <= maxValue), + // assert(minValue < maxValue); /// minimal value - final double minValue; + final double? minValue; /// max value - final double maxValue; + final double? maxValue; /// Initially displayed value in the [CustomDirectionalButtons] - final double initialValue; + final double? initialValue; /// The callback that is called when the button is tapped /// or otherwise activated. /// /// If this is set to null, the button will be disabled. - final ValueChanged onChanged; + final ValueChanged? onChanged; /// interval value - final double step; + final double? step; /// set left,right icons only - final bool horizontal; + final bool? horizontal; /// set after the max value reach, start again from min value - final bool loop; + final bool? loop; /// Holds the text widget style - final TextStyle style; + final TextStyle? style; /// The padding around the button's icon. /// The entire padded icon will react to input gestures. - final double padding; + final double? padding; /// Color of the icon button - final Color iconColor; + final Color? iconColor; @override State createState() => _CustomButton(); @@ -75,48 +75,50 @@ enum _CountDirection { } class _CustomButton extends State { - double _counter; + late double _counter; @override void initState() { super.initState(); - _counter = widget.initialValue; + _counter = widget.initialValue!; } /// Calculate next value for the CustomDirectionalButtons void _count(_CountDirection countDirection) { if (countDirection == _CountDirection.Up) { /// Make sure you can't go over `maxValue` unless `loop == true` - if (_counter + widget.step > widget.maxValue) { - if (widget.loop) { + if (_counter + widget.step! > widget.maxValue!) { + if (widget.loop!) { setState(() { /// Calculate the correct value if you go over maxValue in a loop - final num diff = (_counter + widget.step) - widget.maxValue; - _counter = diff >= 1 ? widget.minValue + diff - 1 : widget.minValue; + final num diff = (_counter + widget.step!) - widget.maxValue!; + _counter = + (diff >= 1 ? widget.minValue! + diff - 1 : widget.minValue)!; }); } } else { - setState(() => _counter += widget.step); + setState(() => _counter += widget.step!); } } else { - if (_counter - widget.step < widget.minValue) { - if (widget.loop) { + if (_counter - widget.step! < widget.minValue!) { + if (widget.loop!) { setState(() { - final num diff = widget.minValue - (_counter - widget.step); - _counter = diff >= 1 ? widget.maxValue - diff + 1 : widget.maxValue; + final num diff = widget.minValue! - (_counter - widget.step!); + _counter = + (diff >= 1 ? widget.maxValue! - diff + 1 : widget.maxValue)!; }); } } else { - setState(() => _counter -= widget.step); + setState(() => _counter -= widget.step!); } } - widget.onChanged(_counter); + widget.onChanged!(_counter); } Widget _getCount() { return Text( - widget.initialValue % 1 == 0 && widget.step % 1 == 0 + widget.initialValue! % 1 == 0 && widget.step! % 1 == 0 ? _counter.toStringAsFixed(0) : _counter.toStringAsFixed(1), style: widget.style ?? Theme.of(context).textTheme.headline5); @@ -124,13 +126,13 @@ class _CustomButton extends State { /// Return different widgets for a horizontal and vertical BuildPicker Widget _buildCustomButton() { - return (!widget.horizontal) + return (!widget.horizontal!) ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: Icon(Icons.arrow_drop_up), - padding: EdgeInsets.only(bottom: widget.padding), + padding: EdgeInsets.only(bottom: widget.padding!), alignment: Alignment.bottomCenter, color: widget.iconColor, splashColor: Colors.transparent, @@ -142,7 +144,7 @@ class _CustomButton extends State { _getCount(), IconButton( icon: Icon(Icons.arrow_drop_down), - padding: EdgeInsets.only(top: widget.padding), + padding: EdgeInsets.only(top: widget.padding!), alignment: Alignment.topCenter, color: widget.iconColor, splashColor: Colors.transparent, @@ -153,11 +155,11 @@ class _CustomButton extends State { ], ) : Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( icon: Icon(Icons.arrow_left), - padding: EdgeInsets.only(right: widget.padding), + padding: EdgeInsets.only(right: widget.padding!), alignment: Alignment.center, color: widget.iconColor, splashColor: Colors.transparent, @@ -168,7 +170,7 @@ class _CustomButton extends State { _getCount(), IconButton( icon: Icon(Icons.arrow_right), - padding: EdgeInsets.only(left: widget.padding), + padding: EdgeInsets.only(left: widget.padding!), alignment: Alignment.center, color: widget.iconColor, splashColor: Colors.transparent, diff --git a/lib/widgets/expansion_tile.dart b/lib/widgets/expansion_tile.dart index 74a6b94b..22410f67 100644 --- a/lib/widgets/expansion_tile.dart +++ b/lib/widgets/expansion_tile.dart @@ -7,9 +7,9 @@ const Duration _kExpand = Duration(milliseconds: 200); class CustomExpansionTile extends StatefulWidget { /// holds the title, children, et., of the expansionTile const CustomExpansionTile({ - Key key, + Key? key, this.headerBackgroundColor, - @required this.title, + this.title, this.backgroundColor, this.onExpansionChanged, this.children = const [], @@ -21,22 +21,22 @@ class CustomExpansionTile extends StatefulWidget { super(key: key); /// Holds the header name of expansion tile - final Widget title; + final Widget? title; /// Holds information of expand or collapse change - final ValueChanged onExpansionChanged; + final ValueChanged? onExpansionChanged; /// Children widget of the [CustomExpansionTile] - final List children; + final List? children; /// [CustomExpansionTile]s background color - final Color backgroundColor; + final Color? backgroundColor; /// Holds the [CustomExpansionTile] title's background color - final Color headerBackgroundColor; + final Color? headerBackgroundColor; /// Holds the information of initially expand/collapse - final bool initiallyExpanded; + final bool? initiallyExpanded; @override _ExpansionTileState createState() => _ExpansionTileState(); @@ -52,17 +52,17 @@ class _ExpansionTileState extends State Tween(begin: 0.0, end: 0.5); final ColorTween _borderColorTween = ColorTween(); - final ColorTween _headerColorTween = ColorTween(); - final ColorTween _iconColorTween = ColorTween(); + final ColorTween? _headerColorTween = ColorTween(); + final ColorTween? _iconColorTween = ColorTween(); final ColorTween _backgroundColorTween = ColorTween(); - AnimationController _controller; - Animation _iconTurns; - Animation _heightFactor; - Animation _borderColor; - Animation _headerColor; - Animation _iconColor; - Animation _backgroundColor; + late AnimationController _controller; + late Animation _iconTurns; + late Animation _heightFactor; + late Animation _borderColor; + late Animation _headerColor; + late Animation _iconColor; + late Animation _backgroundColor; bool _isExpanded = false; @@ -73,8 +73,8 @@ class _ExpansionTileState extends State _heightFactor = _controller.drive(_easeInTween); _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); _borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween)); - _headerColor = _controller.drive(_headerColorTween.chain(_easeInTween)); - _iconColor = _controller.drive(_iconColorTween.chain(_easeInTween)); + _headerColor = _controller.drive(_headerColorTween!.chain(_easeInTween)); + _iconColor = _controller.drive(_iconColorTween!.chain(_easeInTween)); _backgroundColor = _controller.drive(_backgroundColorTween.chain(_easeOutTween)); @@ -109,13 +109,13 @@ class _ExpansionTileState extends State PageStorage.of(context)?.writeState(context, _isExpanded); }); if (widget.onExpansionChanged != null) { - widget.onExpansionChanged(_isExpanded); + widget.onExpansionChanged!(_isExpanded); } } - Widget _buildChildren(BuildContext context, Widget child) { + Widget _buildChildren(BuildContext context, Widget? child) { final Color borderSideColor = _borderColor.value ?? Colors.transparent; - final Color titleColor = _headerColor.value; + final Color titleColor = _headerColor.value!; return Container( decoration: BoxDecoration( @@ -140,9 +140,9 @@ class _ExpansionTileState extends State child: DefaultTextStyle( style: Theme.of(context) .textTheme - .subtitle1 + .subtitle1! .copyWith(color: titleColor), - child: widget.title, + child: widget.title!, ), ), trailing: Padding( @@ -172,14 +172,14 @@ class _ExpansionTileState extends State @override void didChangeDependencies() { final ThemeData theme = Theme.of(context); - _borderColorTween..end = Colors.transparent; - _headerColorTween - ..begin = theme.textTheme.subtitle1.color + _borderColorTween.end = Colors.transparent; + _headerColorTween! + ..begin = theme.textTheme.subtitle1!.color ..end = theme.accentColor; - _iconColorTween + _iconColorTween! ..begin = theme.unselectedWidgetColor ..end = theme.accentColor; - _backgroundColorTween..end = widget.backgroundColor; + _backgroundColorTween.end = widget.backgroundColor; super.didChangeDependencies(); } @@ -189,7 +189,7 @@ class _ExpansionTileState extends State return AnimatedBuilder( animation: _controller.view, builder: _buildChildren, - child: closed ? null : Column(children: widget.children), + child: closed ? null : Column(children: widget.children!), ); } } diff --git a/lib/widgets/flutter_backdrop.dart b/lib/widgets/flutter_backdrop.dart deleted file mode 100644 index 82dad949..00000000 --- a/lib/widgets/flutter_backdrop.dart +++ /dev/null @@ -1,426 +0,0 @@ -///Dart import -import 'dart:math' as math; - -///Package import -import 'package:flutter/material.dart'; - -///Local import -import '../model/model.dart'; - -///Backdrop widget holds the appbar, front panel, etc., widgets -class Backdrop extends StatefulWidget { - /// Holds information of the appbar, front panel, etc., - Backdrop({ - this.sampleListModel, - @required this.frontLayer, - @required this.backLayer, - this.toggleFrontLayer = true, - this.color, - - //--------Appbar properties------------ - this.appBarTitle, - this.appBarActions, - this.panelVisible, - }) : assert(frontLayer != null), - assert(backLayer != null); - - //----------------------Front and Back Panel properties----------------------- - - /// This is the front panel which will contain the main body. - final Widget frontLayer; - - /// This is the back panel where you can put menu Items. - final Widget backLayer; - - /// If true it will toggle the position of your [frontLayer]. - /// - /// Initially keep it false. - /// Then make it true on Selecting any Menu item in [backLayer]. - final bool toggleFrontLayer; - - /// The primary widget displayed in the appbar. - /// - /// Typically a [Text] widget containing a description of the current contents - /// of the app. - final Widget appBarTitle; - - /// Color of the [Backdrop] - final Color color; - - /// Widgets to display after the [appBarTitle] widget. - /// - /// Typically these widgets are [IconButton]s representing common operations. - /// For less common operations, consider using a [PopupMenuButton] as the - /// last action. - /// - /// {@tool snippet --template=stateless_widget} - /// - /// This sample shows adding an action to the appBar of your [Backdrop] - /// that opens a shopping cart. - /// - /// ```dart - /// Backdrop( - /// appBarActions: [ - /// IconButton( - /// icon: Icon(Icons.shopping_cart), - /// tooltip: 'Open shopping cart', - /// onPressed: () { - /// // ... - /// }, - /// ), - /// ], - /// ), - /// ``` - /// {@end-tool} - final List appBarActions; - - /// Holds the SampleModel - final SampleModel sampleListModel; - - /// Contains the front panel visibility - final ValueNotifier panelVisible; - - @override - BackdropState createState() => BackdropState(sampleListModel); -} - -/// Holds the appbar and front panel information -class BackdropState extends State - with SingleTickerProviderStateMixin { - /// holds bropdrop state - BackdropState(SampleModel _sampleListModel, {this.test = false}) { - // ignore: prefer_initializing_formals - sampleListModel = _sampleListModel; - } - - final num _flingVelocity = 2.0; - - /// Holds height of the front panel - static double frontPanelHeight = 0; - - /// Sets front panel visibility - bool panelVisible; - final GlobalKey _backDropKey = GlobalKey(debugLabel: 'Backdrop'); - - ///Holds the dummy test - bool test; - AnimationController _controller; - final GlobalKey _scaffoldKey = - GlobalKey(debugLabel: 'Scaffold'); - - ///Holds sample browser details - SampleModel sampleListModel; - - @override - void initState() { - super.initState(); - panelVisible = widget.panelVisible?.value; - _controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 100), - value: (widget.panelVisible?.value ?? true) ? 1.0 : 0.0) - ..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.completed) { - panelVisible = true; - } else if (status == AnimationStatus.dismissed) { - panelVisible = false; - } - }) - ..addListener(() { - setState(() { - ///Back drop state changed - }); - }); - - widget.panelVisible?.addListener(_subscribeToValueNotifier); - - /// Ensure that the value notifier is updated - /// when the panel is opened or closed - if (widget.panelVisible != null) { - _controller.addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.completed) { - widget.panelVisible.value = true; - } else if (status == AnimationStatus.dismissed) { - widget.panelVisible.value = false; - } - }); - } - } - - void _subscribeToValueNotifier() { - if (widget.panelVisible.value != _backdropPanelVisible) { - _toggleBackdropPanelVisibility(); - } - } - - bool get _backdropPanelVisible => - _controller.status == AnimationStatus.completed || - _controller.status == AnimationStatus.forward; - - void _toggleBackdropPanelVisibility() { - if (widget.toggleFrontLayer) { - _controller.fling( - velocity: _backdropPanelVisible ? -_flingVelocity : _flingVelocity); - } - } - - double get _backdropHeight { - final RenderBox renderBox = _backDropKey.currentContext.findRenderObject(); - return math.max(0.0, renderBox.size.height); - } - - void _handleDragUpdate(DragUpdateDetails details) { - if (!_controller.isAnimating && widget.toggleFrontLayer) { - _controller.value -= details.primaryDelta / _backdropHeight; - } - } - - void _handleDragEnd(DragEndDetails details) { - if (_controller.isAnimating || - _controller.status == AnimationStatus.completed) { - return; - } - - final double fVelocity = - details.velocity.pixelsPerSecond.dy / _backdropHeight; - if (fVelocity < 0.0) { - _controller.fling(velocity: _flingVelocity); - } else if (fVelocity > 0.0) { - _controller.fling(velocity: -_flingVelocity); - } else { - _controller.fling( - velocity: _controller.value < 0.5 ? -_flingVelocity : _flingVelocity); - } - } - - List _appBarMenuButton(Animation progress) { - List toolBarWidgets = []; - if (widget.appBarActions != null) { - toolBarWidgets = []; - for (int i = 0; i < widget.appBarActions.length; i++) { - toolBarWidgets.add(widget.appBarActions[i]); - } - - if (_controller.value < 0.5) { - toolBarWidgets = [ - Container( - height: 60, - width: 60, - child: IconButton( - icon: IconButton( - icon: const Icon( - Icons.clear, - color: Colors.white, - ), - onPressed: () { - _toggleBackdropPanelVisibility(); - }, - ), - onPressed: () {}, - )) - ]; - } - - final Widget res = _CrossFadeTransition( - progress: _controller, - alignment: AlignmentDirectional.centerStart, - child0: - Semantics(namesRoute: true, child: Row(children: toolBarWidgets)), - child1: Semantics( - namesRoute: true, - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 10, 5), - child: Container( - color: Colors.transparent, child: toolBarWidgets[0]), - ))), - ); - toolBarWidgets = [res]; - return toolBarWidgets; - } - return toolBarWidgets; - } - - Size _panelSize = const Size(0, 0); - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - _panelSize = constraints.biggest; - double closedPercentage = 0; - double closedPercentageSearch = 0; - closedPercentage = - (_panelSize.height - (_panelSize.height - frontPanelHeight)) / - _panelSize.height; - closedPercentageSearch = 0.0; - - final Animation panelDetailsPosition = Tween( - begin: Offset(0.0, closedPercentage), - end: Offset(0.0, closedPercentageSearch)) - .animate(_controller.view); - return Theme( - data: sampleListModel.themeData, - child: Scaffold( - resizeToAvoidBottomInset: false, - key: _scaffoldKey, - backgroundColor: sampleListModel.paletteColor, - appBar: PreferredSize( - preferredSize: - const Size.fromHeight(60.0), // here the desired height - child: AppBar( - title: _CrossFadeTransition( - progress: _controller, - alignment: AlignmentDirectional.centerStart, - child0: - Semantics(namesRoute: true, child: widget.appBarTitle), - child1: Semantics(namesRoute: true, child: const Text('')), - ), - actions: _appBarMenuButton(_controller), - elevation: 0.0, - backgroundColor: sampleListModel.backgroundColor, - titleSpacing: NavigationToolbar.kMiddleSpacing, - )), - body: Stack( - overflow: Overflow.clip, - key: _backDropKey, - children: [ - Positioned( - top: 0, - left: 0, - right: 0, - bottom: 0, - child: widget.backLayer), - SlideTransition( - position: panelDetailsPosition, - child: _BackdropPanel( - onTap: _toggleBackdropPanelVisibility, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(12), bottom: Radius.circular(0)), - frontHeaderHeight: 20.0, - padding: EdgeInsets.zero, - onVerticalDragUpdate: _handleDragUpdate, - onVerticalDragEnd: _handleDragEnd, - color: widget.color, - child: widget.frontLayer, - ), - ) - ], - ), - ), - ); - }, - ); - } - - @override - void dispose() { - super.dispose(); - _controller.dispose(); - widget.panelVisible?.removeListener(_subscribeToValueNotifier); - } -} - -class _CrossFadeTransition extends AnimatedWidget { - const _CrossFadeTransition({ - Key key, - this.alignment = Alignment.center, - Animation progress, - this.child0, - this.child1, - }) : super(key: key, listenable: progress); - - final AlignmentGeometry alignment; - final Widget child0; - final Widget child1; - - @override - Widget build(BuildContext context) { - final Animation progress = listenable; - - final double opacity1 = CurvedAnimation( - parent: ReverseAnimation(progress), - curve: const Interval(0.5, 1.0), - ).value; - - final double opacity2 = CurvedAnimation( - parent: progress, - curve: const Interval(0.5, 1.0), - ).value; - - return Stack( - alignment: alignment, - children: [ - Opacity( - opacity: opacity1, - child: Semantics( - scopesRoute: true, - explicitChildNodes: true, - child: child1, - ), - ), - Opacity( - opacity: opacity2, - child: Semantics( - scopesRoute: true, - explicitChildNodes: true, - child: child0, - ), - ), - ], - ); - } -} - -class _BackdropPanel extends StatelessWidget { - const _BackdropPanel({ - Key key, - this.onTap, - this.onVerticalDragUpdate, - this.onVerticalDragEnd, - this.child, - this.borderRadius, - this.frontHeaderHeight, - this.padding, - this.color, - }) : super(key: key); - - final VoidCallback onTap; - final GestureDragUpdateCallback onVerticalDragUpdate; - final GestureDragEndCallback onVerticalDragEnd; - final Widget child; - final BorderRadius borderRadius; - final double frontHeaderHeight; - final EdgeInsets padding; - final Color color; - - @override - Widget build(BuildContext context) { - return Padding( - padding: padding, - child: Material( - color: color, - elevation: 12.0, - borderRadius: borderRadius, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - //---------------------------HEADER------------------------- - GestureDetector( - behavior: HitTestBehavior.opaque, - onVerticalDragUpdate: onVerticalDragUpdate, - onVerticalDragEnd: onVerticalDragEnd, - onTap: onTap, - child: Container(height: frontHeaderHeight), - ), - - //--------------------REST OF THE BODY---------------------- - Expanded( - child: child, - ), - ], - ), - ), - ); - } -} diff --git a/lib/widgets/search_bar.dart b/lib/widgets/search_bar.dart index f41a0c91..1aa918c7 100644 --- a/lib/widgets/search_bar.dart +++ b/lib/widgets/search_bar.dart @@ -15,42 +15,41 @@ import '../model/model.dart'; /// by typing the sample's title in the text editor present in the [SearchBar] class SearchBar extends StatefulWidget { /// Holds the search bar widet - const SearchBar({Key key, @required this.sampleListModel}) + const SearchBar({Key? key, this.sampleListModel}) : assert(sampleListModel != null), super(key: key); /// Contains the sampleModel - final SampleModel sampleListModel; + final SampleModel? sampleListModel; @override - _SearchBarState createState() => _SearchBarState(sampleListModel); + _SearchBarState createState() => _SearchBarState(sampleListModel!); } class _SearchBarState extends State with WidgetsBindingObserver { _SearchBarState(this.sampleListModel); - final SampleModel sampleListModel; + final SampleModel? sampleListModel; - List duplicateControlItems; + late List duplicateControlItems; - List duplicateSampleItems; + late List duplicateSampleItems; List items = []; - OverlayState over; - Widget searchIcon = Icon(Icons.search, - color: kIsWeb ? Colors.white.withOpacity(0.5) : Colors.grey); - Widget closeIcon; + late OverlayState over; + Widget? searchIcon; + Widget? closeIcon; final FocusNode _isFocus = FocusNode(); bool isOpen = false; - OverlayEntry _overlayEntry; + late OverlayEntry _overlayEntry; String hint = 'Search'; - List overlayEntries; + late List overlayEntries; /// Holds the current sample index which selected by keyboard event - int _selectionIndex; + late int? _selectionIndex; /// Holds setState of overlay widget - StateSetter _overlaySetState; + late StateSetter _overlaySetState; /// Creates a focus node for RawKeyEvent final FocusNode _rawKeyFocusNode = FocusNode(); @@ -66,58 +65,64 @@ class _SearchBarState extends State with WidgetsBindingObserver { final Map _keys = {}; /// Holds height of overlay entry - num _overlayHeight; + late num _overlayHeight; ///height of the each search results final num _itemHeight = 38; @override void initState() { + searchIcon = Icon(Icons.search, + color: sampleListModel!.isWebFullView + ? Colors.white.withOpacity(0.5) + : Colors.grey); overlayEntries = []; - over = Overlay.of(context); - duplicateControlItems = sampleListModel.searchControlItems; - duplicateSampleItems = sampleListModel.searchSampleItems; - sampleListModel.searchResults.clear(); - sampleListModel.editingController.text = ''; + over = Overlay.of(context)!; + duplicateControlItems = sampleListModel!.searchControlItems; + duplicateSampleItems = sampleListModel!.searchSampleItems; + sampleListModel!.searchResults.clear(); + sampleListModel!.editingController.text = ''; _isFocus.addListener(() { - closeIcon = - _isFocus.hasFocus && sampleListModel.editingController.text.isNotEmpty - ? IconButton( - splashColor: Colors.transparent, - hoverColor: Colors.transparent, - icon: const Icon(Icons.close, - size: kIsWeb ? 20 : 24, - color: kIsWeb ? Colors.white : Colors.grey), - onPressed: () { - sampleListModel.editingController.text = ''; - _isFocus.unfocus(); - filterSearchResults(''); - if (sampleListModel.isMobileResolution) { - sampleListModel.sampleList.clear(); - setState(() { - closeIcon = null; - }); - } else { - ///Remove the overlay on pressing close button - _overlayEntry.opaque = false; - _removeOverlayEntries(); - } - }) - : null; - if (_isFocus.hasFocus && !sampleListModel.isMobileResolution) { - filterSearchResults(sampleListModel.editingController.text); - } else if (!sampleListModel.isMobileResolution) { + closeIcon = (_isFocus.hasFocus && + sampleListModel!.editingController.text.isNotEmpty + ? IconButton( + splashColor: Colors.transparent, + hoverColor: Colors.transparent, + icon: Icon(Icons.close, + size: sampleListModel!.isWebFullView ? 20 : 24, + color: sampleListModel!.isWebFullView + ? Colors.white + : Colors.grey), + onPressed: () { + sampleListModel!.editingController.text = ''; + _isFocus.unfocus(); + filterSearchResults(''); + if (sampleListModel!.isMobileResolution) { + sampleListModel!.sampleList.clear(); + setState(() { + closeIcon = null; + }); + } else { + ///Remove the overlay on pressing close button + _overlayEntry.opaque = false; + _removeOverlayEntries(); + } + }) + : null); + if (_isFocus.hasFocus && !sampleListModel!.isMobileResolution) { + filterSearchResults(sampleListModel!.editingController.text); + } else if (!sampleListModel!.isMobileResolution) { Timer(const Duration(milliseconds: 200), () { _removeOverlayEntries(); }); } - if (sampleListModel.editingController.text.isEmpty) { + if (sampleListModel!.editingController.text.isEmpty) { setState(() { searchIcon = _isFocus.hasFocus || - sampleListModel.editingController.text.isNotEmpty + sampleListModel!.editingController.text.isNotEmpty ? null : Icon(Icons.search, - color: sampleListModel.isWeb + color: sampleListModel!.isWebFullView ? Colors.white.withOpacity(0.5) : Colors.grey); }); @@ -125,15 +130,15 @@ class _SearchBarState extends State with WidgetsBindingObserver { hint = _isFocus.hasFocus ? '' : 'Search'; }); super.initState(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); } @override void dispose() { - sampleListModel.searchResults.clear(); - sampleListModel.editingController.text = ''; + sampleListModel!.searchResults.clear(); + sampleListModel!.editingController.text = ''; _isFocus.unfocus(); - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance!.removeObserver(this); super.dispose(); } @@ -160,26 +165,26 @@ class _SearchBarState extends State with WidgetsBindingObserver { final List dummyControlData = []; for (int i = 0; i < dummySearchControl.length; i++) { final Control item = dummySearchControl[i]; - if (item.title.toLowerCase().contains(query.toLowerCase())) { + if (item.title!.toLowerCase().contains(query.toLowerCase())) { dummyControlData.add(item); } } final List dummySampleData = []; for (int i = 0; i < dummySearchSamplesList.length; i++) { final SubItem item = dummySearchSamplesList[i]; - if (item.title.toLowerCase().contains(query.toLowerCase())) { + if (item.title!.toLowerCase().contains(query.toLowerCase())) { dummySampleData.add(item); } } - sampleListModel.controlList.clear(); - sampleListModel.sampleList.clear(); - sampleListModel.sampleList.addAll(dummySampleData); - sampleListModel.searchResults.clear(); - sampleListModel.searchResults.addAll(dummySampleData); - if (sampleListModel.isMobileResolution) { + sampleListModel!.controlList.clear(); + sampleListModel!.sampleList.clear(); + sampleListModel!.sampleList.addAll(dummySampleData); + sampleListModel!.searchResults.clear(); + sampleListModel!.searchResults.addAll(dummySampleData); + if (sampleListModel!.isMobileResolution) { //ignore: invalid_use_of_protected_member - sampleListModel.notifyListeners(); + sampleListModel!.notifyListeners(); } else { _overlayEntry = _createOverlayEntry(); overlayEntries.add(_overlayEntry); @@ -187,9 +192,9 @@ class _SearchBarState extends State with WidgetsBindingObserver { return; } } else { - sampleListModel.searchResults.clear(); - sampleListModel.controlList.addAll(duplicateControlItems); - sampleListModel.sampleList.clear(); + sampleListModel!.searchResults.clear(); + sampleListModel!.controlList.addAll(duplicateControlItems); + sampleListModel!.sampleList.clear(); } } @@ -207,42 +212,44 @@ class _SearchBarState extends State with WidgetsBindingObserver { /// Performing key board actions /// [ArrowDown], [ArrowUp], [Enter] RawKeyEvents void _performKeyBoardEvent(RawKeyEvent event) { - final RawKeyEventDataWeb rawKeyEventDataWeb = event.data; + /// We need RawKeyEventDataWeb, RawKeyEventDataWindows, + /// RawKeyEventDataMacOs. So dynamic type used + final dynamic rawKeyEventData = event.data; if (event is RawKeyDownEvent) { - if (sampleListModel.searchResults.isNotEmpty && - rawKeyEventDataWeb.code == 'ArrowDown') { + if (sampleListModel!.searchResults.isNotEmpty && + rawKeyEventData.logicalKey == LogicalKeyboardKey.arrowDown) { ///Arrow down key action _selectionIndex = _selectionIndex == null ? 0 - : (_selectionIndex >= sampleListModel.searchResults.length - 1) - ? sampleListModel.searchResults.length - 1 - : _selectionIndex + 1; + : (_selectionIndex! >= sampleListModel!.searchResults.length - 1) + ? sampleListModel!.searchResults.length - 1 + : _selectionIndex! + 1; final List indexes = _getVisibleIndexes(); if (!indexes.contains(_selectionIndex)) { - _scrollToDown(_selectionIndex); + _scrollToDown(_selectionIndex!); } _overlaySetState(() { ///Notify overlay list to scroll down }); - } else if (sampleListModel.searchResults.isNotEmpty && - rawKeyEventDataWeb.code == 'ArrowUp') { + } else if (sampleListModel!.searchResults.isNotEmpty && + rawKeyEventData.logicalKey == LogicalKeyboardKey.arrowUp) { ///Arrow up key action _selectionIndex = _selectionIndex == null ? 0 : _selectionIndex == 0 ? 0 - : _selectionIndex - 1; + : _selectionIndex! - 1; final List indexes = _getVisibleIndexes(); if (!indexes.contains(_selectionIndex)) { - _scrollToUp(_selectionIndex); + _scrollToUp(_selectionIndex!); } _overlaySetState(() { ///Notify overlay list to scroll up }); - } else if (rawKeyEventDataWeb.code == 'Escape') { + } else if (rawKeyEventData.logicalKey == LogicalKeyboardKey.escape) { ///Escape key action _selectionIndex = null; - sampleListModel.editingController.text = ''; + sampleListModel!.editingController.text = ''; _isFocus.unfocus(); _overlayEntry.maintainState = false; _overlayEntry.opaque = false; @@ -254,39 +261,39 @@ class _SearchBarState extends State with WidgetsBindingObserver { /// Navigate to the selected sample void _navigateToSample(int index) { _overlayEntry.maintainState = false; - sampleListModel.editingController.text = ''; + sampleListModel!.editingController.text = ''; _isFocus.unfocus(); _overlayEntry.opaque = false; _removeOverlayEntries(); - final dynamic renderSample = - sampleListModel.sampleWidget[sampleListModel.searchResults[index].key]; + final dynamic renderSample = sampleListModel! + .sampleWidget[sampleListModel!.searchResults[index].key]; if (renderSample != null) { - sampleListModel.isWeb + sampleListModel!.isWebFullView ? Navigator.pushNamed( - context, sampleListModel.searchResults[index].breadCrumbText) + context, sampleListModel!.searchResults[index].breadCrumbText!) : onTapExpandSample( - context, sampleListModel.searchResults[index], sampleListModel); + context, sampleListModel!.searchResults[index], sampleListModel!); } } /// Scroll the list view position from its current value to the given value /// In up to down direction - void _scrollToDown(num i) { + void _scrollToDown(int i) { _controller.jumpTo(_controller.position.pixels + _itemHeight); } /// Scroll the list view position from its current value to the given value /// In down to up direction - void _scrollToUp(num i) { - _controller.jumpTo(_itemHeight * i); + void _scrollToUp(int i) { + _controller.jumpTo(_itemHeight * i.toDouble()); } ///Get the list of visible index of the listViewBuilder List _getVisibleIndexes() { - final Rect rect = _RectGetterFromListView.getRectFromKey(_globalKey); + final Rect rect = _RectGetterFromListView.getRectFromKey(_globalKey)!; final List items = []; _keys.forEach((dynamic index, dynamic key) { - final Rect itemRect = _RectGetterFromListView.getRectFromKey(key); + final Rect itemRect = _RectGetterFromListView.getRectFromKey(key)!; if (itemRect != null && (itemRect.top >= rect.top && itemRect.bottom <= rect.bottom + 2)) { items.add(index); @@ -296,12 +303,12 @@ class _SearchBarState extends State with WidgetsBindingObserver { } OverlayEntry _createOverlayEntry() { - final RenderBox renderBox = context.findRenderObject(); + final RenderBox renderBox = context.findRenderObject() as RenderBox; final Size size = renderBox.size; final Offset offset = renderBox.localToGlobal(Offset.zero); _selectionIndex = null; - final num height = (sampleListModel.searchResults.length < 4 - ? 0.1 * sampleListModel.searchResults.length + final num height = (sampleListModel!.searchResults.length < 4 + ? 0.1 * sampleListModel!.searchResults.length : 0.4) * MediaQuery.of(context).size.height; @@ -317,22 +324,22 @@ class _SearchBarState extends State with WidgetsBindingObserver { left: offset.dx, top: offset.dy + size.height - 5, width: size.width, - height: sampleListModel.searchResults.isEmpty && - sampleListModel.editingController.text.isNotEmpty && + height: sampleListModel!.searchResults.isEmpty && + sampleListModel!.editingController.text.isNotEmpty && _isFocus.hasFocus ? 0.1 * MediaQuery.of(context).size.height : _overlayHeight.toDouble(), child: CupertinoScrollbar( child: Card( - color: sampleListModel.cardColor, - child: sampleListModel.editingController.text.isEmpty || + color: sampleListModel!.cardColor, + child: sampleListModel!.editingController.text.isEmpty || _isFocus.hasFocus == false ? null - : (sampleListModel.searchResults.isEmpty + : (sampleListModel!.searchResults.isEmpty ? ListTile( title: Text('No results found', style: TextStyle( - color: sampleListModel.textColor, + color: sampleListModel!.textColor, fontSize: 13, fontFamily: 'Roboto-Regular')), onTap: () {}, @@ -343,7 +350,7 @@ class _SearchBarState extends State with WidgetsBindingObserver { controller: _controller, padding: const EdgeInsets.all(0), itemCount: - sampleListModel.searchResults.length, + sampleListModel!.searchResults.length, itemBuilder: (BuildContext context, int index) { _keys[index] = _RectGetterFromListView @@ -355,31 +362,31 @@ class _SearchBarState extends State with WidgetsBindingObserver { child: Material( color: index == _selectionIndex ? Colors.grey.withOpacity(0.4) - : sampleListModel.cardColor, + : sampleListModel!.cardColor, child: InkWell( - hoverColor: Colors.grey - .withOpacity(0.2), - child: Padding( - padding: - const EdgeInsets.all( - 10), - child: Text( - sampleListModel - .searchResults[ - index] - .title, - style: TextStyle( - color: - sampleListModel - .textColor, - fontSize: 13, - fontFamily: - 'Roboto-Regular'), - )), - onTap: () { - _selectionIndex = null; - _navigateToSample(index); - })), + hoverColor: Colors.grey + .withOpacity(0.2), + onTap: () { + _selectionIndex = null; + _navigateToSample(index); + }, + child: Padding( + padding: + const EdgeInsets.all( + 10), + child: Text( + sampleListModel! + .searchResults[index] + .title!, + style: TextStyle( + color: + sampleListModel! + .textColor, + fontSize: 13, + fontFamily: + 'Roboto-Regular'), + )), + )), )); }))), ), @@ -393,7 +400,7 @@ class _SearchBarState extends State with WidgetsBindingObserver { Widget build(BuildContext context) { return RawKeyboardListener( focusNode: _rawKeyFocusNode, - onKey: (RawKeyEvent event) => !sampleListModel.isMobileResolution + onKey: (RawKeyEvent event) => !sampleListModel!.isMobileResolution ? _performKeyBoardEvent(event) : null, child: Column( @@ -401,11 +408,11 @@ class _SearchBarState extends State with WidgetsBindingObserver { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - height: sampleListModel.isWeb ? 35 : 45, + height: sampleListModel!.isWebFullView ? 35 : 45, width: double.infinity, decoration: BoxDecoration( - color: kIsWeb - ? (Colors.grey[100]).withOpacity(0.2) + color: sampleListModel!.isWebFullView + ? (Colors.grey[100])!.withOpacity(0.2) : Colors.white, borderRadius: const BorderRadius.all(Radius.circular(5.0))), child: Padding( @@ -414,23 +421,27 @@ class _SearchBarState extends State with WidgetsBindingObserver { child: Container( child: TextField( mouseCursor: MaterialStateMouseCursor.clickable, - cursorColor: kIsWeb ? Colors.white : Colors.grey, + cursorColor: sampleListModel!.isWebFullView + ? Colors.white + : Colors.grey, focusNode: _isFocus, onChanged: (String value) { closeIcon = _isFocus.hasFocus && - (sampleListModel.editingController.text.isNotEmpty) + (sampleListModel!.editingController.text.isNotEmpty) ? IconButton( splashColor: Colors.transparent, hoverColor: Colors.transparent, - icon: const Icon(Icons.close, - size: kIsWeb ? 20 : 24, - color: kIsWeb ? Colors.white : Colors.grey), + icon: Icon(Icons.close, + size: sampleListModel!.isWebFullView ? 20 : 24, + color: sampleListModel!.isWebFullView + ? Colors.white + : Colors.grey), onPressed: () { - sampleListModel.editingController.text = ''; + sampleListModel!.editingController.text = ''; _isFocus.unfocus(); filterSearchResults(''); - if (sampleListModel.isMobileResolution) { - sampleListModel.sampleList.clear(); + if (sampleListModel!.isMobileResolution) { + sampleListModel!.sampleList.clear(); setState(() { closeIcon = null; }); @@ -448,23 +459,27 @@ class _SearchBarState extends State with WidgetsBindingObserver { onEditingComplete: () { _isFocus.unfocus(); }, - style: const TextStyle( + style: TextStyle( fontFamily: 'Roboto-Regular', - color: kIsWeb ? Colors.white : Colors.grey, + color: sampleListModel!.isWebFullView + ? Colors.white + : Colors.grey, fontSize: 13), - controller: sampleListModel.editingController, + controller: sampleListModel!.editingController, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( - labelStyle: const TextStyle( + labelStyle: TextStyle( fontFamily: 'Roboto-Regular', - color: kIsWeb ? Colors.white : Colors.grey, + color: sampleListModel!.isWebFullView + ? Colors.white + : Colors.grey, fontSize: 13), hintText: hint, border: InputBorder.none, hintStyle: TextStyle( fontSize: 13, fontFamily: 'Roboto-Regular', - color: kIsWeb + color: sampleListModel!.isWebFullView ? Colors.white.withOpacity(0.5) : Colors.grey), suffixIcon: closeIcon, @@ -479,17 +494,18 @@ class _SearchBarState extends State with WidgetsBindingObserver { /// Get the rect from list view using the global key class _RectGetterFromListView extends StatefulWidget { - const _RectGetterFromListView({@required this.key, @required this.child}) - : super(key: key); - final GlobalKey<_RectGetterFromListViewState> key; - final Widget child; + const _RectGetterFromListView({this.key, this.child}) : super(key: key); + @override + final GlobalKey<_RectGetterFromListViewState>? key; + final Widget? child; ///Get the rect of list view - static Rect getRectFromKey( + static Rect? getRectFromKey( GlobalKey<_RectGetterFromListViewState> _globalKey) { - final RenderObject object = _globalKey?.currentContext?.findRenderObject(); - final dynamic translation = object?.getTransformTo(null)?.getTranslation(); - final Size size = object?.semanticBounds?.size; + final RenderObject object = + _globalKey.currentContext?.findRenderObject() as RenderObject; + final dynamic translation = object.getTransformTo(null).getTranslation(); + final Size size = object.semanticBounds.size; if (translation != null && size != null) { return Rect.fromLTWH( @@ -509,5 +525,5 @@ class _RectGetterFromListView extends StatefulWidget { class _RectGetterFromListViewState extends State<_RectGetterFromListView> { @override - Widget build(BuildContext context) => widget.child; + Widget build(BuildContext context) => widget.child!; } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 00000000..85ef4682 --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "flutter_examples") +set(APPLICATION_ID "com.syncfusion.flutter_examples") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..a1da1b9e --- /dev/null +++ b/linux/flutter/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) +pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) +pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO + PkgConfig::BLKID + PkgConfig::LZMA +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..026851fa --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..9bf74789 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..1fc8ed34 --- /dev/null +++ b/linux/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/linux/main.cc b/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/linux/main.cc @@ -0,0 +1,6 @@ +#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/linux/my_application.cc b/linux/my_application.cc new file mode 100644 index 00000000..c74c6877 --- /dev/null +++ b/linux/my_application.cc @@ -0,0 +1,104 @@ +#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, "flutter_examples"); + 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, "flutter_examples"); + } + + 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, + nullptr)); +} diff --git a/linux/my_application.h b/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/linux/my_application.h @@ -0,0 +1,18 @@ +#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/macos/.gitignore b/macos/.gitignore new file mode 100644 index 00000000..d2fd3772 --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,6 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..4618f386 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_macos +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 00000000..dade8dfa --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.11' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2c73eea4 --- /dev/null +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,572 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* flutter_examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flutter_examples.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* flutter_examples.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* flutter_examples.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..518d19c4 --- /dev/null +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..b86f2dfb Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..a2a1e807 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..c81c1d9d Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..b0e5852b Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..e70b3b37 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..84970bf5 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..0f3f90e1 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..537341ab --- /dev/null +++ b/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..29d43380 --- /dev/null +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = flutter_examples + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.syncfusion.flutterExamples + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2021 com.syncfusion. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..08c3ab17 --- /dev/null +++ b/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..2722837e --- /dev/null +++ b/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements new file mode 100644 index 00000000..64cabb4e --- /dev/null +++ b/macos/Runner/Release.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/pubspec.yaml b/pubspec.yaml index 189a91c1..711ff142 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,36 +1,36 @@ name: flutter_examples description: This project contains the Syncfusion Flutter UI widgets examples. version: 18.4.30 -author: Syncfusion homepage: https://github.com/syncfusion/flutter-examples environment: - sdk: ">=2.1.0 <3.0.0" - + sdk: ">=2.12.0 <3.0.0" dependencies: flutter_test: sdk: flutter flutter: sdk: flutter - url_launcher: ^5.0.3 - intl: ^0.16.0 - path_provider: ^1.6.18 - - syncfusion_flutter_datagrid: ^18.4.30-beta - syncfusion_flutter_calendar: ^18.4.30 - syncfusion_flutter_datepicker: ^18.4.30-beta - syncfusion_flutter_charts: ^18.4.30 - syncfusion_flutter_gauges: ^18.4.30 - syncfusion_flutter_sliders: ^18.4.30-beta - syncfusion_flutter_pdf: ^18.4.30-beta - syncfusion_flutter_barcodes: ^18.4.30 - syncfusion_officechart: ^18.4.30-beta - syncfusion_flutter_maps: ^18.4.30-beta - syncfusion_flutter_signaturepad: ^18.4.30-beta - syncfusion_flutter_pdfviewer: ^18.4.30-beta - + url_launcher: ^6.0.2 + path_provider: ^2.0.1 + path_provider_macos: ^2.0.0 + desktop_window: 0.4.0 + syncfusion_flutter_datagrid: ^19.1.54-beta + syncfusion_flutter_calendar: ^19.1.54 + syncfusion_flutter_datepicker: ^19.1.54-beta + syncfusion_flutter_charts: ^19.1.54 + syncfusion_flutter_gauges: ^19.1.54 + syncfusion_flutter_sliders: ^19.1.54-beta + syncfusion_flutter_pdf: ^19.1.54-beta + syncfusion_flutter_barcodes: ^19.1.54 + syncfusion_officechart: ^19.1.54-beta + syncfusion_flutter_maps: ^19.1.54-beta + syncfusion_flutter_signaturepad: ^19.1.54-beta + syncfusion_flutter_pdfviewer: ^19.1.54-beta + syncfusion_flutter_treemap: ^19.1.54-beta + + flutter: uses-material-design: true assets: @@ -46,6 +46,9 @@ flutter: - usa.json - south_america.json - australia.json + - maps_brazil_boundary.json + - maps_uk_boundary.json + - maps_france_boundary.json - river.json - london_to_british.json - london_to_chessington.json diff --git a/web/index.html b/web/index.html index 00e3adff..b7892c93 100644 --- a/web/index.html +++ b/web/index.html @@ -42,24 +42,6 @@ gtag('js', new Date()); gtag('config', 'UA-233131-38'); - async function download() { - var pdfAsDataUri = "data:application/pdf;base64, " + pdfdata; - var link = document.createElement('a'); - link.download = filename; - link.href = pdfAsDataUri; - link.type = 'application/pdf'; - link.click(); - } - - async function downloadExcel() { - var excelAsDataUri = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64, " + exceldata; - var link = document.createElement('a'); - link.download = filename; - link.href = excelAsDataUri; - link.type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; - link.click(); - } - _atrk_opts = { atrk_acct:"LPpPs1Fx9f207i", @@ -90,6 +72,12 @@ }); } + + + diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 00000000..1d36fd92 --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.15) +project(flutter_examples LANGUAGES CXX) + +set(BINARY_NAME "flutter_examples") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() + +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..b02c5485 --- /dev/null +++ b/windows/flutter/CMakeLists.txt @@ -0,0 +1,103 @@ +cmake_minimum_required(VERSION 3.15) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..ddfcf7c3 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,12 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + UrlLauncherPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherPlugin")); +} diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..9846246b --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..411af46d --- /dev/null +++ b/windows/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_windows +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..977e38b5 --- /dev/null +++ b/windows/runner/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(runner LANGUAGES CXX) + +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "run_loop.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) +apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc new file mode 100644 index 00000000..f2dbbf01 --- /dev/null +++ b/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 2,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "2.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.syncfusion" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "flutter_examples" "\0" + VALUE "LegalCopyright", "Copyright (C) 2021 com.syncfusion. All rights reserved." "\0" + VALUE "OriginalFilename", "flutter_examples.exe" "\0" + VALUE "ProductName", "flutter_examples" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..c4227230 --- /dev/null +++ b/windows/runner/flutter_window.cpp @@ -0,0 +1,64 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project) + : run_loop_(run_loop), project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opporutunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h new file mode 100644 index 00000000..b663ddd5 --- /dev/null +++ b/windows/runner/flutter_window.h @@ -0,0 +1,39 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "run_loop.h" +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow driven by the |run_loop|, hosting a + // Flutter view running |project|. + explicit FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The run loop driving events for this window. + RunLoop* run_loop_; + + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp new file mode 100644 index 00000000..3686bfa0 --- /dev/null +++ b/windows/runner/main.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "run_loop.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } else { + STARTUPINFO si = { 0 }; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION pi = { 0 }; + WCHAR lpszCmd[MAX_PATH] = L"cmd.exe"; + if (::CreateProcess(NULL, lpszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { + do { + if (::AttachConsole(pi.dwProcessId)) { + ::TerminateProcess(pi.hProcess, 0); + break; + } + } while (ERROR_INVALID_HANDLE == GetLastError()); + ::CloseHandle(pi.hProcess); + ::CloseHandle(pi.hThread); + } + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + RunLoop run_loop; + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(&run_loop, project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"flutter_examples", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + run_loop.Run(); + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..17e5dc3f Binary files /dev/null and b/windows/runner/resources/app_icon.ico differ diff --git a/windows/runner/run_loop.cpp b/windows/runner/run_loop.cpp new file mode 100644 index 00000000..2d6636ab --- /dev/null +++ b/windows/runner/run_loop.cpp @@ -0,0 +1,66 @@ +#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/windows/runner/run_loop.h b/windows/runner/run_loop.h new file mode 100644 index 00000000..000d3624 --- /dev/null +++ b/windows/runner/run_loop.h @@ -0,0 +1,40 @@ +#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/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..c977c4a4 --- /dev/null +++ b/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp new file mode 100644 index 00000000..d19bdbbc --- /dev/null +++ b/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + if (target_length == 0) { + return std::string(); + } + std::string utf8_string; + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp new file mode 100644 index 00000000..c10f08dc --- /dev/null +++ b/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h new file mode 100644 index 00000000..17ba4311 --- /dev/null +++ b/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_