From a29a31e33761e8a60c650533d97e0df2aec45b38 Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 30 Jul 2023 20:44:50 -0400 Subject: [PATCH 01/11] update to latest dependencies --- lib/beatscratch_plugin.dart | 2 - .../music/notation_music_renderer.dart | 3 +- lib/edit_menu.dart | 7 - lib/layers_view/layers_part_view.dart | 2 - lib/layers_view/layers_view.dart | 2 - lib/layers_view/melody_menu_browser.dart | 2 - lib/layers_view/melody_reference_view.dart | 3 - lib/main.dart | 11 +- lib/main_toolbars.dart | 6 - lib/music_preview/melody_preview.dart | 1 - lib/music_preview/part_preview.dart | 3 - lib/music_preview/preview_renderer.dart | 2 - lib/music_preview/score_preview.dart | 4 - lib/music_preview/section_preview.dart | 1 - lib/music_view/music_scroll_container.dart | 3 - lib/music_view/music_system_painter.dart | 5 - lib/music_view/music_view.dart | 3 - lib/music_view/part_instrument_picker.dart | 2 - lib/music_view/part_melody_browser.dart | 1 - lib/recording/recording.dart | 1 - lib/settings/settings_common.dart | 1 - lib/settings/settings_panel.dart | 5 - lib/settings/tile.dart | 3 - lib/settings/tile_bluetooth.dart | 10 - lib/settings/tile_controller.dart | 2 - lib/settings/tile_synth.dart | 2 - lib/storage/score_manager.dart | 1 - lib/storage/score_picker.dart | 7 - lib/storage/score_picker_preview.dart | 5 - lib/storage/universe_manager.dart | 6 - lib/ui_models.dart | 1 - lib/universe_view/universe_icon.dart | 4 +- lib/universe_view/universe_upload_dialog.dart | 20 - lib/universe_view/universe_view_ui.dart | 5 - lib/util/music_utils.dart | 2 +- lib/util/ui_utils.dart | 1 - lib/widget/beats_badge.dart | 2 - lib/widget/colorboard.dart | 1 - lib/widget/incrementable_value.dart | 2 - lib/widget/keyboard.dart | 1 - lib/widget/my_buttons.dart | 5 +- lib/widget/my_platform.dart | 1 - lib/widget/scalable_view.dart | 3 - lib/widget/section_list.dart | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 +- pubspec.lock | 359 ++++++++---------- pubspec.yaml | 41 +- 47 files changed, 187 insertions(+), 370 deletions(-) diff --git a/lib/beatscratch_plugin.dart b/lib/beatscratch_plugin.dart index 60f1d343..fd64b28e 100644 --- a/lib/beatscratch_plugin.dart +++ b/lib/beatscratch_plugin.dart @@ -1,4 +1,3 @@ -import 'dart:typed_data'; import 'package:dart_midi/dart_midi.dart'; // ignore: implementation_imports @@ -9,7 +8,6 @@ import 'package:flutter/services.dart'; import 'generated/protos/protos.dart'; import 'messages/messages_ui.dart'; import 'recording/recording.dart'; -import 'settings/settings_panel.dart'; import 'settings/settings_common.dart'; import 'util/fake_js.dart' if (dart.library.js) 'dart:js'; import 'util/music_utils.dart'; diff --git a/lib/drawing/music/notation_music_renderer.dart b/lib/drawing/music/notation_music_renderer.dart index 419b763b..f87e2515 100644 --- a/lib/drawing/music/notation_music_renderer.dart +++ b/lib/drawing/music/notation_music_renderer.dart @@ -29,8 +29,7 @@ class _NoteheadInstruction { this.noteheadLeft, this.ledgerLines, this.noteheadTop, - this.staggered, - this.hadStaggeredNotes}); + this.staggered}); } class _StemInstruction { diff --git a/lib/edit_menu.dart b/lib/edit_menu.dart index cafdc3fa..140d0346 100644 --- a/lib/edit_menu.dart +++ b/lib/edit_menu.dart @@ -1,20 +1,13 @@ import 'package:beatscratch_flutter_redux/util/music_theory.dart'; -import 'package:beatscratch_flutter_redux/util/ui_utils.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'beatscratch_plugin.dart'; import 'colors.dart'; -import 'export/export_ui.dart'; import 'generated/protos/protos.dart'; import 'music_preview/melody_preview.dart'; import 'music_preview/part_preview.dart'; import 'music_preview/section_preview.dart'; import 'ui_models.dart'; import 'widget/beats_badge.dart'; -import 'widget/my_platform.dart'; Future showEditMenu( {@required BuildContext context, diff --git a/lib/layers_view/layers_part_view.dart b/lib/layers_view/layers_part_view.dart index b6e72735..059eb1f3 100644 --- a/lib/layers_view/layers_part_view.dart +++ b/lib/layers_view/layers_part_view.dart @@ -1,8 +1,6 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter_reorderable_list/flutter_reorderable_list.dart' as frl; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; diff --git a/lib/layers_view/layers_view.dart b/lib/layers_view/layers_view.dart index 16a1e72f..277205e9 100644 --- a/lib/layers_view/layers_view.dart +++ b/lib/layers_view/layers_view.dart @@ -1,8 +1,6 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; import 'package:animated_list_plus/transitions.dart'; diff --git a/lib/layers_view/melody_menu_browser.dart b/lib/layers_view/melody_menu_browser.dart index 1e898d6f..816fc912 100644 --- a/lib/layers_view/melody_menu_browser.dart +++ b/lib/layers_view/melody_menu_browser.dart @@ -1,7 +1,6 @@ import 'dart:io'; import '../util/util.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -12,7 +11,6 @@ import '../music_preview/melody_preview.dart'; import '../storage/score_manager.dart'; import '../util/dummydata.dart'; import '../util/music_theory.dart'; -import '../util/bs_methods.dart'; import '../widget/my_popup_menu.dart'; import '../widget/my_popup_menu.dart' as myPopup; import '../widget/beats_badge.dart'; diff --git a/lib/layers_view/melody_reference_view.dart b/lib/layers_view/melody_reference_view.dart index 39264866..56c8161d 100644 --- a/lib/layers_view/melody_reference_view.dart +++ b/lib/layers_view/melody_reference_view.dart @@ -1,7 +1,4 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_reorderable_list/flutter_reorderable_list.dart' as frl; import 'package:animated_list_plus/transitions.dart'; diff --git a/lib/main.dart b/lib/main.dart index e8a8925e..df59ba61 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,9 +9,7 @@ import 'universe_view/universe_view.dart'; import 'recording/recording.dart'; import 'package:fluro/fluro.dart' as Fluro; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:native_device_orientation/native_device_orientation.dart'; @@ -32,7 +30,6 @@ import 'storage/score_manager.dart'; import 'storage/score_picker.dart'; import 'storage/url_conversions.dart'; import 'ui_models.dart'; -import 'util/bs_methods.dart'; import 'util/dummydata.dart'; import 'util/music_theory.dart'; import 'util/proto_utils.dart'; @@ -419,7 +416,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { Color get sectionColor => currentSection.color.color; - _selectOrDeselectMelody(Melody melody, {bool hideMusicOnDeselect: true}) { + _selectOrDeselectMelody(Melody melody, {bool hideMusicOnDeselect = true}) { setState(() { if (selectedMelody != melody) { selectedMelody = melody; @@ -444,7 +441,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { }); } - _selectOrDeselectPart(Part part, {bool hideMusicOnDeselect: true}) { + _selectOrDeselectPart(Part part, {bool hideMusicOnDeselect = true}) { setState(() { print("yay"); if (selectedPart != part) { @@ -1140,9 +1137,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { // verticalSectionList = context.isLandscape; // } if (context.isLandscape) { - SystemChrome.setEnabledSystemUIOverlays([]); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); } else { - SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); } if (BeatScratchPlugin.playing) { _tapInBeat = null; diff --git a/lib/main_toolbars.dart b/lib/main_toolbars.dart index 438ac127..309f7f9a 100644 --- a/lib/main_toolbars.dart +++ b/lib/main_toolbars.dart @@ -1,22 +1,17 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; -import 'dart:ui'; import 'package:beatscratch_flutter_redux/edit_menu.dart'; import 'package:beatscratch_flutter_redux/main_menu.dart'; import 'package:beatscratch_flutter_redux/universe_view/universe_view.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:package_info_plus/package_info_plus.dart'; import 'beatscratch_plugin.dart'; import 'cache_management.dart'; import 'colors.dart'; -import 'export/export.dart'; import 'generated/protos/music.pb.dart'; import 'messages/messages_ui.dart'; import 'settings/app_settings.dart'; @@ -25,7 +20,6 @@ import 'storage/score_picker.dart'; import 'storage/universe_manager.dart'; import 'storage/url_conversions.dart'; import 'ui_models.dart'; -import 'util/bs_methods.dart'; import 'util/music_theory.dart'; import 'util/util.dart'; import 'widget/my_buttons.dart'; diff --git a/lib/music_preview/melody_preview.dart b/lib/music_preview/melody_preview.dart index f9c14b9d..2cac1f5e 100644 --- a/lib/music_preview/melody_preview.dart +++ b/lib/music_preview/melody_preview.dart @@ -1,5 +1,4 @@ import '../util/bs_methods.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../generated/protos/music.pb.dart'; diff --git a/lib/music_preview/part_preview.dart b/lib/music_preview/part_preview.dart index 57c25444..b58abad6 100644 --- a/lib/music_preview/part_preview.dart +++ b/lib/music_preview/part_preview.dart @@ -1,12 +1,9 @@ import '../util/bs_methods.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../generated/protos/music.pb.dart'; import 'score_preview.dart'; import '../util/dummydata.dart'; -import '../util/music_theory.dart'; -import '../colors.dart'; class PartPreview extends StatefulWidget { final Section section; diff --git a/lib/music_preview/preview_renderer.dart b/lib/music_preview/preview_renderer.dart index 3732b17d..4844b006 100644 --- a/lib/music_preview/preview_renderer.dart +++ b/lib/music_preview/preview_renderer.dart @@ -1,10 +1,8 @@ -import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../colors.dart'; diff --git a/lib/music_preview/score_preview.dart b/lib/music_preview/score_preview.dart index c3d1c5e2..5ba966ab 100644 --- a/lib/music_preview/score_preview.dart +++ b/lib/music_preview/score_preview.dart @@ -1,5 +1,4 @@ import 'dart:math'; -import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -8,14 +7,11 @@ import 'package:dcache/dcache.dart'; import '../colors.dart'; import '../generated/protos/music.pb.dart'; -import '../music_view/music_system_painter.dart'; import '../settings/app_settings.dart'; import '../ui_models.dart'; -import '../util/bs_methods.dart'; import '../util/music_notation_theory.dart'; import '../util/music_theory.dart'; import '../util/util.dart'; -import '../widget/my_platform.dart'; import 'preview_renderer.dart'; class ScorePreview extends StatefulWidget { diff --git a/lib/music_preview/section_preview.dart b/lib/music_preview/section_preview.dart index 1a4f1d10..783b2cc9 100644 --- a/lib/music_preview/section_preview.dart +++ b/lib/music_preview/section_preview.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import '../generated/protos/music.pb.dart'; import 'score_preview.dart'; import '../util/dummydata.dart'; -import '../util/music_theory.dart'; import '../colors.dart'; class SectionPreview extends StatefulWidget { diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index b0b16a6e..19fa6522 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -1,11 +1,8 @@ import 'dart:math'; import 'package:beatscratch_flutter_redux/settings/settings.dart'; -import 'package:beatscratch_flutter_redux/widget/my_platform.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:matrix4_transform/matrix4_transform.dart'; import '../beatscratch_plugin.dart'; import '../generated/protos/music.pb.dart'; diff --git a/lib/music_view/music_system_painter.dart b/lib/music_view/music_system_painter.dart index e620cf25..10d3c2e4 100644 --- a/lib/music_view/music_system_painter.dart +++ b/lib/music_view/music_system_painter.dart @@ -1,10 +1,7 @@ import 'dart:math'; import 'package:beatscratch_flutter_redux/widget/my_platform.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/painting.dart'; -import 'package:flutter/rendering.dart'; import '../util/util.dart'; import '../beatscratch_plugin.dart'; @@ -12,8 +9,6 @@ import '../colors.dart'; import '../drawing/color_guide.dart'; import '../drawing/harmony_beat_renderer.dart'; import '../drawing/music/music.dart'; -import '../drawing/music/music_clef_renderer.dart'; -import '../drawing/music/music_staff_lines_renderer.dart'; import '../generated/protos/music.pb.dart'; import '../ui_models.dart'; import '../util/dummydata.dart'; diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index e6a23a4d..d55e1500 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -1,7 +1,5 @@ import 'dart:math'; -import 'dart:ui'; -import 'package:beatscratch_flutter_redux/generated/i18n.dart'; import 'package:beatscratch_flutter_redux/widget/color_filtered_image_asset.dart'; import '../colors.dart'; @@ -18,7 +16,6 @@ import '../generated/protos/music.pb.dart'; import '../ui_models.dart'; import '../util/music_notation_theory.dart'; import '../util/music_theory.dart'; -import '../util/bs_methods.dart'; import '../util/util.dart'; import '../widget/incrementable_value.dart'; import '../widget/my_buttons.dart'; diff --git a/lib/music_view/part_instrument_picker.dart b/lib/music_view/part_instrument_picker.dart index 02ce5490..ce6ec7f1 100644 --- a/lib/music_view/part_instrument_picker.dart +++ b/lib/music_view/part_instrument_picker.dart @@ -1,8 +1,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; import 'package:animated_list_plus/transitions.dart'; import 'package:recase/recase.dart'; diff --git a/lib/music_view/part_melody_browser.dart b/lib/music_view/part_melody_browser.dart index 4bbcf525..a2468dfa 100644 --- a/lib/music_view/part_melody_browser.dart +++ b/lib/music_view/part_melody_browser.dart @@ -1,6 +1,5 @@ import '../layers_view/melody_menu_browser.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; import 'package:animated_list_plus/transitions.dart'; diff --git a/lib/recording/recording.dart b/lib/recording/recording.dart index 38dcbcc0..3dba0f42 100644 --- a/lib/recording/recording.dart +++ b/lib/recording/recording.dart @@ -3,7 +3,6 @@ import 'dart:collection'; import '../beatscratch_plugin.dart'; import '../generated/protos/music.pb.dart'; import '../generated/protos/protobeats_plugin.pb.dart'; -import '../util/bs_methods.dart'; import '../util/util.dart'; import '../util/proto_utils.dart'; import '../util/music_theory.dart'; diff --git a/lib/settings/settings_common.dart b/lib/settings/settings_common.dart index 8cf206de..73f3e079 100644 --- a/lib/settings/settings_common.dart +++ b/lib/settings/settings_common.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_appavailability/flutter_appavailability.dart'; import '../beatscratch_plugin.dart'; diff --git a/lib/settings/settings_panel.dart b/lib/settings/settings_panel.dart index 36368552..4c6d7b07 100644 --- a/lib/settings/settings_panel.dart +++ b/lib/settings/settings_panel.dart @@ -1,14 +1,11 @@ import 'dart:async'; -import 'dart:ui'; import 'package:dart_midi/dart_midi.dart'; import 'package:dart_midi/src/byte_writer.dart'; import '../messages/messages_ui.dart'; import 'tile_bluetooth.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter_midi_command/flutter_midi_command.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; @@ -16,14 +13,12 @@ import 'package:animated_list_plus/transitions.dart'; import '../beatscratch_plugin.dart'; import '../colors.dart'; -import '../generated/protos/protobeats_plugin.pb.dart'; import '../generated/protos/protos.dart'; import '../music_preview/melody_preview.dart'; import 'app_settings.dart'; import '../storage/universe_manager.dart'; import '../ui_models.dart'; import '../universe_view/universe_icon.dart'; -import '../util/bs_methods.dart'; import '../util/dummydata.dart'; import '../util/midi_theory.dart'; import '../util/util.dart'; diff --git a/lib/settings/tile.dart b/lib/settings/tile.dart index 82909bc0..4f42c631 100644 --- a/lib/settings/tile.dart +++ b/lib/settings/tile.dart @@ -1,8 +1,5 @@ -import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import '../ui_models.dart'; import '../widget/my_buttons.dart'; diff --git a/lib/settings/tile_bluetooth.dart b/lib/settings/tile_bluetooth.dart index c3baaaef..fbebc389 100644 --- a/lib/settings/tile_bluetooth.dart +++ b/lib/settings/tile_bluetooth.dart @@ -1,21 +1,11 @@ -import 'dart:ui'; -import 'package:beatscratch_flutter_redux/beatscratch_plugin.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import '../ui_models.dart'; import '../widget/my_buttons.dart'; -import 'dart:ui'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter_midi_command/flutter_midi_command.dart'; -import '../ui_models.dart'; -import '../widget/my_buttons.dart'; import '../colors.dart'; class BluetoothDeviceTile extends StatefulWidget { diff --git a/lib/settings/tile_controller.dart b/lib/settings/tile_controller.dart index 74d4ca74..070ea11c 100644 --- a/lib/settings/tile_controller.dart +++ b/lib/settings/tile_controller.dart @@ -1,9 +1,7 @@ import 'dart:math'; -import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import '../beatscratch_plugin.dart'; import '../colors.dart'; diff --git a/lib/settings/tile_synth.dart b/lib/settings/tile_synth.dart index 44d7e16f..3cde7312 100644 --- a/lib/settings/tile_synth.dart +++ b/lib/settings/tile_synth.dart @@ -1,8 +1,6 @@ -import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import '../beatscratch_plugin.dart'; import '../colors.dart'; diff --git a/lib/storage/score_manager.dart b/lib/storage/score_manager.dart index 8fbaea86..b8d03013 100644 --- a/lib/storage/score_manager.dart +++ b/lib/storage/score_manager.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; diff --git a/lib/storage/score_picker.dart b/lib/storage/score_picker.dart index c3c0ca5f..c1ae74ff 100644 --- a/lib/storage/score_picker.dart +++ b/lib/storage/score_picker.dart @@ -1,30 +1,23 @@ import 'dart:io'; import 'dart:math'; -import 'dart:ui'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; -import 'package:beatscratch_flutter_redux/storage/url_conversions.dart'; import 'package:beatscratch_flutter_redux/universe_view/universe_icon.dart'; import 'package:flutter/services.dart'; -import 'package:http/http.dart' as http; -import 'package:beatscratch_flutter_redux/music_view/music_system_painter.dart'; import 'package:beatscratch_flutter_redux/storage/score_picker_preview.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'dart:convert'; import '../beatscratch_plugin.dart'; import '../colors.dart'; import '../ui_models.dart'; import '../util/dummydata.dart'; import '../util/bs_methods.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; import 'package:animated_list_plus/transitions.dart'; import '../generated/protos/music.pb.dart'; import '../generated/protos/protobeats_plugin.pb.dart'; -import '../music_preview/score_preview.dart'; import '../util/music_utils.dart'; import '../widget/my_buttons.dart'; import 'score_manager.dart'; diff --git a/lib/storage/score_picker_preview.dart b/lib/storage/score_picker_preview.dart index 9d7d12dc..e6124831 100644 --- a/lib/storage/score_picker_preview.dart +++ b/lib/storage/score_picker_preview.dart @@ -1,21 +1,16 @@ import 'dart:io'; import 'dart:math'; -import 'dart:ui'; -import 'package:beatscratch_flutter_redux/music_view/music_system_painter.dart'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; import 'package:beatscratch_flutter_redux/util/music_notation_theory.dart'; import 'package:beatscratch_flutter_redux/util/util.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import '../beatscratch_plugin.dart'; import '../colors.dart'; import '../generated/protos/music.pb.dart'; import '../music_preview/score_preview.dart'; import '../ui_models.dart'; -import '../util/bs_methods.dart'; import '../util/dummydata.dart'; import '../widget/my_buttons.dart'; import 'score_manager.dart'; diff --git a/lib/storage/universe_manager.dart b/lib/storage/universe_manager.dart index 44019fab..437e1fac 100644 --- a/lib/storage/universe_manager.dart +++ b/lib/storage/universe_manager.dart @@ -5,19 +5,13 @@ import 'package:beatscratch_flutter_redux/util/util.dart'; import 'dart:convert'; import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_icons/flutter_icons.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:http/http.dart' as http; -import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import '../beatscratch_plugin.dart'; import '../colors.dart'; import '../generated/protos/music.pb.dart'; -import '../util/dummydata.dart'; -import '../util/proto_utils.dart'; import '../widget/my_platform.dart'; import 'url_conversions.dart'; diff --git a/lib/ui_models.dart b/lib/ui_models.dart index a0b273d3..b51c8f97 100644 --- a/lib/ui_models.dart +++ b/lib/ui_models.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; enum InteractionMode { view, edit, universe } diff --git a/lib/universe_view/universe_icon.dart b/lib/universe_view/universe_icon.dart index 2811945b..d9ade944 100644 --- a/lib/universe_view/universe_icon.dart +++ b/lib/universe_view/universe_icon.dart @@ -14,8 +14,8 @@ class UniverseIcon extends StatefulWidget { const UniverseIcon( {Key key, - this.sectionColor: Colors.white, - this.interactionMode: InteractionMode.view, + this.sectionColor = Colors.white, + this.interactionMode = InteractionMode.view, this.animateIcon}) : super(key: key); diff --git a/lib/universe_view/universe_upload_dialog.dart b/lib/universe_view/universe_upload_dialog.dart index 1d9de885..b3c3e826 100644 --- a/lib/universe_view/universe_upload_dialog.dart +++ b/lib/universe_view/universe_upload_dialog.dart @@ -1,34 +1,14 @@ -import 'dart:async'; -import 'dart:ui'; import '../music_preview/score_preview.dart'; -import 'package:dart_midi/dart_midi.dart'; -import 'package:dart_midi/src/byte_writer.dart'; -import '../messages/messages_ui.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_midi_command/flutter_midi_command.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:animated_list_plus/animated_list_plus.dart'; -import 'package:animated_list_plus/transitions.dart'; -import '../settings/settings.dart'; -import '../beatscratch_plugin.dart'; import '../colors.dart'; -import '../generated/protos/protobeats_plugin.pb.dart'; import '../generated/protos/protos.dart'; -import '../music_preview/melody_preview.dart'; import '../storage/universe_manager.dart'; import '../ui_models.dart'; -import '../universe_view/universe_icon.dart'; -import '../util/bs_methods.dart'; -import '../util/dummydata.dart'; -import '../util/midi_theory.dart'; import '../util/util.dart'; import '../widget/my_buttons.dart'; -import '../widget/my_platform.dart'; showUniverseUpload(BuildContext context, Score score, Color sectionColor, UniverseManager universeManager, BSMethod onDoDuplicate) { diff --git a/lib/universe_view/universe_view_ui.dart b/lib/universe_view/universe_view_ui.dart index 218945b9..c465dccf 100644 --- a/lib/universe_view/universe_view_ui.dart +++ b/lib/universe_view/universe_view_ui.dart @@ -8,12 +8,7 @@ import '../widget/my_popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; import '../colors.dart'; import '../ui_models.dart'; diff --git a/lib/util/music_utils.dart b/lib/util/music_utils.dart index b89b386e..393659b9 100644 --- a/lib/util/music_utils.dart +++ b/lib/util/music_utils.dart @@ -7,7 +7,7 @@ import '../generated/protos/music.pb.dart'; import 'util.dart'; extension ScoreReKey on Score { - reKeyMelodies({bool andParts: true}) { + reKeyMelodies({bool andParts = true}) { parts.forEach((part) { if (andParts) { part.id = uuid.v4(); diff --git a/lib/util/ui_utils.dart b/lib/util/ui_utils.dart index cb448684..d0e44dbd 100644 --- a/lib/util/ui_utils.dart +++ b/lib/util/ui_utils.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; diff --git a/lib/widget/beats_badge.dart b/lib/widget/beats_badge.dart index 42efc1a0..2ae09751 100644 --- a/lib/widget/beats_badge.dart +++ b/lib/widget/beats_badge.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import '../ui_models.dart'; diff --git a/lib/widget/colorboard.dart b/lib/widget/colorboard.dart index 90eb798d..4db59167 100644 --- a/lib/widget/colorboard.dart +++ b/lib/widget/colorboard.dart @@ -1,6 +1,5 @@ import '../drawing/canvas_tone_drawer.dart'; import '../drawing/color_guide.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../beatscratch_plugin.dart'; import 'package:aeyrium_sensor/aeyrium_sensor.dart'; diff --git a/lib/widget/incrementable_value.dart b/lib/widget/incrementable_value.dart index 26d1cf5b..a7b4f199 100644 --- a/lib/widget/incrementable_value.dart +++ b/lib/widget/incrementable_value.dart @@ -5,12 +5,10 @@ import 'package:beatscratch_flutter_redux/colors.dart'; import '../music_view/music_action_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/rendering.dart'; import 'dart:async'; import 'my_buttons.dart'; -import 'my_platform.dart'; import '../ui_models.dart'; class IncrementableValue extends StatefulWidget { diff --git a/lib/widget/keyboard.dart b/lib/widget/keyboard.dart index b621c893..c3b803d5 100644 --- a/lib/widget/keyboard.dart +++ b/lib/widget/keyboard.dart @@ -6,7 +6,6 @@ import 'package:aeyrium_sensor/aeyrium_sensor.dart'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; import 'package:flutter/services.dart'; import '../drawing/canvas_tone_drawer.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../beatscratch_plugin.dart'; diff --git a/lib/widget/my_buttons.dart b/lib/widget/my_buttons.dart index 82ca9112..bb1101b1 100644 --- a/lib/widget/my_buttons.dart +++ b/lib/widget/my_buttons.dart @@ -1,7 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import '../colors.dart'; class MyFlatButton extends TextButton { MyFlatButton({ @@ -89,7 +86,7 @@ class MyRaisedButton extends ElevatedButton { onPressed: onPressed, onLongPress: onLongPress, style: ElevatedButton.styleFrom( - primary: color, + backgroundColor: color, padding: padding, enabledMouseCursor: SystemMouseCursors.basic, disabledMouseCursor: SystemMouseCursors.basic), diff --git a/lib/widget/my_platform.dart b/lib/widget/my_platform.dart index f8050335..67716a8f 100644 --- a/lib/widget/my_platform.dart +++ b/lib/widget/my_platform.dart @@ -1,6 +1,5 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:package_info_plus/package_info_plus.dart'; class MyPlatform { static final bool isWeb = kIsWeb; diff --git a/lib/widget/scalable_view.dart b/lib/widget/scalable_view.dart index 1c6274e2..80aee137 100644 --- a/lib/widget/scalable_view.dart +++ b/lib/widget/scalable_view.dart @@ -1,9 +1,6 @@ import '../colors.dart'; import '../music_view/music_action_button.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'incrementable_value.dart'; import '../ui_models.dart'; diff --git a/lib/widget/section_list.dart b/lib/widget/section_list.dart index c5f55ae8..1e23fd86 100644 --- a/lib/widget/section_list.dart +++ b/lib/widget/section_list.dart @@ -12,7 +12,6 @@ import 'package:animated_list_plus/transitions.dart'; import '../ui_models.dart'; import '../util/dummydata.dart'; import '../util/music_theory.dart'; -import '../util/util.dart'; import '../colors.dart'; import 'beats_badge.dart'; import 'my_buttons.dart'; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 45616768..2fe5726e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,7 @@ import FlutterMacOS import Foundation import flutter_midi_command -import package_info_plus_macos +import package_info_plus import path_provider_foundation import shared_preferences_foundation import url_launcher_macos diff --git a/pubspec.lock b/pubspec.lock index d10f4cf3..dfddea0c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,14 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - aeyrium_sensor: - dependency: "direct main" - description: - name: aeyrium_sensor - sha256: d031f52388bcff00a86dfe18701ed5dfbaa9714fcda79f31d08382fef4b77fbd - url: "https://pub.dev" - source: hosted - version: "1.0.7" animated_list_plus: dependency: "direct main" description: @@ -21,26 +13,26 @@ packages: dependency: "direct main" description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" base_x: dependency: "direct main" description: name: base_x - sha256: d18b2b5f8271479f0ca0658c5db25573cfff57370e51a1e8563ee8546abf6795 + sha256: "3f1043679659f1759c651f900da6f24f0a8062c28daa6f9625e8d580002e187b" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "2.0.0" boolean_selector: dependency: transitive description: @@ -53,10 +45,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -69,10 +61,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: @@ -85,26 +77,18 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: a937da4c006989739ceb4d10e3bd6cce64ca85d0fe287fc5b2b9f6ee757dcee6 - url: "https://pub.dev" - source: hosted - version: "0.1.3" - dart_midi: - dependency: "direct main" - description: - name: dart_midi - sha256: "9129dc8a202a00dda0a57e428d4940a2d829cb82407c55ba66e10951fbe01187" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.5" dcache: dependency: "direct main" description: @@ -125,10 +109,10 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" file: dependency: transitive description: @@ -149,62 +133,87 @@ packages: dependency: "direct main" description: name: fluro - sha256: "66d82964a1b6967def34155de92f7bb87ee247aba53ea5dbb70e2bf206865dbc" + sha256: "24d07d0b285b213ec2045b83e85d076185fa5c23651e44dae0ac6755784b97d0" url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.0.5" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" - flutter_appavailability: + flutter_keyboard_visibility: dependency: "direct main" description: - name: flutter_appavailability - sha256: "352b9e84b695ee13b0cfb5a9c8eee61c67e2518930ee633bb54ace923d490cee" + name: flutter_keyboard_visibility + sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb" url: "https://pub.dev" source: hosted - version: "0.0.21" - flutter_icons: - dependency: "direct main" + version: "5.4.1" + flutter_keyboard_visibility_linux: + dependency: transitive description: - name: flutter_icons - sha256: ad1c830f729c71216372d1a8d62c08c6dd792227d9492d5130aea5e391210a9f + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" url: "https://pub.dev" source: hosted - version: "1.1.0" - flutter_keyboard_visibility: - dependency: "direct main" + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive description: - name: flutter_keyboard_visibility - sha256: "5aa7937e11b2e0ae203e01b4cd2ac5d3cd601bd16f58b315908fbf29362c29db" + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 url: "https://pub.dev" source: hosted version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" + source: hosted + version: "1.0.0" flutter_midi_command: dependency: "direct main" description: - path: "../FlutterMidiCommand" - relative: true - source: path - version: "0.3.7" + name: flutter_midi_command + sha256: "7954d279119f190a0147a0bf4d69509abf8074a9a9a6b3d2e6c3805374b93ed1" + url: "https://pub.dev" + source: hosted + version: "0.4.11" flutter_midi_command_platform_interface: dependency: transitive description: name: flutter_midi_command_platform_interface - sha256: "57607a3cf7169f7a7de2d09b2fbac2beefa34f2b4cec5764c1367d59616f74a3" + sha256: cb250720a36d55252ff22612752bd2fb69e8308e9a75e1cb8ef4e0ee0134d77f url: "https://pub.dev" source: hosted - version: "0.3.4" + version: "0.4.0" flutter_reorderable_list: dependency: "direct main" description: name: flutter_reorderable_list - sha256: "7bb60836a2712fffa23dc71d86ae3c77c72d216ef818b4c7b764424c4f28cafe" + sha256: "0400ef34fa00b7cac69f71efc92d7e49727f425bc1080180ebe70bf47618afe0" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" flutter_test: dependency: "direct dev" description: flutter @@ -219,18 +228,18 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "444af62d91e753b1e221d9f3e2f8df48a995962f33bef77773059cec4dac2c47" + sha256: "5fb789145cae1f4c3245c58b3f8fb287d055c26323879eab57a7bf0cfd1e45f3" url: "https://pub.dev" source: hosted - version: "8.12.0" + version: "10.5.0" http: dependency: "direct main" description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.1.0" http_parser: dependency: transitive description: @@ -243,18 +252,18 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -275,26 +284,18 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" - mime: - dependency: transitive - description: - name: mime - sha256: "5041f313f4e30fbd70dee7c0403785a4ee270f75830f590e5983960fddf743e4" - url: "https://pub.dev" - source: hosted - version: "0.9.7" + version: "1.9.1" native_device_orientation: dependency: "direct main" description: name: native_device_orientation - sha256: "4a17190b356d11ef2fce4137578e0fd102990e260f8c03c2ca6bb9a457b17495" + sha256: "7d2fa1a1420b7b4ac3317760ffd063b86704679fb4f1796644581da4a6356ccc" url: "https://pub.dev" source: hosted - version: "0.4.3" + version: "1.1.4" nested: dependency: transitive description: @@ -307,122 +308,90 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: f62d7253edc197fe3c88d7c2ddab82d68f555e778d55390ccc3537eca8e8d637 + sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b url: "https://pub.dev" source: hosted - version: "1.4.3+1" - package_info_plus_linux: - dependency: transitive - description: - name: package_info_plus_linux - sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - package_info_plus_macos: - dependency: transitive - description: - name: package_info_plus_macos - sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6 - url: "https://pub.dev" - source: hosted - version: "1.3.0" + version: "4.0.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8 + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" url: "https://pub.dev" source: hosted - version: "1.0.2" - package_info_plus_web: - dependency: transitive - description: - name: package_info_plus_web - sha256: f0829327eb534789e0a16ccac8936a80beed4e2401c4d3a74f3f39094a822d3b - url: "https://pub.dev" - source: hosted - version: "1.0.6" - package_info_plus_windows: - dependency: transitive - description: - name: package_info_plus_windows - sha256: "79524f11c42dd9078b96d797b3cf79c0a2883a50c4920dc43da8562c115089bc" - url: "https://pub.dev" - source: hosted - version: "2.1.0" + version: "2.0.1" path: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_drawing: dependency: "direct main" description: name: path_drawing - sha256: f084d82ffbbf8b6f7557987929032fd5b9a9f8e8dc0ab72036591f50389347db + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "1.0.1" path_parsing: dependency: transitive description: name: path_parsing - sha256: "4e613c811d25f1533c0d05eb2755e21410247b8a13ac7f6cd23c0cecb2ff683d" + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "1.0.1" path_provider: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.4" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.7" platform: dependency: transitive description: @@ -435,34 +404,26 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.5" pointycastle: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" + version: "3.7.3" protobuf: dependency: "direct main" description: name: protobuf - sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08" + sha256: "4034a02b7e231e7e60bff30a8ac13a7347abfdac0798595fae0b90a3f0afe759" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.0" provider: dependency: "direct main" description: @@ -483,82 +444,74 @@ packages: dependency: "direct main" description: name: recase - sha256: d18e5f9cb089cbf535cf4b772c83ca967b77b62dd9570bcd14d762cfb7590586 + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.1.0" sensors: dependency: "direct main" description: name: sensors - sha256: "60442084bbdbfca4c8b8392ebc49acd457cf47e09229f7e1726079b2f37c73f1" + sha256: "69c10fe94a63dd7c6f5e6557366e5329a713bf6c45d885d95a56642dd8722e35" url: "https://pub.dev" source: hosted - version: "0.4.2+6" - share: - dependency: "direct main" - description: - name: share - sha256: fc1647d0c3a8eb648dc6d91d2207e7976c1d941e2165a09cba7c805b0c24467e - url: "https://pub.dev" - source: hosted - version: "0.6.5+4" + version: "2.0.3" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0" + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" sky_engine: dependency: transitive description: flutter @@ -608,82 +561,82 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted - version: "6.1.8" + version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" url: "https://pub.dev" source: hosted - version: "6.0.23" + version: "6.0.37" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" url: "https://pub.dev" source: hosted - version: "6.0.18" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted - version: "2.0.14" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.7" uuid: dependency: "direct main" description: @@ -704,50 +657,50 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "392c1d83b70fe2495de3ea2c84531268d5b8de2de3f01086a53334d8b6030a88" + sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "4.2.2" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "8b3b2450e98876c70bfcead876d9390573b34b9418c19e28168b74f6cb252dbd" + sha256: d936a09fbfd08cb78f7329e0bbacf6158fbdfe24ffc908b22444c07d295eb193 url: "https://pub.dev" source: hosted - version: "2.10.4" + version: "3.9.2" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "812165e4e34ca677bdfbfa58c01e33b27fd03ab5fa75b70832d4b7d4ca1fa8cf" + sha256: "564ef378cafc1a0e29f1d76ce175ef517a0a6115875dff7b43fccbef2b0aeb30" url: "https://pub.dev" source: hosted - version: "1.9.5" + version: "2.4.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: a5364369c758892aa487cbf59ea41d9edd10f9d9baf06a94e80f1bd1b4c7bbc0 + sha256: "5fa098f28b606f699e8ca52d9e4e11edbbfef65189f5f77ae92703ba5408fd25" url: "https://pub.dev" source: hosted - version: "2.9.5" + version: "3.7.2" win32: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "5.0.6" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.0.1" sdks: - dart: ">=2.19.0 <3.0.0" - flutter: ">=3.7.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3df08d64..e32f084e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,43 +5,44 @@ publish_to: none version: 1.7.5+480 environment: - sdk: ">=2.6.0 <3.0.0" + sdk: ">=2.17.1 <3.0.0" + # sdk: ">=2.6.0 <3.0.0" dependencies: flutter: sdk: flutter - http: ^0.13.3 - protobuf: ^2.0.0 + http: ^1.1.0 + protobuf: ^3.0.0 uuid: ^3.0.4 - package_info_plus: ^1.0.1 - recase: ^3.0.0 - share: ^0.6.5+4 + package_info_plus: ^4.0.2 + recase: ^4.1.0 + # share: ^0.6.5+4 flutter_reorderable_list: ^1.2.0 url_launcher: ^6.0.3 animated_list_plus: ^0.5.0 - flutter_keyboard_visibility: ^2.0.0 - aeyrium_sensor: ^1.0.7 - sensors: '>=0.4.1+10 <2.0.0' - dart_midi: 1.0.1 + flutter_keyboard_visibility: ^5.4.1 + # aeyrium_sensor: ^1.0.7 + sensors: ^2.0.3 + # dart_midi: 1.0.1 quiver: ^3.0.1 - path_drawing: 0.4.1 + path_drawing: 1.0.1 path_provider: ^2.0.2 shared_preferences: ^2.0.6 - base_x: ^1.0.1 + base_x: ^2.0.0 archive: ^3.1.2 - font_awesome_flutter: ^8.11.0 - cupertino_icons: ^0.1.2 + font_awesome_flutter: ^10.5.0 + cupertino_icons: ^1.0.5 fluro: "^2.0.3" - flutter_appavailability: ^0.0.21 - native_device_orientation: ^0.4.3 - webview_flutter: ^3.0.4 - flutter_icons: ^1.1.0 + # flutter_appavailability: ^0.0.21 + native_device_orientation: ^1.1.4 + webview_flutter: ^4.2.2 + # flutter_icons: ^1.1.0 # flutter_blue: ^0.8.0 # path: ../flutter_blue # flutter_reactive_ble: #^3.1.0 # path: ../flutter_reactive_ble - flutter_midi_command: #^0.3.0 - path: ../FlutterMidiCommand + flutter_midi_command: ^0.4.11 + # path: ../FlutterMidiCommand dcache: ^0.4.0 provider: ^6.0.2 matrix4_transform: ^2.0.1 From 05ae0da1333802e8a0a2b682713e6ed2fd3ba224 Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 30 Jul 2023 20:46:38 -0400 Subject: [PATCH 02/11] @required -> required --- lib/animations/size_fade_transition.dart | 2 +- lib/edit_menu.dart | 16 ++--- lib/export/export_ui.dart | 16 ++--- lib/main_menu.dart | 10 +-- lib/main_toolbars.dart | 84 +++++++++++----------- lib/messages/bs_message.dart | 6 +- lib/messages/messages_ui.dart | 10 +-- lib/music_preview/melody_preview.dart | 6 +- lib/music_preview/preview_renderer.dart | 14 ++-- lib/music_view/melody_editing_toolbar.dart | 18 ++--- lib/music_view/music_action_button.dart | 78 ++++++++++++-------- lib/music_view/music_view.dart | 26 +++---- lib/settings/settings_panel.dart | 26 +++---- lib/settings/tile_bluetooth.dart | 16 ++--- lib/universe_view/universe_view_ui.dart | 18 ++--- lib/widget/my_buttons.dart | 10 +-- lib/widget/my_popup_menu.dart | 14 ++-- 17 files changed, 193 insertions(+), 177 deletions(-) diff --git a/lib/animations/size_fade_transition.dart b/lib/animations/size_fade_transition.dart index f9d91ea1..b24e727a 100644 --- a/lib/animations/size_fade_transition.dart +++ b/lib/animations/size_fade_transition.dart @@ -9,7 +9,7 @@ // final Widget child; // const SizeFadeTransition({ // Key key, -// @required this.animation, +// required this.animation, // this.sizeFraction = 0, // this.curve = Curves.linear, // this.axis = Axis.vertical, diff --git a/lib/edit_menu.dart b/lib/edit_menu.dart index 140d0346..ecbcb597 100644 --- a/lib/edit_menu.dart +++ b/lib/edit_menu.dart @@ -10,14 +10,14 @@ import 'ui_models.dart'; import 'widget/beats_badge.dart'; Future showEditMenu( - {@required BuildContext context, - @required RelativeRect position, - @required Score score, - @required Part part, - @required Melody selectedMelody, - @required MusicViewMode musicViewMode, - @required Section section, - @required Function(Object) editObject}) async { + {required BuildContext context, + required RelativeRect position, + required Score score, + required Part part, + required Melody selectedMelody, + required MusicViewMode musicViewMode, + required Section section, + required Function(Object) editObject}) async { onSelected(Object object) { Navigator.pop(context); editObject(object); diff --git a/lib/export/export_ui.dart b/lib/export/export_ui.dart index 0691876c..bf2c502e 100644 --- a/lib/export/export_ui.dart +++ b/lib/export/export_ui.dart @@ -3,7 +3,7 @@ import '../beatscratch_plugin.dart'; import '../generated/protos/music.pb.dart'; import '../messages/messages_ui.dart'; import '../util/dummydata.dart'; -import 'package:share/share.dart'; +// import 'package:share/share.dart'; import '../util/util.dart'; @@ -24,7 +24,7 @@ class ExportUI { static final double _baseHeight = 220; static final double _progressHeight = 30; - static Widget exportIcon({double size = 24, Color color}) => + static Widget exportIcon({double size = 24, Color? color}) => Transform.translate( offset: Offset(size * 2 / 24, 0), child: Icon(MyPlatform.isAppleOS ? CupertinoIcons.share : Icons.share, @@ -44,9 +44,9 @@ class ExportUI { double get height => baseHeight + progressHeight; Widget build( - {@required BuildContext context, - @required Function(VoidCallback) setState, - @required Section currentSection}) { + {required BuildContext context, + required Function(VoidCallback) setState, + required Section currentSection}) { return AnimatedContainer( duration: animationDuration, height: height, @@ -269,9 +269,9 @@ class ExportUI { EdgeInsets.only(left: 5, top: 5, bottom: 5); SingleChildScrollView exportOptions( - {@required BuildContext context, - @required Function(VoidCallback) setState, - @required Section currentSection}) { + {required BuildContext context, + required Function(VoidCallback) setState, + required Section currentSection}) { double width = MediaQuery.of(context).size.width; double scrollContainerWidth = width - 44; double exportTypeWidth = 100; diff --git a/lib/main_menu.dart b/lib/main_menu.dart index 833a67d5..21762e33 100644 --- a/lib/main_menu.dart +++ b/lib/main_menu.dart @@ -10,11 +10,11 @@ import 'generated/protos/protos.dart'; import 'widget/my_platform.dart'; Future showMainMenu( - {@required BuildContext context, - @required RelativeRect position, - @required bool showDownloads, - @required Score currentScore, - @required String currentScoreName}) async { + {required BuildContext context, + required RelativeRect position, + required bool showDownloads, + required Score currentScore, + required String currentScoreName}) async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); return showMenu( diff --git a/lib/main_toolbars.dart b/lib/main_toolbars.dart index 309f7f9a..bc0a7022 100644 --- a/lib/main_toolbars.dart +++ b/lib/main_toolbars.dart @@ -71,48 +71,48 @@ class BeatScratchToolbar extends StatefulWidget { final Function(Object) editObject; const BeatScratchToolbar( {Key key, - @required this.appSettings, - @required this.universeManager, - @required this.interactionMode, - @required this.musicViewMode, - @required this.viewMode, - @required this.universeMode, - @required this.editMode, - @required this.toggleViewOptions, - @required this.sectionColor, - @required this.togglePlaying, - @required this.toggleSectionListDisplayMode, - @required this.setRenderingMode, - @required this.renderingMode, - @required this.showMidiInputSettings, - @required this.showBeatCounts, - @required this.toggleShowBeatCounts, - @required this.showScorePicker, - @required this.saveCurrentScore, - @required this.currentScoreName, - @required this.score, - @required this.pasteScore, - @required this.export, - @required this.scoreManager, - @required this.routeToCurrentScore, - @required this.vertical, - @required this.showSections, - @required this.verticalSections, - @required this.openMelody, - @required this.prevMelody, - @required this.openPart, - @required this.prevPart, - @required this.isMelodyViewOpen, - @required this.currentSection, - @required this.currentPart, - @required this.leftHalfOnly, - @required this.rightHalfOnly, - @required this.savingScore, // BeatScratchPlugin.isSynthesizerAvailable - @required this.messagesUI, - @required this.showDownloads, - @required this.toggleShowDownloads, - @required this.refreshUniverseData, - @required this.editObject}) + required this.appSettings, + required this.universeManager, + required this.interactionMode, + required this.musicViewMode, + required this.viewMode, + required this.universeMode, + required this.editMode, + required this.toggleViewOptions, + required this.sectionColor, + required this.togglePlaying, + required this.toggleSectionListDisplayMode, + required this.setRenderingMode, + required this.renderingMode, + required this.showMidiInputSettings, + required this.showBeatCounts, + required this.toggleShowBeatCounts, + required this.showScorePicker, + required this.saveCurrentScore, + required this.currentScoreName, + required this.score, + required this.pasteScore, + required this.export, + required this.scoreManager, + required this.routeToCurrentScore, + required this.vertical, + required this.showSections, + required this.verticalSections, + required this.openMelody, + required this.prevMelody, + required this.openPart, + required this.prevPart, + required this.isMelodyViewOpen, + required this.currentSection, + required this.currentPart, + required this.leftHalfOnly, + required this.rightHalfOnly, + required this.savingScore, // BeatScratchPlugin.isSynthesizerAvailable + required this.messagesUI, + required this.showDownloads, + required this.toggleShowDownloads, + required this.refreshUniverseData, + required this.editObject}) : super(key: key); @override diff --git a/lib/messages/bs_message.dart b/lib/messages/bs_message.dart index 2006d312..b94511e6 100644 --- a/lib/messages/bs_message.dart +++ b/lib/messages/bs_message.dart @@ -8,9 +8,9 @@ class BSMessage { bool visible = false; BSMessage({ - @required this.id, - @required this.message, + required this.id, + required this.message, this.timeout = const Duration(milliseconds: 500), - @required this.icon, + required this.icon, }); } diff --git a/lib/messages/messages_ui.dart b/lib/messages/messages_ui.dart index 5a860c8b..b9229a3e 100644 --- a/lib/messages/messages_ui.dart +++ b/lib/messages/messages_ui.dart @@ -18,7 +18,7 @@ class MessagesUI { messages.where((m) => m.visible).length * _messageHeight(context); BSMessage sendMessage({ - @required message, + required message, icon, color, timeout = const Duration(milliseconds: 5500), @@ -62,8 +62,8 @@ class MessagesUI { _removeMessage( BSMessage bsMessage, { - @required icon, - @required message, + required icon, + required message, }) { setAppState(() { bsMessage.visible = false; @@ -75,7 +75,7 @@ class MessagesUI { }); } - Widget build({@required BuildContext context}) { + Widget build({required BuildContext context}) { return Column( children: messages .map((m) => buildMessage(m, context: context)) @@ -84,7 +84,7 @@ class MessagesUI { Widget buildMessage( BSMessage message, { - @required BuildContext context, + required BuildContext context, }) { return AnimatedContainer( duration: animationDuration, diff --git a/lib/music_preview/melody_preview.dart b/lib/music_preview/melody_preview.dart index 2cac1f5e..2d19e0f3 100644 --- a/lib/music_preview/melody_preview.dart +++ b/lib/music_preview/melody_preview.dart @@ -30,9 +30,9 @@ class MelodyPreview extends StatefulWidget { static Gradient generateVolumeDecoration( MelodyReference reference, Section section, - {@required bool isSelectedMelody, - @required Color bgColor, - @required Color sectionColor}) { + {required bool isSelectedMelody, + required Color bgColor, + required Color sectionColor}) { if (reference.isEnabled) { Color volumeColor = isSelectedMelody ? Colors.white diff --git a/lib/music_preview/preview_renderer.dart b/lib/music_preview/preview_renderer.dart index 4844b006..683c2bf6 100644 --- a/lib/music_preview/preview_renderer.dart +++ b/lib/music_preview/preview_renderer.dart @@ -23,13 +23,13 @@ class MusicPreviewRenderer { Score get score => Score.fromBuffer(scoreData); MusicPreviewRenderer( - {@required this.scoreData, - @required this.scale, - @required this.width, - @required this.height, - @required this.renderSections, - @required this.renderPartNames, - @required this.musicViewMode, + {required this.scoreData, + required this.scale, + required this.width, + required this.height, + required this.renderSections, + required this.renderPartNames, + required this.musicViewMode, this.renderColor}); MusicSystemPainter get painter { diff --git a/lib/music_view/melody_editing_toolbar.dart b/lib/music_view/melody_editing_toolbar.dart index 4969f477..6275c38c 100644 --- a/lib/music_view/melody_editing_toolbar.dart +++ b/lib/music_view/melody_editing_toolbar.dart @@ -28,15 +28,15 @@ class MelodyEditingToolbar extends StatefulWidget { const MelodyEditingToolbar( {Key key, - @required this.melodyId, - @required this.sectionColor, - @required this.score, - @required this.currentSection, - @required this.highlightedBeat, - @required this.setReferenceVolume, - @required this.recordingMelody, - @required this.visible, - @required this.toggleRecording}) + required this.melodyId, + required this.sectionColor, + required this.score, + required this.currentSection, + required this.highlightedBeat, + required this.setReferenceVolume, + required this.recordingMelody, + required this.visible, + required this.toggleRecording}) : super(key: key); @override diff --git a/lib/music_view/music_action_button.dart b/lib/music_view/music_action_button.dart index 0688033f..8029b5b7 100644 --- a/lib/music_view/music_action_button.dart +++ b/lib/music_view/music_action_button.dart @@ -13,43 +13,61 @@ class MusicActionButton extends StatelessWidget { final Color color; MusicActionButton( - {Key key, this.visible = true, this.width = 48, this.height = 48, @required this.child, @required this.onPressed, this.color = Colors.black26}) - : super(key: key); + {Key key, + this.visible = true, + this.width = 48, + this.height = 48, + required this.child, + required this.onPressed, + this.color = Colors.black26}) + : super(key: key); @override Widget build(BuildContext context) { double width = this.width, height = this.height; - if (!visible && width != null && height != null && width != 0 && height != 0) { + if (!visible && + width != null && + height != null && + width != 0 && + height != 0) { width = 0; height = 0; } return AnimatedOpacity( - duration: animationDuration, - opacity: visible ? 1 : 0, - child: Stack(children: [ - AnimatedContainer( - duration: animationDuration, height: height, width: width, child: SizedBox()), - Positioned( - top: .1, - left: 0, - width: width, - height: height, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - child: IgnorePointer( - ignoring: !visible, - child: AnimatedContainer( - duration: animationDuration, - color: color, - height: height, - width: width, - child: SizedBox())))), - AnimatedContainer( - duration: animationDuration, - color: color, - height: height, - width: width, - child: onPressed == null ? child : MyFlatButton(onPressed: onPressed, padding: EdgeInsets.zero, child: child)) - ])); + duration: animationDuration, + opacity: visible ? 1 : 0, + child: Stack(children: [ + AnimatedContainer( + duration: animationDuration, + height: height, + width: width, + child: SizedBox()), + Positioned( + top: .1, + left: 0, + width: width, + height: height, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: IgnorePointer( + ignoring: !visible, + child: AnimatedContainer( + duration: animationDuration, + color: color, + height: height, + width: width, + child: SizedBox())))), + AnimatedContainer( + duration: animationDuration, + color: color, + height: height, + width: width, + child: onPressed == null + ? child + : MyFlatButton( + onPressed: onPressed, + padding: EdgeInsets.zero, + child: child)) + ])); } } diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index d55e1500..ae56162b 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -237,10 +237,10 @@ class _MusicViewState extends State with TickerProviderStateMixin { } _startValueAnimation( - {@required double Function() value, - @required double Function() currentValue, - @required Function(double) applyAnimatedValue, - @required List controllers, + {required double Function() value, + required double Function() currentValue, + required Function(double) applyAnimatedValue, + required List controllers, VoidCallback onComplete}) { if (value() == currentValue()) { // print("skipping scale animation: no change (${currentValue()} to ${value()}"); @@ -324,12 +324,12 @@ class _MusicViewState extends State with TickerProviderStateMixin { } _animateScaleAtomically({ - @required DateTime Function() getLockTime, - @required Function(DateTime) setLockTime, - @required double Function() value, - @required double Function() currentValue, - @required Function(double) applyAnimatedValue, - @required List controllers, + required DateTime Function() getLockTime, + required Function(DateTime) setLockTime, + required double Function() value, + required double Function() currentValue, + required Function(double) applyAnimatedValue, + required List controllers, }) { if (value() == currentValue()) { return; @@ -1606,7 +1606,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { } } - Widget autoScrollButton({@required bool visible}) { + Widget autoScrollButton({required bool visible}) { return MusicActionButton( child: Stack(children: [ Transform.translate( @@ -1645,7 +1645,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { ); } - Widget nightModeButton({@required bool visible}) { + Widget nightModeButton({required bool visible}) { return MusicActionButton( child: Icon(FontAwesomeIcons.solidMoon, color: musicForegroundColor), color: musicBackgroundColor.withOpacity(0.12), @@ -1657,7 +1657,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { ); } - Widget colorblockButton({@required bool visible}) { + Widget colorblockButton({required bool visible}) { return MusicActionButton( child: Stack(children: [ AnimatedOpacity( diff --git a/lib/settings/settings_panel.dart b/lib/settings/settings_panel.dart index 4c6d7b07..f6924955 100644 --- a/lib/settings/settings_panel.dart +++ b/lib/settings/settings_panel.dart @@ -46,19 +46,19 @@ class SettingsPanel extends StatefulWidget { const SettingsPanel( {Key key, - @required this.appSettings, - @required this.universeManager, - @required this.sectionColor, - @required this.close, - @required this.enableColorboard, - @required this.setColorboardEnabled, - @required this.toggleKeyboardConfig, - @required this.toggleColorboardConfig, - @required this.bluetoothScan, - @required this.visible, - @required this.messagesUI, - @required this.bluetoothControllerPressedNotes, - @required this.keyboardPart}) + required this.appSettings, + required this.universeManager, + required this.sectionColor, + required this.close, + required this.enableColorboard, + required this.setColorboardEnabled, + required this.toggleKeyboardConfig, + required this.toggleColorboardConfig, + required this.bluetoothScan, + required this.visible, + required this.messagesUI, + required this.bluetoothControllerPressedNotes, + required this.keyboardPart}) : super(key: key); @override diff --git a/lib/settings/tile_bluetooth.dart b/lib/settings/tile_bluetooth.dart index fbebc389..a89d5dde 100644 --- a/lib/settings/tile_bluetooth.dart +++ b/lib/settings/tile_bluetooth.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import '../ui_models.dart'; @@ -16,17 +15,16 @@ class BluetoothDeviceTile extends StatefulWidget { final VoidCallback onConnect, onDisconnect; final Color sectionColor; final bool connected; - final ValueNotifier>> - bluetoothControllerPressedNotes; + final ValueNotifier>> bluetoothControllerPressedNotes; const BluetoothDeviceTile( {Key key, - @required this.connected, - @required this.device, - @required this.sectionColor, - @required this.onConnect, - @required this.onDisconnect, - @required this.bluetoothControllerPressedNotes}) + required this.connected, + required this.device, + required this.sectionColor, + required this.onConnect, + required this.onDisconnect, + required this.bluetoothControllerPressedNotes}) : super(key: key); @override diff --git a/lib/universe_view/universe_view_ui.dart b/lib/universe_view/universe_view_ui.dart index c465dccf..a8b04862 100644 --- a/lib/universe_view/universe_view_ui.dart +++ b/lib/universe_view/universe_view_ui.dart @@ -36,25 +36,25 @@ class UniverseViewUI { } double toolbarHeight(BuildContext context, - {@required double keyboardHeight, @required double settingsHeight}) => + {required double keyboardHeight, required double settingsHeight}) => visible ? 44 : 0; double authFormHeight(BuildContext context, - {@required double keyboardHeight, @required double settingsHeight}) => + {required double keyboardHeight, required double settingsHeight}) => visible && signingIn ? 200 : 0; double height(BuildContext context, - {@required double keyboardHeight, @required double settingsHeight}) => + {required double keyboardHeight, required double settingsHeight}) => toolbarHeight(context, keyboardHeight: keyboardHeight, settingsHeight: settingsHeight) + authFormHeight(context, keyboardHeight: keyboardHeight, settingsHeight: settingsHeight); Widget build( - {@required BuildContext context, - @required Color sectionColor, - @required double keyboardHeight, - @required double settingsHeight, - @required VoidCallback showDownloads, - @required double scorePickerWidth}) { + {required BuildContext context, + required Color sectionColor, + required double keyboardHeight, + required double settingsHeight, + required VoidCallback showDownloads, + required double scorePickerWidth}) { double abbreviateAtWidth = 340; return AnimatedOpacity( duration: animationDuration, diff --git a/lib/widget/my_buttons.dart b/lib/widget/my_buttons.dart index bb1101b1..7f169ca1 100644 --- a/lib/widget/my_buttons.dart +++ b/lib/widget/my_buttons.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; class MyFlatButton extends TextButton { MyFlatButton({ Key key, - @required VoidCallback onPressed, + required VoidCallback onPressed, VoidCallback onLongPress, ValueChanged onHighlightChanged, MouseCursor mouseCursor = SystemMouseCursors.basic, @@ -15,7 +15,7 @@ class MyFlatButton extends TextButton { bool autofocus = false, ButtonStyle style, bool lightHighlight = false, - @required Widget child, + required Widget child, }) : assert(clipBehavior != null), assert(autofocus != null), super( @@ -46,7 +46,7 @@ class MyFlatButton extends TextButton { class MyRaisedButton extends ElevatedButton { MyRaisedButton({ Key key, - @required VoidCallback onPressed, + required VoidCallback onPressed, VoidCallback onLongPress, ValueChanged onHighlightChanged, MouseCursor mouseCursor = SystemMouseCursors.basic, @@ -102,8 +102,8 @@ class MyRaisedButton extends ElevatedButton { class MySlider extends Slider { const MySlider({ Key key, - @required double value, - @required ValueChanged onChanged, + required double value, + required ValueChanged onChanged, ValueChanged onChangeStart, ValueChanged onChangeEnd, double min = 0.0, diff --git a/lib/widget/my_popup_menu.dart b/lib/widget/my_popup_menu.dart index 4ebe8b27..ef3f9ca3 100644 --- a/lib/widget/my_popup_menu.dart +++ b/lib/widget/my_popup_menu.dart @@ -146,7 +146,7 @@ class _PopupMenuDividerState extends State { class _MenuItem extends SingleChildRenderObjectWidget { const _MenuItem({ Key key, - @required this.onLayout, + required this.onLayout, Widget child, }) : assert(onLayout != null), super(key: key, child: child); @@ -238,7 +238,7 @@ class PopupMenuItem extends PopupMenuEntry { this.height = kMinInteractiveDimension, this.textStyle, this.mouseCursor, - @required this.child, + required this.child, }) : assert(enabled != null), assert(height != null), super(key: key); @@ -298,7 +298,7 @@ class MyPopupMenuItem extends PopupMenuItem { double height = kMinInteractiveDimension, TextStyle textStyle, MouseCursor mouseCursor = SystemMouseCursors.basic, - @required Widget child, + required Widget child, }) : super( key: key, value: value, @@ -887,9 +887,9 @@ class _PopupMenuRoute extends PopupRoute { /// * [SemanticsConfiguration.namesRoute], for a description of edge triggered /// semantics. Future showMenu({ - @required BuildContext context, - @required RelativeRect position, - @required List> items, + required BuildContext context, + required RelativeRect position, + required List> items, T initialValue, double elevation, String semanticLabel, @@ -1015,7 +1015,7 @@ class MyPopupMenuButton extends StatefulWidget { /// The [itemBuilder] argument must not be null. const MyPopupMenuButton({ Key key, - @required this.itemBuilder, + required this.itemBuilder, this.initialValue, this.onSelected, this.onCanceled, From 04c964af80eb919fababc0dc1d9a5d9031ceeafd Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 11 May 2025 18:49:46 -0400 Subject: [PATCH 03/11] progress --- ios/Runner.xcodeproj/project.pbxproj | 3 +- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- ios/Runner/AppDelegate.swift | 2 +- lib/beatscratch_plugin.dart | 60 +-- lib/cache_management.dart | 5 +- lib/drawing/harmony_beat_renderer.dart | 4 +- .../music/notation_music_renderer.dart | 83 ++-- lib/drawing/sizeutil.dart | 41 -- lib/edit_menu.dart | 6 +- lib/export/export_manager.dart | 20 +- lib/export/export_models.dart | 20 +- lib/export/export_ui.dart | 52 ++- lib/generated/i18n.dart | 70 ++-- lib/layers_view/layers_part_view.dart | 11 +- lib/layers_view/layers_view.dart | 66 ++- lib/layers_view/melody_menu_browser.dart | 78 ++-- lib/layers_view/melody_reference_view.dart | 52 +-- lib/main.dart | 164 ++------ lib/main_menu.dart | 16 +- lib/main_toolbars.dart | 141 +++---- lib/messages/messages_ui.dart | 3 - lib/midi/byte_reader.dart | 95 +++++ lib/midi/byte_writer.dart | 85 ++++ lib/midi/data_chunk.dart | 6 + lib/midi/midi_events.dart | 390 ++++++++++++++++++ lib/midi/midi_file.dart | 8 + lib/midi/midi_header.dart | 16 + lib/midi/midi_parser.dart | 342 +++++++++++++++ lib/midi/midi_writer.dart | 80 ++++ lib/music_preview/melody_preview.dart | 2 +- lib/music_preview/preview_renderer.dart | 7 +- lib/music_preview/score_preview.dart | 11 +- lib/music_view/melody_editing_toolbar.dart | 49 +-- lib/music_view/music_action_button.dart | 6 +- lib/music_view/music_scroll_container.dart | 36 +- lib/music_view/music_system_painter.dart | 166 ++++---- lib/music_view/music_toolbars.dart | 61 ++- lib/music_view/music_view.dart | 86 ++-- lib/music_view/part_instrument_picker.dart | 20 +- lib/music_view/part_melody_browser.dart | 2 +- lib/recording/recording.dart | 28 +- lib/settings/app_settings.dart | 79 ++-- lib/settings/settings_common.dart | 2 +- lib/settings/settings_panel.dart | 30 +- lib/settings/tile.dart | 22 +- lib/storage/migrations.dart | 4 +- lib/storage/score_manager.dart | 47 +-- lib/storage/score_picker.dart | 38 +- lib/storage/score_picker_preview.dart | 70 ++-- lib/storage/universe_manager.dart | 71 ++-- lib/universe_view/universe_icon.dart | 2 +- lib/util/dummydata.dart | 2 +- lib/util/language_utils.dart | 2 +- lib/util/methodcache_utils.dart | 10 +- lib/util/midi_theory.dart | 35 +- lib/util/music_notation_theory.dart | 51 +-- lib/util/music_theory.dart | 41 +- lib/util/music_utils.dart | 25 +- lib/util/proto_utils.dart | 10 +- lib/util/ui_utils.dart | 43 +- lib/widget/beats_badge.dart | 7 +- lib/widget/color_filtered_image_asset.dart | 3 +- lib/widget/incrementable_value.dart | 8 +- lib/widget/my_buttons.dart | 112 +++-- lib/widget/my_popup_menu.dart | 262 ++++++------ lib/widget/scalable_view.dart | 15 +- lib/widget/section_list.dart | 52 +-- macos/Flutter/GeneratedPluginRegistrant.swift | 6 +- pubspec.lock | 372 ++++++++++------- pubspec.yaml | 2 + 70 files changed, 2278 insertions(+), 1541 deletions(-) delete mode 100644 lib/drawing/sizeutil.dart create mode 100644 lib/midi/byte_reader.dart create mode 100644 lib/midi/byte_writer.dart create mode 100644 lib/midi/data_chunk.dart create mode 100644 lib/midi/midi_events.dart create mode 100644 lib/midi/midi_file.dart create mode 100644 lib/midi/midi_header.dart create mode 100644 lib/midi/midi_parser.dart create mode 100644 lib/midi/midi_writer.dart diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 462402ae..c87c0a22 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -251,7 +251,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -301,6 +301,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a3..c53e2b31 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 1b16e3e8..02ba4be4 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -4,7 +4,7 @@ import AVFoundation import Foundation import AudioKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { var flutterViewController: FlutterViewController? diff --git a/lib/beatscratch_plugin.dart b/lib/beatscratch_plugin.dart index fd64b28e..18d8c923 100644 --- a/lib/beatscratch_plugin.dart +++ b/lib/beatscratch_plugin.dart @@ -1,4 +1,3 @@ - import 'package:dart_midi/dart_midi.dart'; // ignore: implementation_imports import 'package:dart_midi/src/byte_writer.dart'; @@ -59,7 +58,7 @@ class BeatScratchPlugin { case "notifyCountInInitiated": _playing = false; _countInInitiated = true; - onCountInInitiated?.call(); + onCountInInitiated.call(); return Future.value(null); break; case "notifyCurrentSection": @@ -120,20 +119,14 @@ class BeatScratchPlugin { } static _notifyScoreUrlOpened(String url) { - if (onOpenUrlFromSystem != null) { - onOpenUrlFromSystem(url); - } else { - Future.delayed(Duration(milliseconds: 500), () { - _notifyScoreUrlOpened(url); - }); - } + onOpenUrlFromSystem(url); } static _notifyMidiDevices(MidiDevices devices) { connectedControllers = List.from(devices.controllers .where((it) => !MyPlatform.isIOS || it.name != "Session 1")); _connectedSynthesizers = List.from(devices.synthesizers); - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static _notifyCurrentSection(String sectionId) { @@ -147,32 +140,31 @@ class BeatScratchPlugin { static _notifyPlayingBeat(int beat) { // In case the user pauses and a beat comes in in a race condition - if (_pausedTime == null || - DateTime.now().difference(_pausedTime).inMilliseconds > 75) { + if (DateTime.now().difference(_pausedTime).inMilliseconds > 75) { _playing = true; } currentBeat.value = beat; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static _notifyPaused() { _playing = false; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static _notifyBpmMultiplier(double bpmMultiplier) { _bpmMultiplier = bpmMultiplier; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static _notifyUnmultipliedBpm(double unmultipliedBpm) { BeatScratchPlugin.unmultipliedBpm = unmultipliedBpm; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static _notifyBeatScratchAudioAvailable(bool available) { _isBeatScratchAudioAvailable = available; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static bool _metronomeEnabled = true; @@ -202,10 +194,6 @@ class BeatScratchPlugin { static double unmultipliedBpm = 123; static bool _playing; static bool get playing { - if (_playing == null) { - _playing = false; - _doSynthesizerStatusChangeLoop(); - } return _playing; } @@ -213,10 +201,6 @@ class BeatScratchPlugin { static bool _isBeatScratchAudioAvailable; static bool get isSynthesizerAvailable { - if (_isBeatScratchAudioAvailable == null) { - _isBeatScratchAudioAvailable = false; - _doSynthesizerStatusChangeLoop(); - } return _isBeatScratchAudioAvailable; } @@ -287,17 +271,13 @@ class BeatScratchPlugin { } else { resultStatus = await _channel.invokeMethod('checkBeatScratchAudioStatus'); } - if (resultStatus == null) { - print("Failed to retrieve Synthesizer Status from JS/Platform Channel"); - resultStatus = false; - } _isBeatScratchAudioAvailable = resultStatus; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); } static void resetAudioSystem() async { _isBeatScratchAudioAvailable = false; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); if (kIsWeb) { } else { _channel.invokeMethod('resetAudioSystem'); @@ -306,7 +286,7 @@ class BeatScratchPlugin { static void createScore(Score score) async { _isBeatScratchAudioAvailable = false; - onSynthesizerStatusChange?.call(); + onSynthesizerStatusChange.call(); _pushScore(score, 'createScore', includeParts: true, includeSections: true); } @@ -373,18 +353,18 @@ class BeatScratchPlugin { static void setCurrentSection(Section section) async { if (kIsWeb) { - context.callMethod('setCurrentSection', [section?.id]); + context.callMethod('setCurrentSection', [section.id]); } else { - _channel.invokeMethod('setCurrentSection', section?.id); + _channel.invokeMethod('setCurrentSection', section.id); } } /// Assigns all external MIDI controllers to the given part. static void setKeyboardPart(Part part) async { if (kIsWeb) { - context.callMethod('setKeyboardPart', [part?.id]); + context.callMethod('setKeyboardPart', [part.id]); } else { - _channel.invokeMethod('setKeyboardPart', part?.id); + _channel.invokeMethod('setKeyboardPart', part.id); } } @@ -433,9 +413,9 @@ class BeatScratchPlugin { /// the native side or from [sendMIDI] in the plugin. static void setRecordingMelody(Melody melody) async { if (kIsWeb) { - context.callMethod('setRecordingMelody', [melody?.id]); + context.callMethod('setRecordingMelody', [melody.id]); } else { - _channel.invokeMethod('setRecordingMelody', melody?.id); + _channel.invokeMethod('setRecordingMelody', melody.id); } } @@ -449,10 +429,10 @@ class BeatScratchPlugin { static void _play() async { if (kIsWeb) { context.callMethod('play', []); - messagesUI?.sendMessage( + messagesUI.sendMessage( message: "Web playback isn't great. Download the app!", isError: true); - messagesUI?.sendMessage( + messagesUI.sendMessage( message: "You may have to play the Keyboard to play.", ); } else { diff --git a/lib/cache_management.dart b/lib/cache_management.dart index 7848d229..abf76ba8 100644 --- a/lib/cache_management.dart +++ b/lib/cache_management.dart @@ -30,10 +30,7 @@ clearMutableCachesForMelody(String melodyId, (key, value) => (key.arguments[0] as String).contains(melodyId)); NotationMusicRenderer.playbackNoteCache .removeWhere((key, value) => key.arguments[0] == melodyId); - if (sectionId == null || - beat == null || - sectionLengthBeats == null || - melodyLengthBeats == null) { + if (beat == null) { NotationMusicRenderer.notationRenderingCache.removeWhere((key, value) => key.arguments[0] == melodyId || (key.arguments[1] as String).contains(melodyId)); diff --git a/lib/drawing/harmony_beat_renderer.dart b/lib/drawing/harmony_beat_renderer.dart index 5c97c704..285005d7 100644 --- a/lib/drawing/harmony_beat_renderer.dart +++ b/lib/drawing/harmony_beat_renderer.dart @@ -67,8 +67,8 @@ extension _HarmonyColor on Chord { class HarmonyBeatRenderer { Section section; - Harmony get harmony => section?.harmony; - Meter get meter => section?.meter; + Harmony get harmony => section.harmony; + Meter get meter => section.meter; int beatPosition = 0; Iterable get subdivisionRange => range( diff --git a/lib/drawing/music/notation_music_renderer.dart b/lib/drawing/music/notation_music_renderer.dart index f87e2515..b8dc34e7 100644 --- a/lib/drawing/music/notation_music_renderer.dart +++ b/lib/drawing/music/notation_music_renderer.dart @@ -137,46 +137,44 @@ class NotationMusicRenderer extends BaseMusicRenderer { Offset(right + 3 * xScale, position * xScale), alphaDrawerPaint); }); - if (noteSign != null) { - double signLeft, signRight, signTop, signBottom; - if (staggered) { - signLeft = left - - 0.7 * - noteheadWidth; //bounds.left - 0.7 * noteheadWidth + xOffset;// bounds.right - 2.3 * noteheadWidth; - } else { - signLeft = left - - 0.5 * - noteheadWidth; //bounds.left - 0.5 * noteheadWidth + xOffset; //bounds.right - 2.8 * noteheadWidth; - } - signRight = signLeft + 0.5 * noteheadWidth; - - switch (noteSign) { - case NoteSign.flat: - case NoteSign.double_flat: - double difference = noteheadHeight * 1.5; - signTop = top - 2 * noteheadHeight / 3 - difference; - signBottom = bottom - difference; - break; - case NoteSign.double_sharp: - signTop = top + noteheadHeight / 4; - signBottom = bottom - noteheadHeight / 4; - break; - case NoteSign.sharp: - case NoteSign.natural: - default: - double difference = noteheadHeight * 1.8; - signTop = top - difference; //- noteheadHeight / 3; - signBottom = bottom - difference; // + noteheadHeight / 3; - } - final signTopOffset = 26 * yScale; - final signLeftOffset = -2 * xScale; - signTop += signTopOffset; - signBottom += signTopOffset; - signLeft += signLeftOffset; - signRight += signLeftOffset; - Rect signRect = Rect.fromLTRB(signLeft, signTop, signRight, signBottom); - _renderSign(canvas, signRect, noteSign); + double signLeft, signRight, signTop, signBottom; + if (staggered) { + signLeft = left - + 0.7 * + noteheadWidth; //bounds.left - 0.7 * noteheadWidth + xOffset;// bounds.right - 2.3 * noteheadWidth; + } else { + signLeft = left - + 0.5 * + noteheadWidth; //bounds.left - 0.5 * noteheadWidth + xOffset; //bounds.right - 2.8 * noteheadWidth; } + signRight = signLeft + 0.5 * noteheadWidth; + + switch (noteSign) { + case NoteSign.flat: + case NoteSign.double_flat: + double difference = noteheadHeight * 1.5; + signTop = top - 2 * noteheadHeight / 3 - difference; + signBottom = bottom - difference; + break; + case NoteSign.double_sharp: + signTop = top + noteheadHeight / 4; + signBottom = bottom - noteheadHeight / 4; + break; + case NoteSign.sharp: + case NoteSign.natural: + default: + double difference = noteheadHeight * 1.8; + signTop = top - difference; //- noteheadHeight / 3; + signBottom = bottom - difference; // + noteheadHeight / 3; + } + final signTopOffset = 26 * yScale; + final signLeftOffset = -2 * xScale; + signTop += signTopOffset; + signBottom += signTopOffset; + signLeft += signLeftOffset; + signRight += signLeftOffset; + Rect signRect = Rect.fromLTRB(signLeft, signTop, signRight, signBottom); + _renderSign(canvas, signRect, noteSign); } _planNoteheadsSignsAndLedgers(_RenderInstructions result) { @@ -255,8 +253,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { break; case NoteSign.natural: default: - if (forceShowNaturals || - (previousSign != null && previousSign != NoteSign.natural)) + if (forceShowNaturals || (previousSign != NoteSign.natural)) signToDraw = NoteSign.natural; break; } @@ -448,9 +445,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { default: break; } - if (signPath != null) { - canvas.drawPath(signPath, alphaDrawerPaint); - } + canvas.drawPath(signPath, alphaDrawerPaint); canvas.restore(); } diff --git a/lib/drawing/sizeutil.dart b/lib/drawing/sizeutil.dart deleted file mode 100644 index 948a7c5f..00000000 --- a/lib/drawing/sizeutil.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; -import 'dart:math'; - -class SizeUtil { - static const _DESIGN_WIDTH = 580; - static const _DESIGN_HEIGHT = 648; - - //logic size in device - static Size _logicSize; - - //device pixel radio. - - static get width { - return _logicSize.width; - } - - static get height { - return _logicSize.height; - } - - static set size(size) { - _logicSize = size; - } - - //@param w is the design w; - static double getAxisX(double w) { - return (w * width) / _DESIGN_WIDTH; - } - -// the y direction - static double getAxisY(double h) { - return (h * height) / _DESIGN_HEIGHT; - } - - // diagonal direction value with design size s. - static double getAxisBoth(double s) { - return s * - sqrt((width * width + height * height) / - (_DESIGN_WIDTH * _DESIGN_WIDTH + _DESIGN_HEIGHT * _DESIGN_HEIGHT)); - } -} diff --git a/lib/edit_menu.dart b/lib/edit_menu.dart index ecbcb597..c61321a6 100644 --- a/lib/edit_menu.dart +++ b/lib/edit_menu.dart @@ -14,7 +14,7 @@ Future showEditMenu( required RelativeRect position, required Score score, required Part part, - required Melody selectedMelody, + Melody? selectedMelody, required MusicViewMode musicViewMode, required Section section, required Function(Object) editObject}) async { @@ -23,7 +23,8 @@ Future showEditMenu( editObject(object); } - final melodies = part.melodies.where((m) => section.referenceTo(m).isEnabled); + final melodies = + part.melodies.where((m) => section.referenceTo(m)?.isEnabled == true); return showMenu( context: context, position: position, @@ -31,6 +32,7 @@ Future showEditMenu( color: (musicBackgroundColor.luminance < 0.5 ? subBackgroundColor : musicBackgroundColor) + // .withAlpha(240) .withOpacity(0.95), items: [ PopupMenuItem( diff --git a/lib/export/export_manager.dart b/lib/export/export_manager.dart index 608075c8..6b51c4eb 100644 --- a/lib/export/export_manager.dart +++ b/lib/export/export_manager.dart @@ -1,10 +1,12 @@ import 'dart:io'; +import 'package:beatscratch_flutter_redux/generated/protos/protos.dart'; + import '../widget/my_platform.dart'; import 'package:path_provider/path_provider.dart'; -import '../util/music_theory.dart'; +// import '../util/music_theory.dart'; import 'export_models.dart'; class ExportManager { @@ -13,9 +15,11 @@ class ExportManager { File createExportFile(BSExport export) { String path = "${exportsDirectory.path.toString()}/${Uri.encodeComponent(export.score.name).replaceAll("%20", " ")}"; - if (export.exportedSection != null) { - path += "-${Uri.encodeComponent(export.exportedSection.canonicalName)}"; + Section? exportedSection = export.exportedSection; + if (exportedSection != null) { + path += "-${Uri.encodeComponent(exportedSection.canonicalName)}"; } + path += "-${DateTime.now().toString().replaceAll(" ", '-').replaceAll(":", '-').split(".").first}"; path += ".${export.exportType.toString().split(".").last}"; @@ -25,12 +29,10 @@ class ExportManager { } List get exportFiles { - if (exportsDirectory != null) { - List result = exportsDirectory?.listSync(); - result.sort( - (a, b) => b.statSync().modified.compareTo(a.statSync().modified)); - return result; - } + List result = exportsDirectory?.listSync(); + result + .sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified)); + return result; return []; } diff --git a/lib/export/export_models.dart b/lib/export/export_models.dart index 87960a9b..fada8185 100644 --- a/lib/export/export_models.dart +++ b/lib/export/export_models.dart @@ -1,6 +1,7 @@ import 'dart:io'; -import 'package:dart_midi/dart_midi.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_writer.dart'; +import 'package:collection/collection.dart'; import '../generated/protos/protos.dart'; import 'export_manager.dart'; @@ -12,12 +13,11 @@ class BSExport { Score score; double tempoMultiplier; ExportType exportType; - String sectionId; + String? sectionId; final List partIds = []; - BSExport( - {this.score, - this.exportType = ExportType.midi, + BSExport(this.score, + {this.exportType = ExportType.midi, this.tempoMultiplier = 1, this.sectionId}); @@ -28,13 +28,11 @@ class BSExport { return fileHandle; } - Section get exportedSection => score.sections.isEmpty + Section? get exportedSection => score.sections.isEmpty ? null - : score.sections.firstWhere((s) => s.id == sectionId, orElse: () => null); + : score.sections.firstWhereOrNull((s) => s.id == sectionId); - bool includesSection(Section section) => - sectionId == null || sectionId == section.id; + bool includesSection(Section section) => sectionId == section.id; - bool includesPart(Part part) => - partIds == null || partIds.isEmpty || partIds.contains(part.id); + bool includesPart(Part part) => partIds.isEmpty || partIds.contains(part.id); } diff --git a/lib/export/export_ui.dart b/lib/export/export_ui.dart index bf2c502e..45fa08cc 100644 --- a/lib/export/export_ui.dart +++ b/lib/export/export_ui.dart @@ -1,4 +1,6 @@ import 'dart:io'; +import 'package:share_plus/share_plus.dart'; + import '../beatscratch_plugin.dart'; import '../generated/protos/music.pb.dart'; import '../messages/messages_ui.dart'; @@ -35,7 +37,7 @@ class ExportUI { bool exporting = false; final BSExport export = BSExport(score: defaultScore()); ExportManager exportManager = ExportManager(); - MessagesUI messagesUI; + MessagesUI? messagesUI; double get baseHeight => visible ? _baseHeight : 0.0; @@ -104,7 +106,7 @@ class ExportUI { Expanded(child: SizedBox()), Transform.translate( offset: Offset(0, 3), - child: Text(export?.score?.name ?? "null", + child: Text(export.score.name ?? "null", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -193,7 +195,7 @@ class ExportUI { exporting = true; visible = false; Future.microtask(() { - File file; + File? file; bool success = false; try { file = export(exportManager); @@ -204,7 +206,7 @@ class ExportUI { print(e.stackTrace); } - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "MIDI Export failed!", isError: true); } @@ -214,35 +216,45 @@ class ExportUI { }); if (success) { if (MyPlatform.isMacOS) { - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Opening exports directory in Finder..."); Future.delayed(Duration(seconds: 1), () { launchURL( "file://${exportManager.exportsDirectory.path}"); - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Export complete!"); }); } else if (MyPlatform.isIOS) { - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Opening exports directory in Files..."); Future.delayed(Duration(seconds: 1), () { launchURL( "shareddocuments://${exportManager.exportsDirectory.path}"); - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Export complete!"); }); } else if (MyPlatform.isMobile) { - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Sharing MIDI file..."); Future.delayed(Duration(seconds: 1), () { - Share.shareFiles([file.path], - text: export.score.name); - messagesUI.sendMessage( + SharePlus.instance + .share(ShareParams( + files: [ + XFile(file!.path), + ], + // sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, + // fileNameOverrides: [fileName], + downloadFallbackEnabled: true, + )); + + // [file.path], + // text: export.score.name); + messagesUI?.sendMessage( message: "Export complete!"); }); } @@ -287,13 +299,10 @@ class ExportUI { List disabledValues, Widget customValue, Function(String) selectValue}) { - if (disabledValues == null) { - disabledValues = []; - } - if (values == null || values.isEmpty) { + if (values.isEmpty) { values = [value]; } - if (value != null && !values.contains(value)) { + if (!values.contains(value)) { values = values + [value]; } values = values.toSet().toList(); @@ -301,7 +310,7 @@ class ExportUI { Widget column = Column(children: [ // if (usesFlex) Expanded(child:SizedBox()), ...values.map((v) { - final clickable = selectValue != null && !disabledValues.contains(v); + final clickable = !disabledValues.contains(v); return MyFlatButton( color: v == value ? Colors.white : Colors.black12, padding: EdgeInsets.all(5), @@ -316,7 +325,7 @@ class ExportUI { : Colors.white, ))); }).toList(), - if (customValue != null) customValue, + customValue, // if (usesFlex) Expanded(child:SizedBox()) ]); // if (!usesFlex) { @@ -341,8 +350,7 @@ class ExportUI { } } - if (export.score == null || - !export.score.sections.any((s) => s.id == export.sectionId)) { + if (!export.score.sections.any((s) => s.id == export.sectionId)) { export.sectionId = null; } export.partIds.removeWhere( @@ -378,7 +386,7 @@ class ExportUI { ? "Entire Score" : export.score.sections .firstWhere((s) => s.id == export.sectionId) - ?.canonicalName ?? + .canonicalName ?? "NULL", sectionWidth, chromaticSteps[3], diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 30fdb7a4..f4685cf7 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -14,13 +14,12 @@ class S implements WidgetsLocalizations { static S current; static const GeneratedLocalizationsDelegate delegate = - GeneratedLocalizationsDelegate(); + GeneratedLocalizationsDelegate(); static S of(BuildContext context) => Localizations.of(context, S); @override TextDirection get textDirection => TextDirection.ltr; - } class $en extends S { @@ -36,9 +35,10 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { ]; } - LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) { + LocaleListResolutionCallback listResolution( + {Locale fallback, bool withCountry = true}) { return (List locales, Iterable supported) { - if (locales == null || locales.isEmpty) { + if (locales.isEmpty) { return fallback ?? supported.first; } else { return _resolve(locales.first, fallback, supported, withCountry); @@ -46,7 +46,8 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { }; } - LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) { + LocaleResolutionCallback resolution( + {Locale fallback, bool withCountry = true}) { return (Locale locale, Iterable supported) { return _resolve(locale, fallback, supported, withCountry); }; @@ -55,14 +56,12 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { @override Future load(Locale locale) { final String lang = getLang(locale); - if (lang != null) { - switch (lang) { - case "en": - S.current = const $en(); - return SynchronousFuture(S.current); - default: - // NO-OP. - } + switch (lang) { + case "en": + S.current = const $en(); + return SynchronousFuture(S.current); + default: + // NO-OP. } S.current = const S(); return SynchronousFuture(S.current); @@ -77,8 +76,9 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { /// /// Internal method to resolve a locale from a list of locales. /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, bool withCountry) { - if (locale == null || !_isSupported(locale, withCountry)) { + Locale _resolve(Locale locale, Locale fallback, Iterable supported, + bool withCountry) { + if (!_isSupported(locale, withCountry)) { return fallback ?? supported.first; } @@ -97,22 +97,22 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { /// Returns true if the specified locale is supported, false otherwise. /// bool _isSupported(Locale locale, bool withCountry) { - if (locale != null) { - for (Locale supportedLocale in supportedLocales) { - // Language must always match both locales. - if (supportedLocale.languageCode != locale.languageCode) { - continue; - } - - // If country code matches, return this locale. - if (supportedLocale.countryCode == locale.countryCode) { - return true; - } - - // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) { - return true; - } + for (Locale supportedLocale in supportedLocales) { + // Language must always match both locales. + if (supportedLocale.languageCode != locale.languageCode) { + continue; + } + + // If country code matches, return this locale. + if (supportedLocale.countryCode == locale.countryCode) { + return true; + } + + // If no country requirement is requested, check if this locale has no country. + if (true != withCountry && + (supportedLocale.countryCode == null || + supportedLocale.countryCode.isEmpty)) { + return true; } } return false; @@ -120,7 +120,7 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { } String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); + ? null + : l.countryCode != null && l.countryCode.isEmpty + ? l.languageCode + : l.toString(); diff --git a/lib/layers_view/layers_part_view.dart b/lib/layers_view/layers_part_view.dart index 059eb1f3..93e90747 100644 --- a/lib/layers_view/layers_part_view.dart +++ b/lib/layers_view/layers_part_view.dart @@ -286,17 +286,16 @@ class _LayersPartViewState extends State { backgroundColor = isSelectedPart ? Colors.white : Colors.grey; textColor = isSelectedPart ? Colors.grey : Colors.white; } - if (lastSelectedMelodyId != null && - selectedMelody != null && + if (selectedMelody != null && lastSelectedMelodyId != selectedMelody.id && widget.autoScroll) { int indexOfMelody = - part.melodies.indexWhere((m) => m.id == selectedMelody?.id); + part.melodies.indexWhere((m) => m.id == selectedMelody.id); if (indexOfMelody >= 0) { requestScrollToTop(indexOfMelody); } } - lastSelectedMelodyId = selectedMelody?.id; + lastSelectedMelodyId = selectedMelody.id; setScrollToTopTimeout(); return frl.ReorderableList( onReorder: this._reorderCallback, @@ -443,7 +442,7 @@ class _LayersPartViewState extends State { })), ), ), - if (part.instrument.type == selectedMelody?.instrumentType) + if (part.instrument.type == selectedMelody.instrumentType) buildDuplicateButton( backgroundColor, textColor, @@ -624,7 +623,7 @@ class _LayersPartViewState extends State { maxLines: 1, overflow: TextOverflow.fade, style: TextStyle( - color: selectedMelody.name?.isNotEmpty ?? false + color: selectedMelody.name.isNotEmpty ?? false ? textColor : textColor.withOpacity(0.5), fontWeight: FontWeight.w300), diff --git a/lib/layers_view/layers_view.dart b/lib/layers_view/layers_view.dart index 277205e9..23d46de3 100644 --- a/lib/layers_view/layers_view.dart +++ b/lib/layers_view/layers_view.dart @@ -49,34 +49,34 @@ class LayersView extends StatefulWidget { final bool shiftUpZoomControls; LayersView( - {this.musicViewMode, - this.superSetState, - this.appSettings, - this.score, - this.sectionColor, - this.currentSection, - this.selectedMelody, - this.selectMelody, - this.colorboardPart, - this.keyboardPart, - this.setKeyboardPart, - this.setColorboardPart, - this.selectPart, - this.toggleMelodyReference, - this.setReferenceVolume, - this.setPartVolume, - this.editingMelody, - this.toggleEditingMelody, - this.hideMelodyView, - this.availableWidth, - this.selectedPart, - this.enableColorboard, - this.showBeatCounts, - this.height, - Key key, - this.showViewOptions, - this.scoreManager, - this.shiftUpZoomControls}) + {Key? key, + required this.musicViewMode, + required this.superSetState, + required this.appSettings, + required this.score, + required this.sectionColor, + required this.currentSection, + required this.selectedMelody, + required this.selectMelody, + required this.colorboardPart, + required this.keyboardPart, + required this.setKeyboardPart, + required this.setColorboardPart, + required this.selectPart, + required this.toggleMelodyReference, + required this.setReferenceVolume, + required this.setPartVolume, + required this.editingMelody, + required this.toggleEditingMelody, + required this.hideMelodyView, + required this.availableWidth, + required this.selectedPart, + required this.enableColorboard, + required this.showBeatCounts, + required this.height, + required this.showViewOptions, + required this.scoreManager, + required this.shiftUpZoomControls}) : super(key: key); @override @@ -142,10 +142,6 @@ class _LayersViewState extends State { Part part = newDrumPart(); widget.score.parts.add(part); BeatScratchPlugin.createPart(part); -// BeatScratchPlugin.pushPart(part); - if (widget.keyboardPart == null) { - widget.setKeyboardPart(part); - } widget.selectPart(part); }); }); @@ -198,12 +194,6 @@ class _LayersViewState extends State { widget.score.parts.add(part); } BeatScratchPlugin.createPart(part); - if (widget.keyboardPart == null) { - widget.setKeyboardPart(part); - } - if (widget.colorboardPart == null) { - widget.setColorboardPart(part); - } widget.selectPart(part); }); }); diff --git a/lib/layers_view/melody_menu_browser.dart b/lib/layers_view/melody_menu_browser.dart index 816fc912..69adfce8 100644 --- a/lib/layers_view/melody_menu_browser.dart +++ b/lib/layers_view/melody_menu_browser.dart @@ -82,10 +82,9 @@ class _MelodyMenuBrowserState extends State { BSMethod updatedMenu; String selectedSamples; Iterable get sampleLists => - (widget.part?.isDrum == true ? _sampleDrumMelodies : _sampleMelodies) - .keys; + (widget.part.isDrum == true ? _sampleDrumMelodies : _sampleMelodies).keys; List get samples => - (widget.part?.isDrum == true + (widget.part.isDrum == true ? _sampleDrumMelodies[selectedSamples] : _sampleMelodies[selectedSamples]) ?? []; @@ -93,7 +92,7 @@ class _MelodyMenuBrowserState extends State { List findDuplicatedMelodies(List input) => input .where((it) => it.name.isNotEmpty && - (widget.part?.melodies?.any((m) => m.name == it.name) ?? false)) + (widget.part.melodies.any((m) => m.name == it.name) ?? false)) .toList(); List> menuEntriesByDuplicateStatus( @@ -122,12 +121,11 @@ class _MelodyMenuBrowserState extends State { @override Widget build(BuildContext context) { - if (selectedScore == null) {} return new MyPopupMenuButton( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), color: musicBackgroundColor.withOpacity(0.95), padding: EdgeInsets.zero, - tooltip: "Import Melody | ${widget.part?.midiName}", + tooltip: "Import Melody | ${widget.part.midiName}", child: widget.child ?? Column(children: [ Expanded( @@ -160,40 +158,22 @@ class _MelodyMenuBrowserState extends State { result.addAll(_scoreDataCache.map(scoreMenuItem)); } return result; - } else if (selectedSamples != null) { + } else List> result = [ backMenuItem(), sampleListHeader() ]; - result - .addAll(menuEntriesByDuplicateStatus(samples, isSample: true)); - // result.addAll(samples.map((m) => melodyMenuItem(m, isSample: true))); - return result; - } else if (selectedPart == null) { - return [backMenuItem(), partListHeader()] + - selectedScore.parts.map(partMenuItem).toList(); - } else { - List> result = [ - backMenuItem(), - melodyListHeader(selectedPart) - ]; - result.addAll(menuEntriesByDuplicateStatus(selectedPart.melodies)); - return result; - } + result.addAll(menuEntriesByDuplicateStatus(samples, isSample: true)); + // result.addAll(samples.map((m) => melodyMenuItem(m, isSample: true))); + return result; }, onSelected: (value) { switch (value) { case "back": - if (selectedPart != null) { - if (selectedPart.isDrum) { - selectedScore = null; - } - selectedPart = null; - } else if (selectedScore != null) { + if (selectedPart.isDrum) { selectedScore = null; - } else if (selectedSamples != null) { - selectedSamples = null; } + selectedPart = null; updatedMenu(); break; default: @@ -203,31 +183,19 @@ class _MelodyMenuBrowserState extends State { } else { selectedScore = _scoreDataCache.firstWhere((s) => s.id == value); - if (widget.part?.isDrum == true) { + if (widget.part.isDrum == true) { selectedPart = selectedScore.parts .firstWhere((p) => p.isDrum, orElse: null); } } updatedMenu(); - } else if (selectedSamples != null) { - if (value.startsWith("sample-")) { - final melody = - samples.firstWhere((m) => "sample-${m.id}" == value); - widget.onMelodySelected(melody.bsRebuild((m) { - m.id = uuid.v4(); - })); - } // else - ??? - } else if (selectedPart == null) { - selectedPart = - selectedScore.parts.firstWhere((p) => p.id == value); - updatedMenu(); - } else { + } else if (value.startsWith("sample-")) { final melody = - selectedPart.melodies.firstWhere((m) => m.id == value); + samples.firstWhere((m) => "sample-${m.id}" == value); widget.onMelodySelected(melody.bsRebuild((m) { m.id = uuid.v4(); })); - } + } // else - ??? } }); } @@ -243,7 +211,7 @@ class _MelodyMenuBrowserState extends State { child: Text( selectedSamples != null ? "Import" - : selectedPart != null && !selectedPart.isDrum + : !selectedPart.isDrum ? "Parts" : "Import", style: TextStyle(color: musicForegroundColor), @@ -271,9 +239,9 @@ class _MelodyMenuBrowserState extends State { TextStyle instrumentStyle(Part part, {bool header = false}) { return TextStyle( fontWeight: FontWeight.w800, - color: part?.instrument?.type == InstrumentType.drum - ? Colors.brown.withOpacity(widget.part?.isDrum == true ? 1 : 0.5) - : widget.part?.isDrum == true || header + color: part.instrument.type == InstrumentType.drum + ? Colors.brown.withOpacity(widget.part.isDrum == true ? 1 : 0.5) + : widget.part.isDrum == true || header ? Colors.grey : musicForegroundColor, ); @@ -288,7 +256,7 @@ class _MelodyMenuBrowserState extends State { padding: EdgeInsets.symmetric(vertical: 2, horizontal: 5), child: Icon(Icons.chevron_right, color: musicForegroundColor)) ]), - enabled: part?.instrument?.type == widget.part?.instrument?.type, + enabled: part.instrument.type == widget.part.instrument.type, ); } @@ -313,7 +281,7 @@ class _MelodyMenuBrowserState extends State { padding: EdgeInsets.symmetric(vertical: 2), child: Icon(Icons.add, color: musicForegroundColor)), if (!isDuplicate && - widget.part?.instrument?.type == melody.instrumentType) + widget.part.instrument.type == melody.instrumentType) SizedBox(width: 5), if (isDuplicate) Transform.scale( @@ -357,7 +325,7 @@ class _MelodyMenuBrowserState extends State { SizedBox(width: 5) ])), ), - if (widget.part?.instrument?.type != melody.instrumentType) + if (widget.part.instrument.type != melody.instrumentType) Transform.scale( scale: 0.8, child: Container( @@ -409,7 +377,7 @@ class _MelodyMenuBrowserState extends State { )), ], ), - enabled: melody.instrumentType == widget.part?.instrument?.type, + enabled: melody.instrumentType == widget.part.instrument.type, ); } @@ -442,7 +410,7 @@ class _MelodyMenuBrowserState extends State { fontSize: 10, color: musicForegroundColor) /*style: instrumentStyle(part, header: true)*/), - Text(widget.part?.midiName ?? "", + Text(widget.part.midiName ?? "", textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, diff --git a/lib/layers_view/melody_reference_view.dart b/lib/layers_view/melody_reference_view.dart index 56c8161d..346ea478 100644 --- a/lib/layers_view/melody_reference_view.dart +++ b/lib/layers_view/melody_reference_view.dart @@ -18,7 +18,7 @@ class MelodyReferenceView extends StatefulWidget { static const double maxColumnWidth = 250; static const double columnWidthIncrement = 12; static const double columnWidthMicroIncrement = 1.4; - static Melody lastAddedMelody; + static Melody? lastAddedMelody; final Melody melody; final bool isFirst; final bool isLast; @@ -41,26 +41,26 @@ class MelodyReferenceView extends StatefulWidget { final double width; MelodyReferenceView({ - this.melody, - this.isFirst, - this.isLast, - this.sectionColor, - this.currentSection, - this.selectedMelody, - this.selectMelody, - this.colorboardPart, - this.keyboardPart, - this.toggleMelodyReference, - this.setReferenceVolume, - this.editingMelody, - this.toggleEditingMelody, - this.hideMelodyView, - this.showBeatsBadge, - this.requestScrollToTop, - this.showMediumDetails, - this.showHighDetails, - this.part, - this.width, + required this.melody, + required this.isFirst, + required this.isLast, + required this.sectionColor, + required this.currentSection, + required this.selectedMelody, + required this.selectMelody, + required this.colorboardPart, + required this.keyboardPart, + required this.toggleMelodyReference, + required this.setReferenceVolume, + required this.editingMelody, + required this.toggleEditingMelody, + required this.hideMelodyView, + required this.showBeatsBadge, + required this.requestScrollToTop, + required this.showMediumDetails, + required this.showHighDetails, + required this.part, + required this.width, }); @override @@ -70,10 +70,10 @@ class MelodyReferenceView extends StatefulWidget { class _MelodyReferenceViewState extends State with TickerProviderStateMixin { MelodyReference get reference => - widget.currentSection.referenceTo(widget.melody); + widget.currentSection.referenceTo(widget.melody)!; - bool get isSelectedMelody => widget.melody.id == widget.selectedMelody?.id; - AnimationController animationController; + bool get isSelectedMelody => widget.melody.id == widget.selectedMelody.id; + late AnimationController animationController; TextEditingController nameController = TextEditingController(); bool get allowEditName => widget.showMediumDetails; bool get showVolume => @@ -282,7 +282,7 @@ class _MelodyReferenceViewState extends State }, style: TextStyle( color: melodyColor.textColor().withOpacity( - reference?.isEnabled == true ? 1 : 0.5)), + reference.isEnabled == true ? 1 : 0.5)), onTap: () { if (!context.isTabletOrLandscapey) { widget.hideMelodyView(); @@ -303,7 +303,7 @@ class _MelodyReferenceViewState extends State // padding: EdgeInsets.only(right:0), child: Icon(Icons.reorder, color: melodyColor.textColor().withOpacity( - reference?.isEnabled == true ? 1 : 0.5)))) + reference.isEnabled == true ? 1 : 0.5)))) ])), ), Row( diff --git a/lib/main.dart b/lib/main.dart index df59ba61..62a9d3a6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -267,9 +267,6 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set keyboardPart(Part part) { _keyboardPart = part; - if (part == null) { - showKeyboard = false; - } BeatScratchPlugin.setKeyboardPart(part); } @@ -279,9 +276,6 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set colorboardPart(Part part) { _colorboardPart = part; - if (part == null) { - showColorboard = false; - } // BeatScratchPlugin.setColorboardPart(part); } @@ -323,9 +317,6 @@ class _MyHomePageState extends State with TickerProviderStateMixin { setState(() { _musicViewSizeFactor = 0; _prevSelectedMelody = selectedMelody; - if (_prevSelectedMelody == null) { - _prevSelectedPart = selectedPart; - } selectedMelody = null; recordingMelody = false; selectedPart = null; @@ -355,9 +346,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { setState(() { bool wasAssignedByPartCreation = keyboardPart == null; keyboardPart = part; - if (part != null && - !wasAssignedByPartCreation && - !hasPrioritizedMIDIController) { + if (!wasAssignedByPartCreation && !hasPrioritizedMIDIController) { showKeyboard = true; } }); @@ -367,7 +356,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { setState(() { bool wasAssignedByPartCreation = colorboardPart == null; colorboardPart = part; - if (part != null && !wasAssignedByPartCreation) { + if (!wasAssignedByPartCreation) { showColorboard = true; } }); @@ -379,14 +368,10 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set selectedMelody(Melody selectedMelody) { _selectedMelody = selectedMelody; - if (selectedMelody != null) { - Part part = score.parts - .firstWhere((p) => p.melodies.any((m) => m.id == selectedMelody.id)); - if (part != null) { - keyboardPart = part; - } - } else { - recordingMelody = false; + Part part = score.parts + .firstWhere((p) => p.melodies.any((m) => m.id == selectedMelody.id)); + if (part != null) { + keyboardPart = part; } } @@ -396,9 +381,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set selectedPart(Part selectedPart) { _selectedPart = selectedPart; - if (selectedPart != null) { - keyboardPart = selectedPart; - } + keyboardPart = selectedPart; } Part _viewingPart; @@ -407,9 +390,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set viewingPart(Part viewingPart) { _viewingPart = viewingPart; - if (viewingPart != null) { - keyboardPart = viewingPart; - } + keyboardPart = viewingPart; } List _sectionLists = []; @@ -476,9 +457,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } else { setState(() { ref.playbackType = MelodyReference_PlaybackType.disabled; - if (selectedMelody != null && - ref != null && - ref.melodyId == selectedMelody.id) { + if (ref != null && ref.melodyId == selectedMelody.id) { recordingMelody = false; } }); @@ -571,27 +550,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { // _universeManager.currentUniverseScore = ""; universeViewUI.visible = false; if (interactionMode.isEdit) { - if (selectedMelody != null) { - _prevSelectedMelody = selectedMelody; - _prevSelectedPart = null; - _hideMusicView(); - } else if (selectedPart != null) { - _prevSelectedMelody = null; - _prevSelectedPart = selectedPart; - _hideMusicView(); - } else if (musicViewMode == MusicViewMode.section) { - _prevSelectedMelody = null; - _prevSelectedPart = null; - _hideMusicView(); - } else { - if (_prevSelectedMelody != null) { - _selectOrDeselectMelody(_prevSelectedMelody); - } else if (_prevSelectedPart != null) { - _selectOrDeselectPart(_prevSelectedPart); - } else { - _selectSection(currentSection); - } - } + _prevSelectedMelody = selectedMelody; + _prevSelectedPart = null; + _hideMusicView(); } else { if (_scoreManager.currentScoreName == ScoreManager.UNIVERSE_SCORE || _scoreManager.currentScoreName == ScoreManager.WEB_SCORE || @@ -619,13 +580,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { // }); // }); } - if (_prevSelectedMelody != null) { - _selectOrDeselectMelody(_prevSelectedMelody); - } else if (_prevSelectedPart != null) { - _selectOrDeselectPart(_prevSelectedPart); - } else { - musicViewMode = MusicViewMode.section; - } + _selectOrDeselectMelody(_prevSelectedMelody); interactionMode = InteractionMode.edit; // showSections = true; _showMusicView(); @@ -885,13 +840,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { score = widget.initialScore; _currentSection = widget.initialScore.sections[0]; _scoreManager.doOpenScore = doOpenScore; - if (widget.pastebinCode != null) { - _scoreManager.loadPastebinScoreIntoUI(widget.pastebinCode, onFail: () { - messagesUI.sendMessage(message: "Failed to load URL!", isError: true); - }); - } else if (MyPlatform.isWeb) { - BeatScratchPlugin.createScore(score); - } + _scoreManager.loadPastebinScoreIntoUI(widget.pastebinCode, onFail: () { + messagesUI.sendMessage(message: "Failed to load URL!", isError: true); + }); if (MyPlatform.isMobile) { KeyboardVisibility.onChange.listen((bool visible) { setState(() { @@ -1124,10 +1075,6 @@ class _MyHomePageState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - if (splitMode == null) { - splitMode = (context.isTablet) ? SplitMode.half : SplitMode.full; - verticalSectionList = context.isTablet || context.isLandscapePhone; - } if (hasPrioritizedMIDIController && !hadPriotizedMIDIController) { showKeyboard = false; } @@ -1139,7 +1086,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { if (context.isLandscape) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); } else { - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, + overlays: SystemUiOverlay.values); } if (BeatScratchPlugin.playing) { _tapInBeat = null; @@ -1389,23 +1337,22 @@ class _MyHomePageState extends State with TickerProviderStateMixin { padding: EdgeInsets.zero, onPressed: _universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = _universeManager - .currentUniverseScoreFuture?.likes; + bool oldValue = + _universeManager.currentUniverseScoreFuture.likes; setState(() { if (oldValue == true) { - scoreFuture?.likes = null; - scoreFuture?.voteCount -= 1; + scoreFuture.likes = null; + scoreFuture.voteCount -= 1; } else { - scoreFuture?.likes = true; - scoreFuture?.voteCount += - oldValue == null ? 1 : 2; + scoreFuture.likes = true; + scoreFuture.voteCount += oldValue == null ? 1 : 2; } _universeManager.vote( - scoreFuture?.fullName, scoreFuture?.likes); + scoreFuture.fullName, scoreFuture.likes); }); } : null, - color: scoreFuture?.likes == true + color: scoreFuture.likes == true ? chromaticSteps[11] : Colors.transparent, child: Align( @@ -1415,7 +1362,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Icon(Icons.arrow_upward, color: _universeManager.isAuthenticated - ? scoreFuture?.likes == true + ? scoreFuture.likes == true ? chromaticSteps[11].textColor() : chromaticSteps[11] : musicForegroundColor.withOpacity(0.5)))), @@ -1425,7 +1372,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Align( alignment: Alignment.center, - child: Text(scoreFuture?.voteCount?.toString() ?? '', + child: Text(scoreFuture.voteCount.toString() ?? '', textAlign: TextAlign.center, style: TextStyle( color: musicForegroundColor, @@ -1437,22 +1384,22 @@ class _MyHomePageState extends State with TickerProviderStateMixin { padding: EdgeInsets.zero, onPressed: _universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = _universeManager - .currentUniverseScoreFuture?.likes; + bool oldValue = + _universeManager.currentUniverseScoreFuture.likes; setState(() { if (oldValue == false) { - scoreFuture?.likes = null; + scoreFuture.likes = null; scoreFuture.voteCount += 1; } else { - scoreFuture?.likes = false; + scoreFuture.likes = false; scoreFuture.voteCount -= oldValue == null ? 1 : 2; } _universeManager.vote( - scoreFuture?.fullName, scoreFuture?.likes); + scoreFuture.fullName, scoreFuture.likes); }); } : null, - color: scoreFuture?.likes == false + color: scoreFuture.likes == false ? chromaticSteps[10] : Colors.transparent, child: Align( @@ -1462,7 +1409,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Icon(Icons.arrow_downward, color: _universeManager.isAuthenticated - ? scoreFuture?.likes == false + ? scoreFuture.likes == false ? chromaticSteps[10].textColor() : chromaticSteps[10] : musicForegroundColor.withOpacity(0.5)))), @@ -1766,12 +1713,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool isDisplayed = (!vertical && !bottom && _tapInBarHeight != 0) || (vertical && _landscapeTapInBarWidth != 0) || (bottom && _bottomTapInBarHeight != 0); - final double tapInFirstSize = - !playing && (vertical || tapInBeat == null) ? 42 : 0; + final double tapInFirstSize = !playing && (vertical) ? 42 : 0; final double tapInSecondSize = - !BeatScratchPlugin.playing && (_tapInBeat == null || _tapInBeat <= -2) - ? 42 - : 0; + !BeatScratchPlugin.playing && (_tapInBeat <= -2) ? 42 : 0; final audioButtonColor = BeatScratchPlugin.metronomeEnabled ? sectionColor : Colors.grey; Widget tapInBarInstructions({bool withText = true, bool withIcon = true}) => @@ -2242,12 +2186,10 @@ class _MyHomePageState extends State with TickerProviderStateMixin { showViewOptions; showMidiConfiguration = true; showViewOptions = true; - if (keyboardPart != null && showKeyboard) { + if (showKeyboard) { _showKeyboardConfiguration = true; } - if (_enableColorboard && - colorboardPart != null && - showColorboard) { + if (_enableColorboard && showColorboard) { _showColorboardConfiguration = true; } }); @@ -2261,12 +2203,6 @@ class _MyHomePageState extends State with TickerProviderStateMixin { saveCurrentScore: saveCurrentScore, pasteScore: () async { ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); - if (data == null) { - setState(() { - pasteFailed = true; - }); - return; - } String scoreUrl = data.text; _scoreManager.loadFromScoreUrl(scoreUrl, currentScoreToSave: this.score, onFail: () { @@ -2330,12 +2266,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { _selectOrDeselectPart(object); } } else if (object is Section) { - if (selectedMelody != null) { - _selectOrDeselectMelody(selectedMelody); - } - if (selectedPart != null) { - _selectOrDeselectPart(selectedPart); - } + _selectOrDeselectMelody(selectedMelody); + _selectOrDeselectPart(selectedPart); musicViewMode = MusicViewMode.section; if (!interactionMode.isEdit) { _editMode(); @@ -2404,9 +2336,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { }); }, showTempoConfiguration: _showTapInBar, - visible: (_secondToolbarHeight != null && _secondToolbarHeight != 0) || - (_landscapePhoneSecondToolbarWidth != null && - _landscapePhoneSecondToolbarWidth != 0) || + visible: (_secondToolbarHeight != 0) || + (_landscapePhoneSecondToolbarWidth != 0) || _scalableUI, tempoLongPress: _landscapePhoneUI ? () { @@ -2469,11 +2400,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { })); } - if (delay == null) { - Future.microtask(doSave); - } else { - Future.delayed(delay, doSave); - } + Future.delayed(delay, doSave); } double beatScratchToolbarHeight(BuildContext context) => @@ -2833,8 +2760,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } : null, cloneCurrentSection: () { - if (currentSection.name == null || - currentSection.name.trim().isEmpty) { + if (currentSection.name.trim().isEmpty) { String prefix = "Section"; while (score.sections.any((s) => s.name.startsWith("$prefix "))) { prefix = "$prefix'"; diff --git a/lib/main_menu.dart b/lib/main_menu.dart index 21762e33..22485510 100644 --- a/lib/main_menu.dart +++ b/lib/main_menu.dart @@ -9,7 +9,7 @@ import 'export/export_ui.dart'; import 'generated/protos/protos.dart'; import 'widget/my_platform.dart'; -Future showMainMenu( +Future showMainMenu( {required BuildContext context, required RelativeRect position, required bool showDownloads, @@ -44,21 +44,21 @@ Future showMainMenu( Expanded( child: SizedBox(), ), - if (packageInfo?.version != null) - Text('v${packageInfo?.version}', + if (packageInfo.version != null) + Text('v${packageInfo.version}', style: TextStyle( color: musicForegroundColor.withOpacity(0.5), fontWeight: FontWeight.w500, fontSize: 10)), - if (packageInfo?.version != null) SizedBox(width: 3), - if (packageInfo?.version != null) - Text('(${packageInfo?.buildNumber})', + if (packageInfo.version != null) SizedBox(width: 3), + if (packageInfo.version != null) + Text('(${packageInfo.buildNumber})', style: TextStyle( color: musicForegroundColor.withOpacity(0.5), fontWeight: FontWeight.w100, fontSize: 10)), - if (packageInfo?.version == null) - Text('(build ${packageInfo?.buildNumber})', + if (packageInfo.version == null) + Text('(build ${packageInfo.buildNumber})', style: TextStyle( color: musicForegroundColor.withOpacity(0.5), fontWeight: FontWeight.w100, diff --git a/lib/main_toolbars.dart b/lib/main_toolbars.dart index bc0a7022..fd5705c1 100644 --- a/lib/main_toolbars.dart +++ b/lib/main_toolbars.dart @@ -70,7 +70,7 @@ class BeatScratchToolbar extends StatefulWidget { final BSMethod refreshUniverseData; final Function(Object) editObject; const BeatScratchToolbar( - {Key key, + {Key? key, required this.appSettings, required this.universeManager, required this.interactionMode, @@ -121,20 +121,19 @@ class BeatScratchToolbar extends StatefulWidget { class _BeatScratchToolbarState extends State with TickerProviderStateMixin { - AnimationController sectionRotationController; - Animation sectionOrPlayRotation; - AnimationController editController; - Animation editRotation; - Animation editTranslation; - Animation editScale; - AnimationController editRotationOnlyController; - Animation editRotationOnlyRotation; + late AnimationController sectionRotationController; + late Animation sectionOrPlayRotation; + late AnimationController editController; + late Animation editRotation; + late Animation editTranslation; + late Animation editScale; + late AnimationController editRotationOnlyController; + late Animation editRotationOnlyRotation; bool get hasMelody => widget.openMelody != null || widget.prevMelody != null; - bool get hasPart => - !hasMelody && widget.openPart != null || widget.prevPart != null; + bool get hasPart => !hasMelody || widget.prevPart != null; bool get hasDrumPart => - hasPart && (widget.openPart?.isDrum ?? widget.prevPart?.isDrum ?? false); + hasPart && (widget.openPart.isDrum ?? widget.prevPart.isDrum ?? false); @override void initState() { @@ -190,7 +189,7 @@ class _BeatScratchToolbarState extends State // clipboardTriggerTime.cancel(); } - Widget columnOrRow(BuildContext context, {List children}) { + Widget columnOrRow(BuildContext context, {required List children}) { if (widget.vertical) { return Column(children: children); } else { @@ -565,8 +564,9 @@ class _BeatScratchToolbarState extends State class _EditButton extends StatelessWidget { final Score score; final Section currentSection; - final Part currentPart, openPart, prevPart; - final Melody openMelody, prevMelody; + final Part currentPart; + final Part? openPart, prevPart; + final Melody? openMelody, prevMelody; final InteractionMode interactionMode; final MusicViewMode musicViewMode; final VoidCallback editMode; @@ -581,31 +581,31 @@ class _EditButton extends StatelessWidget { final Function(Object) editObject; const _EditButton({ - Key key, - this.score, - this.currentSection, - this.currentPart, + Key? key, + required this.score, + required this.currentSection, + required this.currentPart, this.openPart, this.prevPart, - this.openMelody, - this.prevMelody, - this.interactionMode, - this.musicViewMode, - this.editMode, - this.sectionColor, - this.editController, - this.vertical, - this.isMelodyViewOpen, - this.editRotation, - this.editTranslation, - this.editScale, - this.editRotationOnlyController, - this.editRotationOnlyRotation, - this.editObject, + required this.openMelody, + required this.prevMelody, + required this.interactionMode, + required this.musicViewMode, + required this.editMode, + required this.sectionColor, + required this.editController, + required this.vertical, + required this.isMelodyViewOpen, + required this.editRotation, + required this.editTranslation, + required this.editScale, + required this.editRotationOnlyController, + required this.editRotationOnlyRotation, + required this.editObject, }) : super(key: key); bool get hasMelody => openMelody != null || prevMelody != null; - bool get hasPart => !hasMelody && openPart != null || prevPart != null; + bool get hasPart => !hasMelody || prevPart != null; bool get hasDrumPart => hasPart && (openPart?.isDrum ?? prevPart?.isDrum ?? false); @@ -728,17 +728,17 @@ class _EditButton extends StatelessWidget { width: vertical ? 44 : 60, child: Text( openMelody != null - ? openMelody.canonicalName + ? openMelody!.canonicalName : openPart != null - ? openPart.midiName + ? openPart!.midiName : isMelodyViewOpen || (prevPart == null && prevMelody == null) ? currentSection.canonicalName : prevMelody != null - ? prevMelody.canonicalName + ? prevMelody!.canonicalName : prevPart != null - ? prevPart.midiName + ? prevPart!.midiName : "Oops", textAlign: TextAlign.center, maxLines: vertical ? 2 : 2, @@ -795,28 +795,28 @@ class SecondToolbar extends StatefulWidget { final Function(VoidCallback) setAppState; const SecondToolbar({ - Key key, - this.appSettings, - this.toggleKeyboard, - this.toggleColorboard, - this.showKeyboard, - this.showColorboard, - this.interactionMode, - this.showViewOptions, - this.showKeyboardConfiguration, - this.showColorboardConfiguration, - this.toggleKeyboardConfiguration, - this.toggleColorboardConfiguration, - this.sectionColor, - this.enableColorboard, - this.recordingMelody, - this.toggleTempoConfiguration, - this.showTempoConfiguration, - this.vertical, - this.visible, - this.tempoLongPress, - this.rewind, - this.setAppState, + Key? key, + required this.appSettings, + required this.toggleKeyboard, + required this.toggleColorboard, + required this.showKeyboard, + required this.showColorboard, + required this.interactionMode, + required this.showViewOptions, + required this.showKeyboardConfiguration, + required this.showColorboardConfiguration, + required this.toggleKeyboardConfiguration, + required this.toggleColorboardConfiguration, + required this.sectionColor, + required this.enableColorboard, + required this.recordingMelody, + required this.toggleTempoConfiguration, + required this.showTempoConfiguration, + required this.vertical, + required this.visible, + required this.tempoLongPress, + required this.rewind, + required this.setAppState, }) : super(key: key); @override @@ -825,9 +825,9 @@ class SecondToolbar extends StatefulWidget { class _SecondToolbarState extends State { DateTime lastMetronomeAudioToggleTime = DateTime(0); - double tempoButtonGestureStartMultiplier; - double tempoButtonGestureStartPosition; - Widget columnOrRow(BuildContext context, {List children}) { + double? tempoButtonGestureStartMultiplier; + double? tempoButtonGestureStartPosition; + Widget columnOrRow(BuildContext context, {List children = const []}) { if (widget.vertical) { return Column(children: children); } else { @@ -849,7 +849,7 @@ class _SecondToolbarState extends State { if (widget.enableColorboard) { numberOfButtons += 1; } - Widget createPlayIcon(IconData icon, {bool visible, Color color}) { + Widget createPlayIcon(IconData icon, {bool visible = true, Color? color}) { return AnimatedOpacity( opacity: visible ? 1 : 0, duration: animationDuration, @@ -1022,7 +1022,7 @@ class _SecondToolbarState extends State { ])); } - Widget tempoButton(BuildContext context, {Color backgroundColor}) { + Widget tempoButton(BuildContext context, {required Color backgroundColor}) { double sensitivity = 7; tempoDragStart(DragStartDetails details) { tempoButtonGestureStartPosition = @@ -1032,13 +1032,14 @@ class _SecondToolbarState extends State { tempoDragUpdate(DragUpdateDetails details) { final change = widget.vertical - ? -(details.localPosition.dy - tempoButtonGestureStartPosition) - : details.localPosition.dx - tempoButtonGestureStartPosition; + ? -(details.localPosition.dy - tempoButtonGestureStartPosition!) + : details.localPosition.dx - tempoButtonGestureStartPosition!; widget.setAppState(() { var startTempo = (BeatScratchPlugin.unmultipliedBpm * BeatScratchPlugin.bpmMultiplier) .toStringAsFixed(0); - double newMultiplier = tempoButtonGestureStartMultiplier + change / 250; + double newMultiplier = + tempoButtonGestureStartMultiplier! + change / 250; BeatScratchPlugin.bpmMultiplier = max(0.1, min(newMultiplier, 2)); var endTempo = (BeatScratchPlugin.unmultipliedBpm * BeatScratchPlugin.bpmMultiplier) @@ -1086,7 +1087,7 @@ class _SecondToolbarState extends State { final buttonBackgroundColor = (widget.showTempoConfiguration) ? Colors.white : backgroundColor; - final buttonForegroundColor = buttonBackgroundColor.textColor(); + final buttonForegroundColor = buttonBackgroundColor!.textColor(); return GestureDetector( onVerticalDragStart: widget.vertical ? tempoDragStart : null, onVerticalDragUpdate: diff --git a/lib/messages/messages_ui.dart b/lib/messages/messages_ui.dart index b9229a3e..9bdc3538 100644 --- a/lib/messages/messages_ui.dart +++ b/lib/messages/messages_ui.dart @@ -31,9 +31,6 @@ class MessagesUI { ? Icon(Icons.warning, size: 18, color: color ?? chromaticSteps[7]) : Icon(Icons.info, size: 18, color: color ?? chromaticSteps[0]); } - if (messageId == null) { - messageId = uuid.v4(); - } final bsMessage = BSMessage( id: messageId, message: message, diff --git a/lib/midi/byte_reader.dart b/lib/midi/byte_reader.dart new file mode 100644 index 00000000..fe13113b --- /dev/null +++ b/lib/midi/byte_reader.dart @@ -0,0 +1,95 @@ +import 'data_chunk.dart'; + +class ByteReader { + final List buffer; + int pos = 0; + bool get eof => this.pos >= buffer.length; + + ByteReader(this.buffer); + + int readUInt8() { + var result = this.buffer[this.pos]; + this.pos += 1; + return result; + } + + int readInt8() { + var u = this.readUInt8(); + if (u & 0x80 != 0) { + return u - 0x100; + } else + return u; + } + + int readUInt16() { + var b0 = this.readUInt8(); + var b1 = this.readUInt8(); + return (b0 << 8) + b1; + } + + int readInt16() { + var u = this.readUInt16(); + if (u & 0x8000 != 0) { + return u - 0x10000; + } else + return u; + } + + int readUInt24() { + var b0 = this.readUInt8(); + var b1 = this.readUInt8(); + var b2 = this.readUInt8(); + return (b0 << 16) + (b1 << 8) + b2; + } + + int readInt24() { + var u = this.readUInt16(); + if (u & 0x800000 != 0) { + return u - 0x1000000; + } else + return u; + } + + int readUInt32() { + var b0 = this.readUInt8(); + var b1 = this.readUInt8(); + var b2 = this.readUInt8(); + var b3 = this.readUInt8(); + + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + } + + List readBytes(int len) { + var bytes = this.buffer.sublist(this.pos, this.pos + len); + this.pos += len; + return bytes; + } + + String readString(int len) { + var bytes = this.readBytes(len); + return String.fromCharCodes(bytes); + } + + int readVarInt() { + var result = 0; + while (!this.eof) { + var b = this.readUInt8(); + if (b & 0x80 != 0) { + result += (b & 0x7f); + result <<= 7; + } else { + // b is last byte + return result + b; + } + } + // premature eof + return result; + } + + DataChunk readChunk() { + var id = this.readString(4); + var length = this.readUInt32(); + var data = this.readBytes(length); + return DataChunk(id: id, length: length, bytes: data); + } +} diff --git a/lib/midi/byte_writer.dart b/lib/midi/byte_writer.dart new file mode 100644 index 00000000..27f8de32 --- /dev/null +++ b/lib/midi/byte_writer.dart @@ -0,0 +1,85 @@ +import 'data_chunk.dart'; + +class ByteWriter { + final List buffer = []; + int pos = 0; + bool get eof => this.pos >= buffer.length; + + ByteWriter(); + + void writeUInt8(int v) { + this.buffer.add(v & 0xFF); + } + + void writeInt8(int v) => writeUInt8(v); + + void writeUInt16(int v) { + var b0 = (v >> 8) & 0xFF, b1 = v & 0xFF; + + this.writeUInt8(b0); + this.writeUInt8(b1); + } + + void writeInt16(int v) => writeUInt16(v); + + void writeUInt24(int v) { + var b0 = (v >> 16) & 0xFF, b1 = (v >> 8) & 0xFF, b2 = v & 0xFF; + + this.writeUInt8(b0); + this.writeUInt8(b1); + this.writeUInt8(b2); + } + + void writeInt24(int v) => writeUInt24(v); + + void writeUInt32(int v) { + var b0 = (v >> 24) & 0xFF, + b1 = (v >> 16) & 0xFF, + b2 = (v >> 8) & 0xFF, + b3 = v & 0xFF; + + this.writeUInt8(b0); + this.writeUInt8(b1); + this.writeUInt8(b2); + this.writeUInt8(b3); + } + + void writeBytes(List bytes) { + this.buffer.addAll(bytes); + } + + void writeString(String str) { + int i, len = str.length; + List arr = []; + + for (i = 0; i < len; i++) { + arr.add(str.codeUnitAt(i)); + } + this.writeBytes(arr); + } + + void writeVarInt(int v) { + if (v < 0) throw "Cannot write negative variable-length integer"; + + if (v <= 0x7F) { + this.writeUInt8(v); + } else { + var i = v; + List bytes = []; + bytes.add(i & 0x7F); + i >>= 7; + while (i != 0) { + var b = i & 0x7F | 0x80; + bytes.add(b); + i >>= 7; + } + this.writeBytes(bytes.reversed.toList()); + } + } + + void writeChunk(DataChunk chunk) { + this.writeString(chunk.id); + this.writeUInt32(chunk.bytes.length); + this.writeBytes(chunk.bytes); + } +} diff --git a/lib/midi/data_chunk.dart b/lib/midi/data_chunk.dart new file mode 100644 index 00000000..e3b0c099 --- /dev/null +++ b/lib/midi/data_chunk.dart @@ -0,0 +1,6 @@ +class DataChunk { + final String id; + final int? length; + final List bytes; + DataChunk({required this.id, this.length, required this.bytes}); +} \ No newline at end of file diff --git a/lib/midi/midi_events.dart b/lib/midi/midi_events.dart new file mode 100644 index 00000000..b6363cab --- /dev/null +++ b/lib/midi/midi_events.dart @@ -0,0 +1,390 @@ +import 'dart:math'; + +import 'byte_writer.dart'; + +abstract class MidiEvent { + String type = ''; + int deltaTime = 0; + bool meta = false; + bool running = false; + + // ByteWriter stuff + int? lastEventTypeByte; + bool useByte9ForNoteOff = false; + + int writeEvent(ByteWriter w); +} + +class SequenceNumberEvent extends MidiEvent { + int number = 0; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x00); + w.writeVarInt(2); + w.writeUInt16(number); + return -1; + } +} + +class EndOfTrackEvent extends MidiEvent { + bool meta = true; + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x2F); + w.writeVarInt(0); + return -1; + } +} + +class ProgramChangeMidiEvent extends MidiEvent { + int channel = 0; + int programNumber = 0; + int writeEvent(ByteWriter w) { + int eventTypeByte = 0xC0 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(programNumber); + return eventTypeByte; + } +} + +class ChannelAfterTouchEvent extends MidiEvent { + int channel = 0; + int amount = 0; + + int writeEvent(ByteWriter w) { + var eventTypeByte = 0xD0 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(amount); + return eventTypeByte; + } +} + +class PitchBendEvent extends MidiEvent { + int channel = 0; + int value = + 0; // A pitch bend value from -8192 to 8191. Defaults to 0, or no bend. + + int writeEvent(ByteWriter w) { + var eventTypeByte = 0xE0 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + var value14 = 0x2000 + value; + var lsb14 = (value14 & 0x7F); + var msb14 = (value14 >> 7) & 0x7F; + w.writeUInt8(lsb14); + w.writeUInt8(msb14); + return eventTypeByte; + } +} + +class ControllerEvent extends MidiEvent { + int controllerType = 0; + int channel = 0; + int value = 0; + int? number; + + int writeEvent(ByteWriter w) { + var eventTypeByte = 0xB0 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(controllerType); + w.writeUInt8(value); + return eventTypeByte; + } +} + +class NoteOnEvent extends MidiEvent { + int noteNumber = 60; + int velocity = 127; + int channel = 0; + bool byte9 = false; + + int writeEvent(ByteWriter w) { + var eventTypeByte = 0x90 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(noteNumber); + w.writeUInt8(velocity); + return eventTypeByte; + } +} + +class NoteAfterTouchEvent extends MidiEvent { + int noteNumber = 60; + int amount = 0; + int channel = 0; + + int writeEvent(ByteWriter w) { + var eventTypeByte = 0xA0 | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(noteNumber); + w.writeUInt8(amount); + return eventTypeByte; + } +} + +class NoteOffEvent extends MidiEvent { + int noteNumber = 60; + int channel = 0; + int velocity = 0; + bool byte9 = false; + + int writeEvent(ByteWriter w) { + // Use 0x90 when opts.useByte9ForNoteOff is set and velocity is zero, or when event.byte9 is explicitly set on it. + // parseMidi will set event.byte9 for each event, so that we can get an exact copy by default. + // Explicitly set opts.useByte9ForNoteOff to false, to override event.byte9 and always use 0x80 for noteOff events. + var noteByte = ((useByte9ForNoteOff != false && byte9) || + (useByte9ForNoteOff && velocity == 0)) + ? 0x90 + : 0x80; + + var eventTypeByte = noteByte | channel; + if (eventTypeByte != lastEventTypeByte) w.writeUInt8(eventTypeByte); + w.writeUInt8(noteNumber); + w.writeUInt8(velocity); + return eventTypeByte; + } +} + +class TextEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x01); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class CopyrightNoticeEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x02); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class LyricsEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x05); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class MarkerEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x06); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class CuePointEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x07); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class InstrumentNameEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x04); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class TrackNameEvent extends MidiEvent { + String text = ''; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x03); + w.writeVarInt(text.length); + w.writeString(text); + return -1; + } +} + +class ChannelPrefixEvent extends MidiEvent { + int channel = 0; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x20); + w.writeVarInt(1); + w.writeUInt8(channel); + return -1; + } +} + +class PortPrefixEvent extends MidiEvent { + int port = 0; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x21); + w.writeVarInt(1); + w.writeUInt8(port); + return -1; + } +} + +class SetTempoEvent extends MidiEvent { + int microsecondsPerBeat = 500000; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x51); + w.writeVarInt(3); + w.writeUInt24(microsecondsPerBeat); + return -1; + } +} + +class SequencerSpecificEvent extends MidiEvent { + List data = []; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x7F); + w.writeVarInt(data.length); + w.writeBytes(data); + + return -1; + } +} + +class SystemExclusiveEvent extends MidiEvent { + List data = []; + int writeEvent(ByteWriter w) { + w.writeUInt8(0xF0); + w.writeVarInt(data.length); + w.writeBytes(data); + + return -1; + } +} + +class EndSystemExclusiveEvent extends MidiEvent { + List data = []; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xF7); + w.writeVarInt(data.length); + w.writeBytes(data); + return -1; + } +} + +class UnknownMetaEvent extends MidiEvent { + bool meta = true; + + List data = []; + int? metatypeByte; + + int writeEvent(ByteWriter w) { + if (metatypeByte != null) { + w.writeUInt8(0xFF); + w.writeUInt8(metatypeByte!); + w.writeVarInt(data.length); + w.writeBytes(data); + } + + return -1; + } +} + +class SmpteOffsetEvent extends MidiEvent { + bool meta = true; + + int frameRate = 24; + int hour = 0; + int min = 0; + int sec = 0; + int frame = 0; + int subFrame = 0; + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x54); + w.writeVarInt(5); + var frameRates = {24: 0x00, 25: 0x20, 29: 0x40, 30: 0x60}; + var hourByte = (hour & 0x1F) | frameRates[frameRate]!; + w.writeUInt8(hourByte); + w.writeUInt8(min); + w.writeUInt8(sec); + w.writeUInt8(frame); + w.writeUInt8(subFrame); + return -1; + } +} + +class TimeSignatureEvent extends MidiEvent { + bool meta = true; + + int numerator = 4; + int denominator = 4; + int metronome = 18; + int thirtyseconds = 8; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x58); + w.writeVarInt(4); + w.writeUInt8(numerator); + var _denominator = (log(denominator) / ln2).floor() & 0xFF; + w.writeUInt8(_denominator); + w.writeUInt8(metronome); + w.writeUInt8(thirtyseconds); + return -1; + } +} + +class KeySignatureEvent extends MidiEvent { + int key = 0; + int scale = 0; + bool meta = true; + + int writeEvent(ByteWriter w) { + w.writeUInt8(0xFF); + w.writeUInt8(0x59); + w.writeVarInt(2); + w.writeInt8(key); + w.writeUInt8(scale); + return -1; + } +} diff --git a/lib/midi/midi_file.dart b/lib/midi/midi_file.dart new file mode 100644 index 00000000..584e9690 --- /dev/null +++ b/lib/midi/midi_file.dart @@ -0,0 +1,8 @@ +import 'midi_events.dart'; +import 'midi_header.dart'; + +class MidiFile { + final List> tracks; + final MidiHeader header; + MidiFile(this.tracks, this.header); +} diff --git a/lib/midi/midi_header.dart b/lib/midi/midi_header.dart new file mode 100644 index 00000000..53180c45 --- /dev/null +++ b/lib/midi/midi_header.dart @@ -0,0 +1,16 @@ +class MidiHeader { + final int? framesPerSecond; + final int? ticksPerBeat; + final int? ticksPerFrame; + final int numTracks; + final int format; + final int? timeDivision; + + MidiHeader( + {this.framesPerSecond, + this.ticksPerBeat, + required this.format, + required this.numTracks, + this.ticksPerFrame, + this.timeDivision}); +} \ No newline at end of file diff --git a/lib/midi/midi_parser.dart b/lib/midi/midi_parser.dart new file mode 100644 index 00000000..12cad9f6 --- /dev/null +++ b/lib/midi/midi_parser.dart @@ -0,0 +1,342 @@ +import 'byte_reader.dart'; +import 'midi_events.dart'; +import 'midi_file.dart'; +import 'midi_header.dart'; +import 'dart:io'; + +/// MidiParser is a class responsible of parsing MIDI data into dart objects +class MidiParser { + int? _lastEventTypeByte; + + MidiParser(); + + /// Reads a midi file from provided [buffer] + /// + /// Returns parsed [MidiFile] + MidiFile parseMidiFromBuffer(List buffer) { + var p = new ByteReader(buffer); + + var headerChunk = p.readChunk(); + if (headerChunk.id != 'MThd') + throw "Bad MIDI file. Expected 'MHdr', got: '${headerChunk.id}'"; + var header = parseHeader(headerChunk.bytes); + + List> tracks = []; + for (var i = 0; !p.eof && i < header.numTracks; i++) { + var trackChunk = p.readChunk(); + if (trackChunk.id != 'MTrk') + throw "Bad MIDI file. Expected 'MTrk', got: '${trackChunk.id}'"; + var track = parseTrack(trackChunk.bytes); + tracks.add(track); + } + + return MidiFile(tracks, header); + } + + /// Reads a provided byte [data] into [MidiHeader] + MidiHeader parseHeader(List data) { + final ByteReader p = ByteReader(data); + + final int format = p.readUInt16(); + final int numTracks = p.readUInt16(); + int? framesPerSecond; + int? ticksPerFrame; + int? ticksPerBeat; + + final int timeDivision = p.readUInt16(); + if (timeDivision & 0x8000 != 0) { + framesPerSecond = 0x100 - (timeDivision >> 8); + ticksPerFrame = timeDivision & 0xFF; + } else { + ticksPerBeat = timeDivision; + } + + return MidiHeader( + format: format, + framesPerSecond: framesPerSecond, + numTracks: numTracks, + ticksPerBeat: ticksPerBeat, + ticksPerFrame: ticksPerFrame, + ); + } + + /// Parses provided [file] and returns [MidiFile] + MidiFile parseMidiFromFile(File file) { + return parseMidiFromBuffer(file.readAsBytesSync()); + } + + /// Reads event from provided [p] and returns parsed [MidiEvent] + MidiEvent readEvent(ByteReader p) { + var deltaTime = p.readVarInt(); + + var eventTypeByte = p.readUInt8(); + + if ((eventTypeByte & 0xf0) == 0xf0) { + // system / meta event + if (eventTypeByte == 0xff) { + // meta event + final int metatypeByte = p.readUInt8(); + final int length = p.readVarInt(); + switch (metatypeByte) { + case 0x00: + final SequenceNumberEvent event = SequenceNumberEvent(); + event.deltaTime = deltaTime; + event.type = 'sequenceNumber'; + if (length != 2) + throw 'Expected length for sequenceNumber event is 2, got ${length.toString()}'; + event.number = p.readUInt16(); + return event; + case 0x01: + var event = TextEvent(); + event.type = 'text'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x02: + var event = CopyrightNoticeEvent(); + event.type = 'copyrightNotice'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x03: + var event = TrackNameEvent(); + event.type = 'trackName'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x04: + var event = InstrumentNameEvent(); + event.type = 'instrumentName'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x05: + var event = LyricsEvent(); + event.type = 'lyrics'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x06: + var event = MarkerEvent(); + event.type = 'marker'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x07: + var event = CuePointEvent(); + event.type = 'cuePoint'; + event.deltaTime = deltaTime; + event.text = p.readString(length); + return event; + case 0x20: + var event = ChannelPrefixEvent(); + event.type = 'channelPrefix'; + event.deltaTime = deltaTime; + if (length != 1) + throw 'Expected length for channelPrefix event is 1, got ${length.toString()}'; + event.deltaTime = deltaTime; + event.channel = p.readUInt8(); + return event; + case 0x21: + var event = PortPrefixEvent(); + event.type = 'portPrefix'; + + event.deltaTime = deltaTime; + if (length != 1) + throw 'Expected length for portPrefix event is 1, got ${length.toString()}'; + event.port = p.readUInt8(); + return event; + case 0x2f: + var event = EndOfTrackEvent(); + event.deltaTime = deltaTime; + event.type = 'endOfTrack'; + if (length != 0) + throw 'Expected length for endOfTrack event is 0, got ${length.toString()}'; + return event; + case 0x51: + final event = SetTempoEvent(); + event.deltaTime = deltaTime; + event.type = 'setTempo'; + ; + if (length != 3) + throw 'Expected length for setTempo event is 3, got ${length.toString()}'; + event.microsecondsPerBeat = p.readUInt24(); + return event; + case 0x54: + var event = SmpteOffsetEvent(); + event.deltaTime = deltaTime; + event.type = 'smpteOffset'; + if (length != 5) + throw 'Expected length for smpteOffset event is 5, got ${length.toString()}'; + var hourByte = p.readUInt8(); + var frameRates = {0x00: 24, 0x20: 25, 0x40: 29, 0x60: 30}; + event.frameRate = frameRates[hourByte & 0x60]!; + event.hour = hourByte & 0x1f; + event.min = p.readUInt8(); + event.sec = p.readUInt8(); + event.frame = p.readUInt8(); + event.subFrame = p.readUInt8(); + return event; + case 0x58: + var event = TimeSignatureEvent(); + event.deltaTime = deltaTime; + event.type = 'timeSignature'; + if (length != 4) + throw 'Expected length for timeSignature event is 4, got ${length.toString()}'; + event.numerator = p.readUInt8(); + event.denominator = (1 << p.readUInt8()); + event.metronome = p.readUInt8(); + event.thirtyseconds = p.readUInt8(); + return event; + case 0x59: + var event = KeySignatureEvent(); + event.deltaTime = deltaTime; + event.type = 'keySignature'; + if (length != 2) + throw 'Expected length for keySignature event is 2, got ${length.toString()}'; + event.key = p.readInt8(); + event.scale = p.readUInt8(); + return event; + case 0x7f: + var event = SequencerSpecificEvent(); + event.deltaTime = deltaTime; + event.type = 'sequencerSpecific'; + event.data = p.readBytes(length); + return event; + default: + var event = UnknownMetaEvent(); + event.deltaTime = deltaTime; + event.type = 'unknownMeta'; + event.data = p.readBytes(length); + event.metatypeByte = metatypeByte; + return event; + } + } else if (eventTypeByte == 0xf0) { + var event = SystemExclusiveEvent(); + event.deltaTime = deltaTime; + event.type = 'sysEx'; + var length = p.readVarInt(); + event.data = p.readBytes(length); + return event; + } else if (eventTypeByte == 0xf7) { + var event = EndSystemExclusiveEvent(); + event.deltaTime = deltaTime; + event.type = 'endSysEx'; + var length = p.readVarInt(); + event.data = p.readBytes(length); + return event; + } else { + throw 'Unrecognised MIDI event type byte: ${eventTypeByte.toString()}'; + } + } else { + // channel event + int param1; + bool running = false; + if ((eventTypeByte & 0x80) == 0) { + // running status - reuse lastEventTypeByte as the event type. + // eventTypeByte is actually the first parameter + if (_lastEventTypeByte == null) + throw "Running status byte encountered before status byte"; + param1 = eventTypeByte; + eventTypeByte = _lastEventTypeByte!; + running = true; + } else { + param1 = p.readUInt8(); + _lastEventTypeByte = eventTypeByte; + } + var eventType = eventTypeByte >> 4; + var channel = eventTypeByte & 0x0f; + switch (eventType) { + case 0x08: + var event = NoteOffEvent(); + event.deltaTime = deltaTime; + event.type = 'noteOff'; + event.running = running; + event.channel = channel; + event.noteNumber = param1; + event.velocity = p.readUInt8(); + return event; + case 0x09: + var velocity = p.readUInt8(); + if (velocity == 0) { + var event = NoteOffEvent(); + event.deltaTime = deltaTime; + event.channel = channel; + event.type = 'noteOff'; + event.noteNumber = param1; + event.velocity = velocity; + event.running = running; + if (velocity == 0) event.byte9 = true; + return event; + } else { + var event = NoteOnEvent(); + event.deltaTime = deltaTime; + event.type = 'noteOn'; + + event.channel = channel; + event.running = running; + event.noteNumber = param1; + event.velocity = velocity; + if (velocity == 0) event.byte9 = true; + return event; + } + case 0x0a: + var event = NoteAfterTouchEvent(); + event.channel = channel; + event.deltaTime = deltaTime; + event.noteNumber = param1; + event.running = running; + event.amount = p.readUInt8(); + return event; + case 0x0b: + var event = ControllerEvent(); + event.channel = channel; + event.running = running; + event.deltaTime = deltaTime; + event.type = 'controller'; + event.controllerType = param1; + event.value = p.readUInt8(); + return event; + case 0x0c: + var event = ProgramChangeMidiEvent(); + event.channel = channel; + event.deltaTime = deltaTime; + event.type = 'programChange'; + event.programNumber = param1; + event.running = running; + return event; + case 0x0d: + var event = ChannelAfterTouchEvent(); + event.channel = channel; + event.deltaTime = deltaTime; + event.type = 'channelAftertouch'; + event.amount = param1; + event.running = running; + return event; + case 0x0e: + var event = PitchBendEvent(); + event.channel = channel; + event.deltaTime = deltaTime; + event.running = running; + event.type = 'pitchBend'; + event.value = (param1 + (p.readUInt8() << 7)) - 0x2000; + return event; + default: + throw 'Unrecognised MIDI event type: ${eventType.toString()}'; + } + } + } + + /// Parses provided [data] and returns a list of [MidiEvent] + List parseTrack(List data) { + var p = new ByteReader(data); + + List events = []; + while (!p.eof) { + var event = readEvent(p); + events.add(event); + } + + return events; + } +} diff --git a/lib/midi/midi_writer.dart b/lib/midi/midi_writer.dart new file mode 100644 index 00000000..e1a03439 --- /dev/null +++ b/lib/midi/midi_writer.dart @@ -0,0 +1,80 @@ +import 'byte_writer.dart'; +import 'data_chunk.dart'; +import 'midi_events.dart'; +import 'midi_file.dart'; +import 'midi_header.dart'; +import 'dart:io'; + +class MidiWriter { + MidiWriter(); + + /// Converts a [MidiFile] to byte buffer represented by [List] + /// + /// [running] reuse previous eventTypeByte when possible, to compress file + /// [useByte9ForNoteOff] use 0x09 for noteOff when velocity is zero + List writeMidiToBuffer(MidiFile file, + {bool running = false, bool useByte9ForNoteOff = false}) { + var w = new ByteWriter(); + writeHeader(w, file.header, file.tracks.length); + + file.tracks.forEach((f) => writeTrack(w, f)); + + return w.buffer; + } + + /// Writes [midiFile] as bytes into a provided [file] + /// + /// [running] reuse previous eventTypeByte when possible, to compress file + /// [useByte9ForNoteOff] use 0x09 for noteOff when velocity is zero + void writeMidiToFile(MidiFile midiFile, File file, + {bool running = false, bool useByte9ForNoteOff = false}) { + var bytes = this.writeMidiToBuffer(midiFile); + file.writeAsBytesSync(bytes); + } + + /// Writes a midi track + void writeTrack(ByteWriter w, List track, + {bool running = false, bool useByte9ForNoteOff = false}) { + var t = new ByteWriter(); + int i, len = track.length; + int? eventTypeByte; + for (i = 0; i < len; i++) { + // Reuse last eventTypeByte when opts.running is set, or event.running is explicitly set on it. + // parseMidi will set event.running for each event, so that we can get an exact copy by default. + // Explicitly set opts.running to false, to override event.running and never reuse last eventTypeByte. + if (running == false || !running && !track[i].running) + eventTypeByte = null; + + var event = track[i]; + event.lastEventTypeByte = eventTypeByte; + event.useByte9ForNoteOff = useByte9ForNoteOff; + + t.writeVarInt(event.deltaTime); + eventTypeByte = event.writeEvent(t); + } + + w.writeChunk(DataChunk(id: 'MTrk', bytes: t.buffer)); + } + + /// Writes provided [header] into [w] + void writeHeader(ByteWriter w, MidiHeader header, int numTracks) { + int format = header.format; + + var timeDivision = 128; + if (header.timeDivision != null) { + timeDivision = header.timeDivision!; + } else if (header.ticksPerFrame != null && header.framesPerSecond != null) { + timeDivision = (-(header.framesPerSecond! & 0xFF) << 8) | + (header.ticksPerFrame! & 0xFF); + } else if (header.ticksPerBeat != null && header.ticksPerBeat != 0) { + timeDivision = header.ticksPerBeat! & 0x7FFF; + } + + var h = new ByteWriter(); + h.writeUInt16(format); + h.writeUInt16(numTracks); + h.writeUInt16(timeDivision); + + w.writeChunk(DataChunk(id: 'MThd', bytes: h.buffer)); + } +} diff --git a/lib/music_preview/melody_preview.dart b/lib/music_preview/melody_preview.dart index 2d19e0f3..f7f47bd8 100644 --- a/lib/music_preview/melody_preview.dart +++ b/lib/music_preview/melody_preview.dart @@ -82,7 +82,7 @@ class _MelodyPreviewState extends State { BSMethod notifyUpdate; String get previewKey => - "${widget.melody.id}-${widget.melody.hashCode}|${widget.part?.id ?? "null"}|" + + "${widget.melody.id}-${widget.melody.hashCode}|${widget.part.id ?? "null"}|" + "${widget.section.id}-${widget.section.hashCode}"; @override diff --git a/lib/music_preview/preview_renderer.dart b/lib/music_preview/preview_renderer.dart index 683c2bf6..a5bcc18f 100644 --- a/lib/music_preview/preview_renderer.dart +++ b/lib/music_preview/preview_renderer.dart @@ -94,9 +94,7 @@ class MusicPreviewRenderer { canvas.scale(_overSampleScale); // await () async { final originalForegroundColor = musicForegroundColor; - if (renderColor != null) { - musicForegroundColor = renderColor; - } + musicForegroundColor = renderColor; painter.paint(canvas, size); musicForegroundColor = originalForegroundColor; // }; @@ -109,9 +107,6 @@ class MusicPreviewRenderer { Future get renderedScoreImageData async { final image = await renderedScoreImage; - if (image == null) { - return null; - } return Uint8List.sublistView( await image.toByteData(format: ui.ImageByteFormat.png)); } diff --git a/lib/music_preview/score_preview.dart b/lib/music_preview/score_preview.dart index 5ba966ab..d03381b7 100644 --- a/lib/music_preview/score_preview.dart +++ b/lib/music_preview/score_preview.dart @@ -86,7 +86,7 @@ class _ScorePreviewState extends State { initState() { super.initState(); currentThumbnail = _Thumbnail.a; - widget.notifyUpdate?.addListener(_updateScoreImage); + widget.notifyUpdate.addListener(_updateScoreImage); renderableWidth = actualWidth; _prevRenderColor = widget.renderColor ?? musicForegroundColor; _prevRenderingMode = AppSettings.globalRenderingMode; @@ -97,7 +97,7 @@ class _ScorePreviewState extends State { @override dispose() { - widget.notifyUpdate?.removeListener(_updateScoreImage); + widget.notifyUpdate.removeListener(_updateScoreImage); disposed = true; super.dispose(); } @@ -167,13 +167,6 @@ class _ScorePreviewState extends State { _updateScoreImage() { Future.delayed(animationDuration, () async { final Uint8List data = RENDER_CACHE.get(renderingArguments); - if (data == null) { - // print("Ummm this bad"); - if (widget.width != 0 && widget.height != 0) { - _updateScoreImage(); - } - return; - } if (disposed) return; setState(() { if (actualWidth > renderableWidth) { diff --git a/lib/music_view/melody_editing_toolbar.dart b/lib/music_view/melody_editing_toolbar.dart index 6275c38c..af77c98b 100644 --- a/lib/music_view/melody_editing_toolbar.dart +++ b/lib/music_view/melody_editing_toolbar.dart @@ -95,12 +95,9 @@ class _MelodyEditingToolbarState extends State recordingColor = Colors.grey; } int beats; - if (widget.melody != null) { - beats = widget.melody.length ~/ widget.melody.subdivisionsPerBeat; - } - bool hasHighlightedBeat = widget.highlightedBeat.value != null && - BeatScratchPlugin.playing && - widget.recordingMelody; + beats = widget.melody.length ~/ widget.melody.subdivisionsPerBeat; + bool hasHighlightedBeat = + BeatScratchPlugin.playing && widget.recordingMelody; final melodyReference = widget.currentSection.referenceTo(widget.melody); bool playingOrCountingIn = BeatScratchPlugin.playing || BeatScratchPlugin.countInInitiated; @@ -217,9 +214,9 @@ class _MelodyEditingToolbarState extends State SizedBox(width: 7), IncrementableValue( collapsing: true, - onDecrement: (widget.melody != null && widget.melody.beatCount > 1) + onDecrement: (widget.melody.beatCount > 1) ? () { - if (widget.melody != null && widget.melody.beatCount > 1) { + if (widget.melody.beatCount > 1) { widget.melody.length -= widget.melody.subdivisionsPerBeat; BeatScratchPlugin.onSynthesizerStatusChange(); clearMutableCachesForMelody(widget.melody.id); @@ -227,9 +224,9 @@ class _MelodyEditingToolbarState extends State } } : null, - onIncrement: (widget.melody != null && widget.melody.beatCount <= 999) + onIncrement: (widget.melody.beatCount <= 999) ? () { - if (widget.melody != null && widget.melody.beatCount <= 999) { + if (widget.melody.beatCount <= 999) { widget.melody.length += widget.melody.subdivisionsPerBeat; BeatScratchPlugin.onSynthesizerStatusChange(); clearMutableCachesForMelody(widget.melody.id); @@ -246,10 +243,10 @@ class _MelodyEditingToolbarState extends State SizedBox(width: 5), IncrementableValue( collapsing: true, - onDecrement: (widget.melody?.subdivisionsPerBeat ?? -1) > 1 + onDecrement: (widget.melody.subdivisionsPerBeat ?? -1) > 1 ? () { - if ((widget.melody?.subdivisionsPerBeat ?? -1) > 1) { - widget.melody?.subdivisionsPerBeat -= 1; + if ((widget.melody.subdivisionsPerBeat ?? -1) > 1) { + widget.melody.subdivisionsPerBeat -= 1; widget.melody.length = beats * widget.melody.subdivisionsPerBeat; clearMutableCachesForMelody(widget.melody.id); @@ -259,10 +256,10 @@ class _MelodyEditingToolbarState extends State } } : null, - onIncrement: (widget.melody?.subdivisionsPerBeat ?? -1) < 24 + onIncrement: (widget.melody.subdivisionsPerBeat ?? -1) < 24 ? () { - if ((widget.melody?.subdivisionsPerBeat ?? -1) < 24) { - widget.melody?.subdivisionsPerBeat += 1; + if ((widget.melody.subdivisionsPerBeat ?? -1) < 24) { + widget.melody.subdivisionsPerBeat += 1; widget.melody.length = beats * widget.melody.subdivisionsPerBeat; clearMutableCachesForMelody(widget.melody.id); @@ -275,7 +272,7 @@ class _MelodyEditingToolbarState extends State child: Padding( padding: EdgeInsets.symmetric(vertical: 0, horizontal: 5), child: BeatsBadge( - beats: widget.melody?.subdivisionsPerBeat, + beats: widget.melody.subdivisionsPerBeat, isPerBeat: true, )), ), @@ -283,14 +280,14 @@ class _MelodyEditingToolbarState extends State Expanded( child: AnimatedOpacity( duration: animationDuration, - opacity: widget.melody != null && widget.visible ? 1 : 0, + opacity: widget.visible ? 1 : 0, child: MySlider( - value: melodyReference?.volume ?? 0, - activeColor: melodyReference?.playbackType == + value: melodyReference.volume ?? 0, + activeColor: melodyReference.playbackType == MelodyReference_PlaybackType.playback_indefinitely ? widget.sectionColor : widget.sectionColor.withOpacity(0.5), - onChanged: (widget.melody != null && widget.visible) + onChanged: (widget.visible) ? (value) { widget.setReferenceVolume(melodyReference, value); } @@ -303,7 +300,7 @@ class _MelodyEditingToolbarState extends State padding: EdgeInsets.only(left: 5), child: AnimatedOpacity( duration: animationDuration, - opacity: widget.melody != null && showHoldToClear ? 1 : 0, + opacity: showHoldToClear ? 1 : 0, child: Stack(children: [ Transform.translate( offset: Offset(0, -7), @@ -337,7 +334,7 @@ class _MelodyEditingToolbarState extends State padding: EdgeInsets.only(left: 5), child: AnimatedOpacity( duration: animationDuration, - opacity: widget.melody != null && showDataCleared ? 1 : 0, + opacity: showDataCleared ? 1 : 0, child: Stack(children: [ // Transform.translate(offset: Offset(0, -7), child: Align(alignment: Alignment.center, child: // Text("Data", maxLines: 1, overflow: TextOverflow.visible, style: TextStyle(fontSize: 10)))), @@ -422,11 +419,7 @@ class _MelodyEditingToolbarState extends State ? () { print("clearing single beat"); int beatToDelete = widget.highlightedBeat.value; - if (beatToDelete == null) { - beatToDelete = BeatScratchPlugin.currentBeat.value; - } else { - beatToDelete -= firstBeatOfSection; - } + beatToDelete -= firstBeatOfSection; widget.melody.deleteBeat(beatToDelete); clearMutableCachesForMelody(widget.melody.id); BeatScratchPlugin.onSynthesizerStatusChange(); diff --git a/lib/music_view/music_action_button.dart b/lib/music_view/music_action_button.dart index 8029b5b7..4be03e0e 100644 --- a/lib/music_view/music_action_button.dart +++ b/lib/music_view/music_action_button.dart @@ -25,11 +25,7 @@ class MusicActionButton extends StatelessWidget { @override Widget build(BuildContext context) { double width = this.width, height = this.height; - if (!visible && - width != null && - height != null && - width != 0 && - height != 0) { + if (!visible && width != 0 && height != 0) { width = 0; height = 0; } diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 19fa6522..8f98ef95 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -220,19 +220,17 @@ class _MusicScrollContainerState extends State AnimationController interactiveController; void _interactiveAnimationStop() { interactiveController.stop(); - interactiveAnimation?.removeListener(_onInteractiveAnimation); + interactiveAnimation.removeListener(_onInteractiveAnimation); interactiveAnimation = null; interactiveController.reset(); } void _onInteractiveAnimation() { - if (interactiveAnimation != null) { - transformationController.value = interactiveAnimation.value; - if (!interactiveController.isAnimating) { - interactiveAnimation.removeListener(_onInteractiveAnimation); - interactiveAnimation = null; - interactiveController.reset(); - } + transformationController.value = interactiveAnimation.value; + if (!interactiveController.isAnimating) { + interactiveAnimation.removeListener(_onInteractiveAnimation); + interactiveAnimation = null; + interactiveController.reset(); } } @@ -384,12 +382,8 @@ class _MusicScrollContainerState extends State ValueNotifier interactionStartFocal = ValueNotifier(null); ValueNotifier interactionStartSystem = ValueNotifier(null); _deriveStartSystemFromFocal() { - if (interactionStartFocal.value == null) { - interactionStartSystem.value = null; - } else { - interactionStartSystem.value = - max(0, (interactingFocal.dy / scaledSystemHeight).floor()); - } + interactionStartSystem.value = + max(0, (interactingFocal.dy / scaledSystemHeight).floor()); } Offset get interactingFocal => interactionStartFocal.value; @@ -446,16 +440,14 @@ class _MusicScrollContainerState extends State scrollToCurrentBeat(); _lastAutoScrollTime = DateTime.now(); }); - } else if (_prevSectionId != null && - _prevSectionId != widget.currentSection.id) { + } else if (_prevSectionId != widget.currentSection.id) { scrollToCurrentBeat(); _lastAutoScrollTime = DateTime.now(); - } else if (prevWidth != null && prevWidth != widget.width) { + } else if (prevWidth != widget.width) { // print("width changed"); scrollToCurrentBeat(); _lastAutoScrollTime = DateTime.now(); - } else if (_prevSectionOrder != null && - _prevSectionOrder != sectionOrder) { + } else if (_prevSectionOrder != sectionOrder) { Future.delayed(animationDuration, () { scrollToCurrentBeat(); _lastAutoScrollTime = DateTime.now(); @@ -486,7 +478,7 @@ class _MusicScrollContainerState extends State _prevBeat = currentBeat; _prevSectionOrder = sectionOrder; _prevSectionId = widget.currentSection.id; - _prevPartId = widget.focusedPart?.id; + _prevPartId = widget.focusedPart.id; _hasBuilt = true; // print( // "InteractiveViewer overallCanvasHeight=$overallCanvasHeight, systemsToRender=$systemsToRender, systemHeight=$systemHeight"); @@ -564,7 +556,7 @@ class _MusicScrollContainerState extends State section: widget.currentSection, musicViewMode: widget.musicViewMode, transformationController: transformationController, - focusedMelodyId: widget.focusedMelody?.id, + focusedMelodyId: widget.focusedMelody.id, staves: stavesNotifier, partTopOffsets: partTopOffsets, staffOffsets: staffOffsets, @@ -850,7 +842,7 @@ class _MusicScrollContainerState extends State extension CloseComparison on double { bool roughlyEquals(double x, {double precision = 0.005}) => - x != null && (this - x).abs() < precision; + (this - x).abs() < precision; bool notRoughlyEquals(double x, {double precision = 0.005}) => !roughlyEquals(x, precision: precision); diff --git a/lib/music_view/music_system_painter.dart b/lib/music_view/music_system_painter.dart index 10d3c2e4..ea274c05 100644 --- a/lib/music_view/music_system_painter.dart +++ b/lib/music_view/music_system_painter.dart @@ -55,8 +55,8 @@ class MusicSystemPainter extends CustomPainter { .expand((p) => p.melodies) .firstWhere((m) => m.id == focusedMelodyId, orElse: () => null); - int get numberOfBeats => /*isViewingSection ? section.harmony.beatCount :*/ score - .beatCount; + int get numberOfBeats => /*isViewingSection ? section.harmony.beatCount :*/ + score.beatCount; double get standardClefWidth => clefWidth; @@ -112,7 +112,7 @@ class MusicSystemPainter extends CustomPainter { BeatScratchPlugin.pressedMidiControllerNotes, BeatScratchPlugin.currentBeat, transformationController, - if (otherListenables != null) ...otherListenables + ...otherListenables ])) { _tickPaint.color = musicForegroundColor; _tickPaint.strokeWidth = 2.0; @@ -238,9 +238,6 @@ class MusicSystemPainter extends CustomPainter { } } renderingSection = candidate; - if (renderingSection == null) { - break; - } if (renderingSectionBeat >= renderingSection.beatCount) { //TODO do this better... break; @@ -282,7 +279,7 @@ class MusicSystemPainter extends CustomPainter { right = left + beatWidth; String sectionName = renderingSection.name; - if (sectionName == null || sectionName.isEmpty) { + if (sectionName.isEmpty) { sectionName = renderingSection.id; } @@ -428,23 +425,21 @@ class MusicSystemPainter extends CustomPainter { index++; } - if (focusedMelody != null) { - final part = score.parts - .firstWhere((p) => p.melodies.any((m) => m.id == focusedMelodyId)); - final parts = staff.getParts(score, staffConfiguration); - if (parts.any((p) => p.id == part.id)) { - double opacity = 1; - if (!melodiesToRender.contains(focusedMelody)) { - if (renderingSection.id == section.id) { - opacity = 0.6; - } else { - opacity = 0; - } + final part = score.parts + .firstWhere((p) => p.melodies.any((m) => m.id == focusedMelodyId)); + final parts = staff.getParts(score, staffConfiguration); + if (parts.any((p) => p.id == part.id)) { + double opacity = 1; + if (!melodiesToRender.contains(focusedMelody)) { + if (renderingSection.id == section.id) { + opacity = 0.6; + } else { + opacity = 0; } - _renderMelodyBeat(canvas, focusedMelody, melodyBounds, renderingSection, - renderingSectionBeat, true, opacity, renderQueue, - renderLoopStarts: true); } + _renderMelodyBeat(canvas, focusedMelody, melodyBounds, renderingSection, + renderingSectionBeat, true, opacity, renderQueue, + renderLoopStarts: true); } try { @@ -479,16 +474,14 @@ class MusicSystemPainter extends CustomPainter { melodyBounds, Paint() ..style = PaintingStyle.fill - ..color = part != null && - tappedPart.value?.id == part.id && + ..color = tappedPart.value.id == part.id && renderingBeat == tappedBeat.value ? sectionColor.value.withOpacity(0.12) : Colors.black12); } if (isCurrentScore && (renderingBeat == tappedBeat.value) && - part != null && - tappedPart.value?.id == part.id) { + tappedPart.value.id == part.id) { canvas.drawRect( melodyBounds, Paint() @@ -548,7 +541,7 @@ class MusicSystemPainter extends CustomPainter { if (staff .getParts(score, staves.value) - .any((element) => element.id == focusedPart.value?.id)) { + .any((element) => element.id == focusedPart.value.id)) { Rect highlight = Rect.fromPoints( bounds.topLeft.translate(-bounds.width / 13, notationOpacityNotifier.value * bounds.height / 6), @@ -614,9 +607,9 @@ class MusicSystemPainter extends CustomPainter { ..color = musicForegroundColor.withOpacity(0.26)); var staffParts = staff.getParts(score, staves.value); bool hasColorboardPart = - staffParts.any((part) => part.id == colorboardPart.value?.id); + staffParts.any((part) => part.id == colorboardPart.value.id); bool hasKeyboardPart = - staffParts.any((part) => part.id == keyboardPart.value?.id); + staffParts.any((part) => part.id == keyboardPart.value.id); if (hasColorboardPart || hasKeyboardPart) { _colorboardDummyMelody.setMidiDataFromSimpleMelody( {0: colorboardNotesNotifier.value.toList()}); @@ -637,7 +630,7 @@ class MusicSystemPainter extends CustomPainter { keyboardNotes.length.toDouble(); _keyboardDummyMelody.instrumentType = - keyboardPart?.value?.instrument?.type ?? InstrumentType.harmonic; + keyboardPart.value.instrument.type ?? InstrumentType.harmonic; if (hasColorboardPart) { _renderMelodyBeat( canvas, @@ -750,58 +743,56 @@ class MusicSystemPainter extends CustomPainter { renderingSection.id != section.id) { opacityFactor *= 0.25; } - if (melody != null) { - if (renderLoopStarts && - renderingSectionBeat % (melody.length / melody.subdivisionsPerBeat) == - 0 && - renderingSection.id == section.id) { - Rect highlight = Rect.fromPoints( - melodyBounds.topLeft.translate(-melodyBounds.width / 13, 0), - melodyBounds.bottomLeft.translate(melodyBounds.width / 13, 0)); - canvas.drawRect( - highlight, Paint()..color = sectionColor.value.withAlpha(127)); - } - try { - if (colorblockOpacityNotifier.value > 0) { - ColorblockMusicRenderer() - ..uiScale = scale - ..overallBounds = melodyBounds - ..section = renderingSection - ..beatPosition = renderingSectionBeat - ..colorblockAlpha = - colorblockOpacityNotifier.value * alpha * opacityFactor - ..drawPadding = 3 - ..nonRootPadding = 3 - ..isUserChoosingHarmonyChord = false - ..isMelodyReferenceEnabled = true - ..melody = melody - ..draw(canvas); - } - } catch (e, s) { - print("exception rendering colorblock: $e: \n$s"); + if (renderLoopStarts && + renderingSectionBeat % (melody.length / melody.subdivisionsPerBeat) == + 0 && + renderingSection.id == section.id) { + Rect highlight = Rect.fromPoints( + melodyBounds.topLeft.translate(-melodyBounds.width / 13, 0), + melodyBounds.bottomLeft.translate(melodyBounds.width / 13, 0)); + canvas.drawRect( + highlight, Paint()..color = sectionColor.value.withAlpha(127)); + } + try { + if (colorblockOpacityNotifier.value > 0) { + ColorblockMusicRenderer() + ..uiScale = scale + ..overallBounds = melodyBounds + ..section = renderingSection + ..beatPosition = renderingSectionBeat + ..colorblockAlpha = + colorblockOpacityNotifier.value * alpha * opacityFactor + ..drawPadding = 3 + ..nonRootPadding = 3 + ..isUserChoosingHarmonyChord = false + ..isMelodyReferenceEnabled = true + ..melody = melody + ..draw(canvas); } - try { - if (notationOpacityNotifier.value > 0) { - NotationMusicRenderer() - ..otherMelodiesOnStaff = otherMelodiesOnStaff - ..xScale = xScale - ..yScale = yScale - ..overallBounds = melodyBounds - ..section = renderingSection - ..beatPosition = renderingSectionBeat - ..notationAlpha = - notationOpacityNotifier.value * alpha * opacityFactor - ..drawPadding = 3 - ..nonRootPadding = 3 - ..stemsUp = stemsUp - ..isUserChoosingHarmonyChord = false - ..isMelodyReferenceEnabled = true - ..melody = melody - ..draw(canvas); - } - } catch (e, s) { - print("exception rendering notation: $e: \n$s"); + } catch (e, s) { + print("exception rendering colorblock: $e: \n$s"); + } + try { + if (notationOpacityNotifier.value > 0) { + NotationMusicRenderer() + ..otherMelodiesOnStaff = otherMelodiesOnStaff + ..xScale = xScale + ..yScale = yScale + ..overallBounds = melodyBounds + ..section = renderingSection + ..beatPosition = renderingSectionBeat + ..notationAlpha = + notationOpacityNotifier.value * alpha * opacityFactor + ..drawPadding = 3 + ..nonRootPadding = 3 + ..stemsUp = stemsUp + ..isUserChoosingHarmonyChord = false + ..isMelodyReferenceEnabled = true + ..melody = melody + ..draw(canvas); } + } catch (e, s) { + print("exception rendering notation: $e: \n$s"); } } @@ -823,15 +814,6 @@ class MusicSystemPainter extends CustomPainter { } int renderingSectionBeat = renderingBeat; Section renderingSection = this.section; - if (renderingSection == null) { - int _beat = 0; - Section candidate = score.sections[0]; - while (_beat + candidate.beatCount <= renderingBeat) { - _beat += candidate.beatCount; - renderingSectionBeat -= candidate.beatCount; - } - renderingSection = candidate; - } Harmony renderingHarmony = renderingSection.harmony; double beatLeft = left; for (int renderingSubdivision in range( @@ -839,11 +821,7 @@ class MusicSystemPainter extends CustomPainter { (renderingSectionBeat + 1) * renderingHarmony.subdivisionsPerBeat - 1)) { Chord chordAtSubdivision = - renderingHarmony.changeBefore(renderingSubdivision) ?? - cChromatic; //TODO Is this default needed? - if (renderingChord == null) { - renderingChord = chordAtSubdivision; - } + renderingHarmony.changeBefore(renderingSubdivision) ?? cChromatic; if (renderingChord != chordAtSubdivision) { Rect renderingRect = Rect.fromLTRB(chordLeft, top, left, bottom); try { diff --git a/lib/music_view/music_toolbars.dart b/lib/music_view/music_toolbars.dart index 3f133e75..b3e9b484 100644 --- a/lib/music_view/music_toolbars.dart +++ b/lib/music_view/music_toolbars.dart @@ -49,12 +49,11 @@ class MelodyToolbarState extends State { widget.currentSection.referenceTo(widget.melody); bool get melodySelected => widget.melody != null; bool get melodyEnabled => - melodySelected && (melodyReference?.isEnabled ?? false); + melodySelected && (melodyReference.isEnabled ?? false); Melody confirmingDeleteFor; - bool get isConfirmingDelete => - confirmingDeleteFor != null && confirmingDeleteFor == widget.melody; + bool get isConfirmingDelete => confirmingDeleteFor == widget.melody; bool get showVolume => - (melodyReference?.isEnabled == true) && + (melodyReference.isEnabled == true) && (/*context.isTablet ||*/ _showVolume); @override @@ -76,15 +75,13 @@ class MelodyToolbarState extends State { if (context.isTabletOrLandscapey) { width = width / 2; } - _showVolume &= melodyReference != null && - (melodyReference?.isEnabled == true) && - !isConfirmingDelete; + _showVolume &= (melodyReference.isEnabled == true) && !isConfirmingDelete; - if (confirmingDeleteFor != null && confirmingDeleteFor != widget.melody) { + if (confirmingDeleteFor != widget.melody) { confirmingDeleteFor = null; } nameController.value = - nameController.value.copyWith(text: widget.melody?.name ?? ""); + nameController.value.copyWith(text: widget.melody.name ?? ""); return Container( // color: Colors.white, @@ -160,10 +157,10 @@ class MelodyToolbarState extends State { height: 36, padding: EdgeInsets.zero, child: MySlider( - value: melodyReference?.volume ?? 0, + value: melodyReference.volume ?? 0, activeColor: (melodyReference != null) ? widget.sectionColor : Colors.grey, - onChanged: (melodyReference?.isEnabled != true) + onChanged: (melodyReference.isEnabled != true) ? null : (value) { widget.setReferenceVolume(melodyReference, value); @@ -181,7 +178,7 @@ class MelodyToolbarState extends State { widget.toggleMelodyReference(melodyReference); } : null, - onLongPress: (melodyReference?.isEnabled == true) + onLongPress: (melodyReference.isEnabled == true) ? () { setState(() { _showVolume = !_showVolume; @@ -245,7 +242,7 @@ class MelodyToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - if (widget.melody.name?.isEmpty != false && + if (widget.melody.name.isEmpty != false && (widget.melody.midiData.data.isEmpty || widget.melody.midiData.data.values .where((mc) => mc.data.length != 0) @@ -303,19 +300,18 @@ class PartToolbar extends StatefulWidget { class PartToolbarState extends State { Part confirmingDeleteFor; - bool get isConfirmingDelete => - confirmingDeleteFor != null && confirmingDeleteFor == widget.part; + bool get isConfirmingDelete => confirmingDeleteFor == widget.part; Widget build(BuildContext context) { var width = MediaQuery.of(context).size.width; if (context.isTabletOrLandscapey) { width = width / 2; } - if (confirmingDeleteFor != null && confirmingDeleteFor != widget.part) { + if (confirmingDeleteFor != widget.part) { confirmingDeleteFor = null; } return Container( - key: Key("part-toolbar-${widget.part?.id}"), + key: Key("part-toolbar-${widget.part.id}"), child: Row(children: [ AnimatedContainer( duration: animationDuration, @@ -328,7 +324,7 @@ class PartToolbarState extends State { color: widget.configuringPart ? Colors.white : null, child: AnimatedOpacity( duration: animationDuration, - opacity: widget.part == null || isConfirmingDelete ? 0 : 1, + opacity: isConfirmingDelete ? 0 : 1, child: Icon(Icons.settings, color: widget.configuringPart ? Colors.black @@ -377,8 +373,7 @@ class PartToolbarState extends State { height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( - onPressed: (widget.part != null && - widget.part.instrument.type != InstrumentType.drum) + onPressed: (widget.part.instrument.type != InstrumentType.drum) ? () { widget.setColorboardPart(widget.part); } @@ -386,19 +381,15 @@ class PartToolbarState extends State { padding: EdgeInsets.zero, child: AnimatedOpacity( duration: animationDuration, - opacity: widget.part == null || - isConfirmingDelete || - !widget.enableColorboard - ? 0 - : 1, + opacity: + isConfirmingDelete || !widget.enableColorboard ? 0 : 1, child: Stack(children: [ Align( alignment: Alignment.bottomRight, child: AnimatedOpacity( duration: animationDuration, - opacity: (widget.part != null && - widget.part.instrument.type != - InstrumentType.drum) + opacity: (widget.part.instrument.type != + InstrumentType.drum) ? 1 : 0.25, child: Padding( @@ -431,7 +422,7 @@ class PartToolbarState extends State { padding: EdgeInsets.all(0), child: AnimatedOpacity( duration: animationDuration, - opacity: (widget.part != null && !isConfirmingDelete) ? 0 : 0, + opacity: (!isConfirmingDelete) ? 0 : 0, child: Stack(children: [ Align( alignment: Alignment.topLeft, @@ -543,9 +534,7 @@ class SectionToolbar extends StatefulWidget { class SectionToolbarState extends State { Section confirmingDeleteFor; - bool get isConfirmingDelete => - confirmingDeleteFor != null && - confirmingDeleteFor == widget.currentSection; + bool get isConfirmingDelete => confirmingDeleteFor == widget.currentSection; TextEditingController nameController = TextEditingController(); @override @@ -560,8 +549,7 @@ class SectionToolbarState extends State { if (context.isTabletOrLandscapey) { width = width / 2; } - if (confirmingDeleteFor != null && - confirmingDeleteFor != widget.currentSection) { + if (confirmingDeleteFor != widget.currentSection) { confirmingDeleteFor = null; } nameController.value = @@ -619,7 +607,7 @@ class SectionToolbarState extends State { )), AnimatedContainer( duration: animationDuration, - width: isConfirmingDelete || widget.addPart == null ? 0 : 69, + width: isConfirmingDelete ? 0 : 69, height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( @@ -628,8 +616,7 @@ class SectionToolbarState extends State { child: AnimatedOpacity( duration: animationDuration, opacity: widget.musicViewMode != MusicViewMode.section || - isConfirmingDelete || - widget.addPart == null + isConfirmingDelete ? 0 : 1, child: Row(children: [ diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index ae56162b..c1794734 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -222,8 +222,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { SwipeTutorial get currentSwipeTutorial => _currentSwipeTutorial; set currentSwipeTutorial(SwipeTutorial value) { - if (value == null || - _swipeTutorialsSeen[widget.musicViewMode].contains(value)) { + if (_swipeTutorialsSeen[widget.musicViewMode].contains(value)) { _currentSwipeTutorial = null; return; } @@ -271,7 +270,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { if (status == AnimationStatus.completed) { Future.delayed(animationDuration, () { // print("_startValueAnimation onComplete"); - onComplete?.call(); + onComplete.call(); }); } }); @@ -283,18 +282,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { _updateFocusedBeatValue( {int value, bool withDelayClear = true, bool force = false}) { - if (value == null) { - value = getBeat( - Offset( - widget.width / - (context.isLandscape && widget.splitMode == SplitMode.half - ? 4 - : 2), - 0), - targeted: false); - } if (force || - focusedBeat.value == null || DateTime.now().difference(focusedBeatUpdated).inMilliseconds > focusTimeout) { focusedBeat.value = value; @@ -368,8 +356,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { // notifyUpdate(ScaleUpdate(currentValue(), value())); } - if (getLockTime() == null || - DateTime.now().difference(getLockTime()).inMilliseconds > 500) { + if (DateTime.now().difference(getLockTime()).inMilliseconds > 500) { if (lock()) { // print("unlocked"); startAnimation(); @@ -502,17 +489,9 @@ class _MusicViewState extends State with TickerProviderStateMixin { @override Widget build(context) { - if (scale == null || targetedScale == null) { + if (targetedScale == null) { final musicScale = widget.appSettings.musicScale; - if (musicScale == null) { - if (context.isTablet) { - scale = 0.33; - } else { - scale = 0.22; - } - } else { - scale = musicScale; - } + scale = musicScale; targetedScale = scale; } // if (targetedScale != null && @@ -533,9 +512,6 @@ class _MusicViewState extends State with TickerProviderStateMixin { } _previousSplitMode = widget.splitMode; _previousMusicViewMode = widget.musicViewMode; - if (widget.part == null) { - // isConfiguringPart = false; - } if (widget.musicViewMode != MusicViewMode.section) { // isEditingSection = false; } @@ -562,9 +538,8 @@ class _MusicViewState extends State with TickerProviderStateMixin { : (widget.musicViewMode == MusicViewMode.melody) ? Colors.white : (widget.musicViewMode == MusicViewMode.part) - ? ((widget.part != null && - widget.part.instrument.type == - InstrumentType.drum) + ? ((widget.part.instrument.type == + InstrumentType.drum) ? Colors.brown : Colors.grey) : Colors.black, @@ -783,18 +758,13 @@ class _MusicViewState extends State with TickerProviderStateMixin { child: Align( alignment: Alignment.center, child: AnimatedOpacity( - opacity: currentSwipeTutorial == null || - MyPlatform.isMacOS || - MyPlatform.isWeb - ? 0 - : 0.8, + opacity: + MyPlatform.isMacOS || MyPlatform.isWeb + ? 0 + : 0.8, duration: animationDuration, child: AnimatedContainer( - height: - currentSwipeTutorial == null || - _hasSwipedClosed - ? 0 - : 36, + height: _hasSwipedClosed ? 0 : 36, duration: animationDuration, padding: EdgeInsets.symmetric( horizontal: 10), @@ -851,7 +821,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { recordingMelody: recordingMelody, sectionColor: widget.sectionColor, score: widget.score, - melodyId: widget.melody?.id, + melodyId: widget.melody.id, currentSection: widget.currentSection, highlightedBeat: highlightedBeat, setReferenceVolume: widget.setReferenceVolume, @@ -861,8 +831,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { duration: animationDuration, opacity: widget.musicViewMode == MusicViewMode.part ? 1 : 0, child: AnimatedContainer( - color: widget.part != null && - widget.part.instrument.type == InstrumentType.drum + color: widget.part.instrument.type == InstrumentType.drum ? Colors.brown : Colors.grey, duration: animationDuration, @@ -888,8 +857,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { : 0, child: AnimatedContainer( duration: animationDuration, - color: widget.part != null && - widget.part.instrument.type == InstrumentType.drum + color: widget.part.instrument.type == InstrumentType.drum ? Colors.brown : Colors.grey, height: (widget.musicViewMode == MusicViewMode.part && @@ -1013,7 +981,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { final mainPart = this.mainPart(); parts = [mainPart] + widget.score.parts - .where((p) => p.id != mainPart?.id) + .where((p) => p.id != mainPart.id) .toList(growable: false); } final part = parts[max(0, min(parts.length - 1, partIndex))]; @@ -1065,13 +1033,13 @@ class _MusicViewState extends State with TickerProviderStateMixin { staves = []; // print("mainPart=$mainPart"); - if (mainPart != null && mainPart.isHarmonic) { + if (mainPart.isHarmonic) { staves.add(PartStaff(mainPart)); - } else if (mainPart != null && mainPart.isDrum) { + } else if (mainPart.isDrum) { staves.add(DrumStaff()); } staves.addAll(widget.score.parts - .where((part) => part.id != mainPart?.id) + .where((part) => part.id != mainPart.id) .map((part) => (part.isDrum) ? DrumStaff() : PartStaff(part)) .toList(growable: false)); // if (widget.score.parts.any((part) => part.isHarmonic && part != mainPart)) { @@ -1086,12 +1054,11 @@ class _MusicViewState extends State with TickerProviderStateMixin { .toList(growable: false); } - bool focusedPartIsNotFirst = mainPart != null && + bool focusedPartIsNotFirst = widget.score.parts.indexWhere((it) => it.id == mainPart.id) != 0; - bool focusedMelodyIsNotFirst = widget.melody != null && - widget.score.parts.indexWhere( - (p) => p.melodies.any((m) => m.id == widget.melody.id)) != - 0; + bool focusedMelodyIsNotFirst = widget.score.parts.indexWhere( + (p) => p.melodies.any((m) => m.id == widget.melody.id)) != + 0; bool showAutoFocusButton = (widget.musicViewMode == MusicViewMode.part || widget.musicViewMode == MusicViewMode.melody || widget.musicViewMode == MusicViewMode.score) && @@ -1107,11 +1074,8 @@ class _MusicViewState extends State with TickerProviderStateMixin { bool isPartOrMelodyView = widget.musicViewMode == MusicViewMode.part || widget.musicViewMode == MusicViewMode.melody; onLongPress() { - if (widget.score.parts.isEmpty || - tappedPart.value == null || - tappedBeat.value == null) return; + if (widget.score.parts.isEmpty) return; final part = tappedPart.value; - if (part == null) return; HapticFeedback.lightImpact(); if (widget.musicViewMode == MusicViewMode.score) { widget.setKeyboardPart(part); @@ -1181,7 +1145,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { pointerDown(details.localPosition); }, onTapUp: (details) { - if (ignoreNextTap || tappedBeat.value == null) { + if (ignoreNextTap) { return; } int beat = tappedBeat.value; diff --git a/lib/music_view/part_instrument_picker.dart b/lib/music_view/part_instrument_picker.dart index ce6ec7f1..361a297b 100644 --- a/lib/music_view/part_instrument_picker.dart +++ b/lib/music_view/part_instrument_picker.dart @@ -37,28 +37,26 @@ class _PartConfigurationState extends State { TextEditingController searchController = TextEditingController(); ScrollController scrollController = ScrollController(); - int get midiChannel => widget.part?.instrument?.midiChannel; + int get midiChannel => widget.part.instrument.midiChannel; - int get midiInstrument => widget.part?.instrument?.midiInstrument; + int get midiInstrument => widget.part.instrument.midiInstrument; - int get midiMsb => widget.part?.instrument?.midiGm2Msb; + int get midiMsb => widget.part.instrument.midiGm2Msb; - int get midiLsb => widget.part?.instrument?.midiGm2Lsb; + int get midiLsb => widget.part.instrument.midiGm2Lsb; set midiChannel(int value) { - widget.part?.instrument?.midiChannel = value; + widget.part.instrument.midiChannel = value; } set midiInstrument(int value) { var part = widget.part; - if (part != null) { - part.instrument.midiInstrument = value; - } + part.instrument.midiInstrument = value; } - bool get isHarmonic => widget?.part?.isHarmonic ?? false; + bool get isHarmonic => widget.part.isHarmonic ?? false; - bool get isDrum => widget?.part?.isDrum ?? false; + bool get isDrum => widget.part.isDrum ?? false; String searchText = ""; Widget _buildMidiInstrumentDisplay( @@ -191,7 +189,7 @@ class _PartConfigurationState extends State { onChanged: (value) { widget.superSetState(() { setState(() { - widget.part?.instrument?.volume = value; + widget.part.instrument.volume = value; BeatScratchPlugin.updatePartConfiguration( widget.part); }); diff --git a/lib/music_view/part_melody_browser.dart b/lib/music_view/part_melody_browser.dart index a2468dfa..6b677a67 100644 --- a/lib/music_view/part_melody_browser.dart +++ b/lib/music_view/part_melody_browser.dart @@ -163,7 +163,7 @@ class _PartMelodyBrowserState extends State } Widget getList(BuildContext context) { - var items = widget.part?.melodies ?? []; + var items = widget.part.melodies ?? []; items.sort((m1, m2) { final r1 = widget.currentSection.referenceTo(m1); final r2 = widget.currentSection.referenceTo(m2); diff --git a/lib/recording/recording.dart b/lib/recording/recording.dart index 3dba0f42..a86141ac 100644 --- a/lib/recording/recording.dart +++ b/lib/recording/recording.dart @@ -16,7 +16,7 @@ class RecordedSegmentQueue { /// Should be set in [State.initState] and [State.dispose] for static Function(Melody) updateRecordingMelody; - static Melody get recordingMelody => getRecordingMelody?.call(); + static Melody get recordingMelody => getRecordingMelody.call(); // static set recordingMelody(Melody melody) => updateRecordingMelody(melody); static final Queue segments = ListQueue(); static final BSValueMethod enabled = BSValueMethod(false) @@ -48,20 +48,18 @@ class RecordedSegmentQueue { static _processSegment(RecordedSegment segment) { if (segment.recordedData.isEmpty) return; final melody = recordingMelody; - if (melody != null) { - RecordedSegment_RecordedBeat firstBeat = - segment.beats.minBy((rb) => rb.timestamp.toInt()); - RecordedSegment_RecordedBeat secondBeat = - segment.beats.maxBy((rb) => rb.timestamp.toInt()); - segment.recordedData.forEach((data) { - _processSegmentData(segment, data, melody, firstBeat, secondBeat); - }); - print("applying PostProcessing: separateNoteOnAndOffs()"); - melody.separateNoteOnAndOffs(); - print("updateRecordingMelody?.call: ${melody.logString}"); - updateRecordingMelody?.call(melody); - BeatScratchPlugin.updateMelody(melody); - } + RecordedSegment_RecordedBeat firstBeat = + segment.beats.minBy((rb) => rb.timestamp.toInt()); + RecordedSegment_RecordedBeat secondBeat = + segment.beats.maxBy((rb) => rb.timestamp.toInt()); + segment.recordedData.forEach((data) { + _processSegmentData(segment, data, melody, firstBeat, secondBeat); + }); + print("applying PostProcessing: separateNoteOnAndOffs()"); + melody.separateNoteOnAndOffs(); + print("updateRecordingMelody?.call: ${melody.logString}"); + updateRecordingMelody?.call(melody); + BeatScratchPlugin.updateMelody(melody); } static _processSegmentData( diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 375e3cf9..49a52b29 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -26,115 +26,114 @@ class AppSettings { melodyColor = darkMode ? Color(0xFF424242) : Color(0xFFDDDDDD); globalRenderingMode = renderingMode; if (!initializingState) { - BeatScratchPlugin.onSynthesizerStatusChange?.call(); + BeatScratchPlugin.onSynthesizerStatusChange.call(); } } RenderingMode get renderingMode => RenderingMode.values.firstWhere( - (rm) => rm.index == (_preferences?.getInt('renderingMode') ?? 0)); + (rm) => rm.index == (_preferences.getInt('renderingMode') ?? 0)); set renderingMode(RenderingMode rm) { globalRenderingMode = rm; - _preferences?.setInt('renderingMode', rm.index); + _preferences.setInt('renderingMode', rm.index); } List get controllersReplacingKeyboard => - _preferences?.getStringList('controllersReplacingKeyboard') ?? []; + _preferences.getStringList('controllersReplacingKeyboard') ?? []; set controllersReplacingKeyboard(List value) => - _preferences?.setStringList("controllersReplacingKeyboard", value); + _preferences.setStringList("controllersReplacingKeyboard", value); - bool get integratePastee => _preferences?.getBool('integratePastee') ?? true; + bool get integratePastee => _preferences.getBool('integratePastee') ?? true; set integratePastee(bool value) => - _preferences?.setBool("integratePastee", value); + _preferences.setBool("integratePastee", value); - bool get darkMode => _preferences?.getBool('darkMode') ?? true; + bool get darkMode => _preferences.getBool('darkMode') ?? true; set darkMode(bool value) { - _preferences?.setBool("darkMode", value); + _preferences.setBool("darkMode", value); _updateColors(); } - bool get autoScrollLayers => - _preferences?.getBool('autoScrollLayers') ?? true; + bool get autoScrollLayers => _preferences.getBool('autoScrollLayers') ?? true; set autoScrollLayers(bool value) { - _preferences?.setBool("autoScrollLayers", value); + _preferences.setBool("autoScrollLayers", value); } double get layersColumnWidth => - _preferences?.getDouble('layersColumnWidth') ?? 100; + _preferences.getDouble('layersColumnWidth') ?? 100; set layersColumnWidth(double value) => - _preferences?.setDouble("layersColumnWidth", value); + _preferences.setDouble("layersColumnWidth", value); - bool get autoScrollMusic => _preferences?.getBool('autoScrollMusic') ?? true; + bool get autoScrollMusic => _preferences.getBool('autoScrollMusic') ?? true; set autoScrollMusic(bool value) { - _preferences?.setBool("autoScrollMusic", value); + _preferences.setBool("autoScrollMusic", value); } - bool get autoSortMusic => _preferences?.getBool('autoSortMusic') ?? true; + bool get autoSortMusic => _preferences.getBool('autoSortMusic') ?? true; set autoSortMusic(bool value) { - _preferences?.setBool("autoSortMusic", value); + _preferences.setBool("autoSortMusic", value); } bool get autoZoomAlignMusic => - _preferences?.getBool('autoZoomAlignMusic') ?? true; + _preferences.getBool('autoZoomAlignMusic') ?? true; set autoZoomAlignMusic(bool value) { - _preferences?.setBool("autoZoomAlignMusic", value); + _preferences.setBool("autoZoomAlignMusic", value); } - double get musicScale => _preferences?.getDouble('musicScale'); - set musicScale(double value) => _preferences?.setDouble("musicScale", value); + double get musicScale => _preferences.getDouble('musicScale'); + set musicScale(double value) => _preferences.setDouble("musicScale", value); - bool get alignMusic => _preferences?.getBool('alignMusic') ?? true; + bool get alignMusic => _preferences.getBool('alignMusic') ?? true; set alignMusic(bool value) { - _preferences?.setBool("alignMusic", value); + _preferences.setBool("alignMusic", value); } - bool get partAlignMusic => _preferences?.getBool('partAlignMusic') ?? false; + bool get partAlignMusic => _preferences.getBool('partAlignMusic') ?? false; set partAlignMusic(bool value) { - _preferences?.setBool("partAlignMusic", value); + _preferences.setBool("partAlignMusic", value); } RenderingMode get renderMode => RenderingMode.values.firstWhere( (m) => m.toString().endsWith(_preferences.getString('renderMode')), orElse: () => RenderingMode.notation); - set renderMode(RenderingMode value) => _preferences?.setString( + set renderMode(RenderingMode value) => _preferences.setString( "musicRenderingType", value.toString().split('.').last); - bool get keyboard3DTouch => _preferences?.getBool('keyboard3DTouch') ?? false; + bool get keyboard3DTouch => _preferences.getBool('keyboard3DTouch') ?? false; set keyboard3DTouch(bool value) { - _preferences?.setBool("keyboard3DTouch", value); + _preferences.setBool("keyboard3DTouch", value); } - bool get showBeatsBadges => _preferences?.getBool('showBeatsBadges') ?? false; + bool get showBeatsBadges => _preferences.getBool('showBeatsBadges') ?? false; set showBeatsBadges(bool value) { - _preferences?.setBool("showBeatsBadges", value); + _preferences.setBool("showBeatsBadges", value); } double get keyboardHalfStepWidth => - _preferences?.getDouble('keyboardHalfStepWidth') ?? 35.0; + _preferences.getDouble('keyboardHalfStepWidth') ?? 35.0; set keyboardHalfStepWidth(double value) => - _preferences?.setDouble("keyboardHalfStepWidth", value); + _preferences.setDouble("keyboardHalfStepWidth", value); bool get enableUniverse => true; //_preferences?.getBool('enableUniverse') ?? false; set enableUniverse(bool value) { - _preferences?.setBool("enableUniverse", value); + _preferences.setBool("enableUniverse", value); } bool get enableApollo => MyPlatform.isIOS && enableUniverse && - (_preferences?.getBool('enableApollo') ?? false); + (_preferences.getBool('enableApollo') ?? false); set enableApollo(bool value) { - _preferences?.setBool("enableApollo", value); + _preferences.setBool("enableApollo", value); } bool get showWebDownloadLinks => MyPlatform.isWeb && - (_preferences?.getBool('showWebDownloadLinks') ?? MyPlatform.isWeb); + (_preferences.getBool('showWebDownloadLinks') ?? MyPlatform.isWeb); set showWebDownloadLinks(bool value) { - _preferences?.setBool("showWebDownloadLinks", value); + _preferences.setBool("showWebDownloadLinks", value); } - int get systemsToRender => _preferences?.getInt('systemsToRender') ?? 0; + int get systemsToRender => _preferences.getInt('systemsToRender') ?? 0; set systemsToRender(int value) => - _preferences?.setInt("systemsToRender", value); + _preferences.setInt("systemsToRender", value); } diff --git a/lib/settings/settings_common.dart b/lib/settings/settings_common.dart index 73f3e079..abfe6f06 100644 --- a/lib/settings/settings_common.dart +++ b/lib/settings/settings_common.dart @@ -10,7 +10,7 @@ extension Sanitize on String { } extension ControllerNameOrId on MidiController { - String get nameOrId => (name?.isNotEmpty == true) ? name : id; + String get nameOrId => (name.isNotEmpty == true) ? name : id; } const Map supportedAndroidSynthApps = { diff --git a/lib/settings/settings_panel.dart b/lib/settings/settings_panel.dart index f6924955..b73e5b67 100644 --- a/lib/settings/settings_panel.dart +++ b/lib/settings/settings_panel.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'package:dart_midi/dart_midi.dart'; -import 'package:dart_midi/src/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_events.dart'; import '../messages/messages_ui.dart'; import 'tile_bluetooth.dart'; @@ -45,7 +45,7 @@ class SettingsPanel extends StatefulWidget { final Part keyboardPart; const SettingsPanel( - {Key key, + {Key? key, required this.appSettings, required this.universeManager, required this.sectionColor, @@ -71,15 +71,15 @@ class _SettingsPanelState extends State { BeatScratchPlugin.midiControllers; Iterable get midiSynthesizers => BeatScratchPlugin.midiSynthesizers; - List observedDevices; - List connectedDeviceIds; - StreamSubscription midiCommandSubscription; + late List observedDevices; + late List connectedDeviceIds; + late StreamSubscription? midiCommandSubscription; _startBluetoothScanLoop() async { MidiCommand().devices.then((results) { - observedDevices = results.where((r) => r.type == "BLE").toList(); + observedDevices = results?.where((r) => r.type == "BLE").toList() ?? []; connectedDeviceIds - .removeWhere((id) => !observedDevices.any((d) => d.id == id)); + .removeWhere((id) => !observedDevices!.any((d) => d.id == id)); Future.delayed( Duration(seconds: widget.visible ? 5 : 15), _startBluetoothScanLoop); }); @@ -103,13 +103,13 @@ class _SettingsPanelState extends State { if (e is NoteOnEvent) { e.channel = widget.keyboardPart.instrument.midiChannel; e.writeEvent(writer); - widget.bluetoothControllerPressedNotes.value[event.device.id] + widget.bluetoothControllerPressedNotes.value[event.device.id]! .add(e.noteNumber - 60); widget.bluetoothControllerPressedNotes.notifyListeners(); } else if (e is NoteOffEvent) { e.channel = widget.keyboardPart.instrument.midiChannel; e.writeEvent(writer); - widget.bluetoothControllerPressedNotes.value[event.device.id] + widget.bluetoothControllerPressedNotes.value[event.device.id]! .remove(e.noteNumber - 60); widget.bluetoothControllerPressedNotes.notifyListeners(); } @@ -167,7 +167,7 @@ class _SettingsPanelState extends State { BeatScratchPlugin.supportsSynthesizerConfig ? this.midiSynthesizers.toList() : [this.midiSynthesizers.toList().first]; - List appSettings = [ + List appSettings = [ SeparatorTile(text: "App Settings", id: "app-settings"), SettingsTile( id: "pasteeIntegration", @@ -479,7 +479,7 @@ class _SettingsPanelState extends State { ...appSettings, ...features, ]; - return ImplicitlyAnimatedList( + return ImplicitlyAnimatedList( key: ValueKey("MidiSettingsList"), scrollDirection: Axis.horizontal, spawnIsolate: false, @@ -493,7 +493,7 @@ class _SettingsPanelState extends State { return SizedBox(); } final dynamic item = items[index]; - Widget tile; + Widget? tile; if (item is MidiController) { tile = MidiControllerTile( appSettings: widget.appSettings, @@ -703,3 +703,7 @@ showColors(BuildContext context, Color sectionColor) { ), ); } + +abstract class Identifiable { + String get id; +} diff --git a/lib/settings/tile.dart b/lib/settings/tile.dart index 4f42c631..333012b0 100644 --- a/lib/settings/tile.dart +++ b/lib/settings/tile.dart @@ -1,18 +1,18 @@ - +import 'package:beatscratch_flutter_redux/settings/settings.dart'; import 'package:flutter/material.dart'; import '../ui_models.dart'; import '../widget/my_buttons.dart'; -class SettingsTile extends StatelessWidget { +class SettingsTile extends StatelessWidget implements Identifiable { final String id; - final Widget child; - final Color color; - final VoidCallback onPressed; + final Widget? child; + final Color? color; + final VoidCallback? onPressed; const SettingsTile({ - Key key, - this.id, + Key? key, + required this.id, this.child, this.color, this.onPressed, @@ -36,14 +36,14 @@ class SettingsTile extends StatelessWidget { } } -class SeparatorTile extends StatelessWidget { +class SeparatorTile extends StatelessWidget implements Identifiable { final String text; final String id; const SeparatorTile({ - Key key, - this.text, - this.id, + Key? key, + required this.text, + required this.id, }) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/storage/migrations.dart b/lib/storage/migrations.dart index 0156f07a..e15bb731 100644 --- a/lib/storage/migrations.dart +++ b/lib/storage/migrations.dart @@ -16,13 +16,13 @@ extension Migrations on Score { _setBpmsOnSections() { double firstSeenBpm; for (Section section in sections) { - if (section.tempo != null && section.tempo.bpm != null) { + if (section.tempo.bpm != null) { firstSeenBpm = section.tempo.bpm; break; } } sections.forEach((section) { - if (section.tempo == null || section.tempo.bpm == null) { + if (section.tempo.bpm == null) { section.tempo = Tempo()..bpm = firstSeenBpm ?? 123; } }); diff --git a/lib/storage/score_manager.dart b/lib/storage/score_manager.dart index b8d03013..6a6bd5eb 100644 --- a/lib/storage/score_manager.dart +++ b/lib/storage/score_manager.dart @@ -31,24 +31,22 @@ class ScoreManager { SharedPreferences _prefs; String get currentScoreName => - _prefs?.getString('currentScoreName') ?? UNIVERSE_SCORE; + _prefs.getString('currentScoreName') ?? UNIVERSE_SCORE; set currentScoreName(String value) => - _prefs?.setString("currentScoreName", value); + _prefs.setString("currentScoreName", value); File get currentScoreFile => File( "${scoresDirectory.path}/${Uri.encodeComponent(currentScoreName).replaceAll("%20", " ")}.beatscratch"); List get scoreFiles { - if (scoresDirectory != null) { - List result = scoresDirectory - ?.listSync() - .where((f) => f.path.endsWith(".beatscratch")) - .toList(); - result.sort( - (a, b) => b.statSync().modified.compareTo(a.statSync().modified)); - return result; - } + List result = scoresDirectory + ?.listSync() + .where((f) => f.path.endsWith(".beatscratch")) + .toList(); + result + .sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified)); + return result; return []; } @@ -108,7 +106,7 @@ class ScoreManager { } catch (e) { score = defaultScore(); } - doOpenScore?.call(score); + doOpenScore.call(score); } loadFromScoreUrl(String scoreUrl, @@ -126,7 +124,7 @@ class ScoreManager { throw Exception("nope"); } Score score = scoreFromUrlHashValue(scoreUrl); - if (score == null || score.sections.isEmpty) { + if (score.sections.isEmpty) { throw Exception("nope"); } String scoreName = score.name ?? ""; @@ -136,13 +134,11 @@ class ScoreManager { } else { suggestedScoreName += newScoreNameSuffix; } - if (currentScoreToSave != null) { - saveCurrentScore(currentScoreToSave); - } + saveCurrentScore(currentScoreToSave); openScoreWithFilename( score, newScoreDefaultFilename); // side-effect: updates this.score _lastSuggestedScoreName = suggestedScoreName; - onSuccess?.call(suggestedScoreName); + onSuccess.call(suggestedScoreName); } catch (any) { loadPastebinScoreIntoUI(scoreUrl, newScoreDefaultFilename: newScoreDefaultFilename, @@ -180,9 +176,7 @@ class ScoreManager { longUrl = longUrl.replaceFirst(new RegExp(r'http.*#/score/'), ''); Score score = scoreFromUrlHashValue(longUrl); - if (titleOverride != null) { - score.name = titleOverride; - } + score.name = titleOverride; return score; } @@ -192,9 +186,6 @@ class ScoreManager { Score currentScoreToSave, VoidCallback onFail, Function(String) onSuccess}) async { - if (pastebinCode == null) { - return; - } try { Score score = await loadPastebinScore(pastebinCode); String scoreName = score.name ?? ""; @@ -205,17 +196,15 @@ class ScoreManager { suggestedScoreName += newScoreNameSuffix; } if (BeatScratchPlugin.supportsStorage) { - if (currentScoreToSave != null) { - saveCurrentScore(currentScoreToSave); - } + saveCurrentScore(currentScoreToSave); openScoreWithFilename(score, newScoreDefaultFilename); } else { doOpenScore(score); } - onSuccess?.call(suggestedScoreName); + onSuccess.call(suggestedScoreName); _lastSuggestedScoreName = suggestedScoreName; } catch (any) { - onFail?.call(); + onFail.call(); } } @@ -233,7 +222,7 @@ class ScoreManager { extension ScoreName on FileSystemEntity { String get scoreName { - String fileName = path.split("/")?.last ?? ".beatscratch"; + String fileName = path.split("/").last ?? ".beatscratch"; fileName = fileName.substring(0, max(0, fileName.length - 12)); String scoreName = Uri.decodeComponent(fileName.replaceAll(" ", "%20")); return scoreName; diff --git a/lib/storage/score_picker.dart b/lib/storage/score_picker.dart index c1ae74ff..aff290a5 100644 --- a/lib/storage/score_picker.dart +++ b/lib/storage/score_picker.dart @@ -96,8 +96,7 @@ class ScorePickerState extends State { String overwritingScoreName; BSMethod universeAnimation = BSMethod(); - bool get wasShowingScoreNameEntry => - previousMode?.showScoreNameEntry ?? false; + bool get wasShowingScoreNameEntry => previousMode.showScoreNameEntry ?? false; @override initState() { @@ -256,7 +255,7 @@ class ScorePickerState extends State { animateIcon: universeAnimation, )), )), - if (icon != null && operationText.isNotEmpty) + if (operationText.isNotEmpty) MyFlatButton( padding: EdgeInsets.zero, lightHighlight: true, @@ -620,11 +619,8 @@ class ScorePickerState extends State { } else { return scoreManager.scoreFiles.map((scoreFile) { Future loadScore() async { - if (scoreFile == null) { - return Future.value(defaultScore()); - } try { - final data = await File(scoreFile?.path).readAsBytes(); + final data = await File(scoreFile.path).readAsBytes(); return Score.fromBuffer(data); } catch (e) { @@ -645,7 +641,7 @@ class ScorePickerState extends State { spawnIsolate: false, controller: _scrollController, items: scores, - areItemsTheSame: (a, b) => a?.identity == b?.identity, + areItemsTheSame: (a, b) => a.identity == b.identity, // Called, as needed, to build list item widgets. // List items are only built when they're scrolled into view. itemBuilder: (context, animation, section, index) { @@ -653,7 +649,7 @@ class ScorePickerState extends State { if (index < scores.length) { scoreFuture = scores[index]; } - File scoreFile = scoreFuture?.file; + File scoreFile = scoreFuture.file; Widget tile = ScorePickerPreview( sectionColor: widget.sectionColor, @@ -666,10 +662,8 @@ class ScorePickerState extends State { : () { switch (widget.mode) { case ScorePickerMode.open: - if (scoreFile != null) { - widget.scoreManager.openScore(scoreFile); - widget.universeManager.currentUniverseScore = ""; - } + widget.scoreManager.openScore(scoreFile); + widget.universeManager.currentUniverseScore = ""; break; case ScorePickerMode.universe: if (BeatScratchPlugin.supportsStorage) { @@ -684,19 +678,17 @@ class ScorePickerState extends State { }); break; default: - String scoreName = scoreFile?.scoreName; - if (scoreName != null) { - nameController.clear(); - setState(() { - nameController.value = - nameController.value.copyWith(text: scoreName); - }); - } + String scoreName = scoreFile.scoreName; + nameController.clear(); + setState(() { + nameController.value = + nameController.value.copyWith(text: scoreName); + }); } }, scoreManager: scoreManager, universeManager: widget.universeManager, - scoreKey: (scoreFile?.lastModifiedSync() ?? DateTime(0)).hashCode, + scoreKey: (scoreFile.lastModifiedSync() ?? DateTime(0)).hashCode, scoreFuture: scoreFuture, deleteScore: widget.mode == ScorePickerMode.universe ? null @@ -737,7 +729,7 @@ class ScorePickerState extends State { bottom: widget.scrollDirection == Axis.vertical ? 10 : 0), child: tile); return SizeFadeTransition( - key: ValueKey("ScorePickerTile-${scoreFuture?.identity}"), + key: ValueKey("ScorePickerTile-${scoreFuture.identity}"), sizeFraction: 0.7, curve: Curves.easeInOut, axis: widget.scrollDirection, diff --git a/lib/storage/score_picker_preview.dart b/lib/storage/score_picker_preview.dart index e6124831..3bb3a832 100644 --- a/lib/storage/score_picker_preview.dart +++ b/lib/storage/score_picker_preview.dart @@ -56,30 +56,21 @@ class ScoreFuture { String get identity => filePath ?? "//universe-score://$scoreUrl"; FileSystemEntity get file { - if (filePath != null) { - try { - return File(filePath); - } catch (e) { - print("Error loading score from file: $e"); - } + try { + return File(filePath); + } catch (e) { + print("Error loading score from file: $e"); } return null; } Future loadScore(ScoreManager scoreManager) async { - if (this.file != null) { - return loadScoreFromFile(); - } else { - return loadScoreFromUniverse(scoreManager); - } + return loadScoreFromFile(); } Future loadScoreFromFile() async { - if (file == null) { - return Future.value(defaultScore()); - } try { - final data = await File(file?.path).readAsBytes(); + final data = await File(file.path).readAsBytes(); return Score.fromBuffer(data); } catch (e) { @@ -94,9 +85,6 @@ class ScoreFuture { scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#/s/'), ''); try { final score = scoreFromUrlHashValue(scoreUrl); - if (score == null) { - throw "failed to load"; - } return score..name = title; } catch (e) { try { @@ -175,9 +163,9 @@ class _ScorePickerPreviewState extends State { } String get unloadedScoreName => - widget.scoreFuture?.title ?? widget.scoreFuture?.file?.scoreName ?? ""; + widget.scoreFuture.title ?? widget.scoreFuture.file.scoreName ?? ""; - bool get isUniverse => widget.scoreFuture?.voteCount != null; + bool get isUniverse => widget.scoreFuture.voteCount != null; @override Widget build(BuildContext context) { final scoreName = unloadedScoreName; @@ -185,7 +173,7 @@ class _ScorePickerPreviewState extends State { ? widget.scoreFuture.identity == widget.universeManager.currentUniverseScore : unloadedScoreName == widget.scoreManager.currentScoreName; - if (widget.scoreKey != _lastScoreKey && widget.scoreFuture != null) { + if (widget.scoreKey != _lastScoreKey) { _confirmingDelete = false; _confirmingOverwrite = false; _previewScore = null; @@ -222,7 +210,7 @@ class _ScorePickerPreviewState extends State { // if (previewScore == null) { // previewScore = defaultScore(); // } - if (previewScore?.sections?.isEmpty == true) { + if (previewScore.sections.isEmpty == true) { previewScore.sections.add(defaultSection()); } final actualScoreName = isUniverse @@ -239,8 +227,8 @@ class _ScorePickerPreviewState extends State { return Row(children: [ AnimatedContainer( duration: animationDuration, - width: /*widget.scoreFuture?.loadScore != null ? */ widget - .width /*: 0*/, + width: /*widget.scoreFuture?.loadScore != null ? */ + widget.width /*: 0*/, height: widget.height, color: backgroundColor, padding: EdgeInsets.zero, @@ -440,7 +428,7 @@ class _ScorePickerPreviewState extends State { alignment: Alignment.bottomLeft, child: AnimatedOpacity( duration: animationDuration, - opacity: widget.scoreFuture?.author != null ? 1 : 0, + opacity: widget.scoreFuture.author != null ? 1 : 0, child: Container( height: 36, padding: EdgeInsets.all(5), @@ -459,7 +447,7 @@ class _ScorePickerPreviewState extends State { fontSize: 8)) ]), SizedBox(width: 5), - Text(widget.scoreFuture?.author ?? "", + Text(widget.scoreFuture.author ?? "", style: TextStyle( color: musicForegroundColor, fontWeight: FontWeight.w700)) @@ -477,70 +465,70 @@ class _ScorePickerPreviewState extends State { child: Column( children: [ MyFlatButton( - color: widget.scoreFuture?.likes == true + color: widget.scoreFuture.likes == true ? chromaticSteps[11] : Colors.transparent, padding: EdgeInsets.symmetric(vertical: 5), onPressed: widget.universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = widget.scoreFuture?.likes; + bool oldValue = widget.scoreFuture.likes; setState(() { if (oldValue == true) { - widget.scoreFuture?.likes = null; + widget.scoreFuture.likes = null; widget.scoreFuture.voteCount -= 1; } else { - widget.scoreFuture?.likes = true; + widget.scoreFuture.likes = true; widget.scoreFuture.voteCount += oldValue == null ? 1 : 2; } widget.universeManager.vote( - widget.scoreFuture?.fullName, - widget.scoreFuture?.likes); + widget.scoreFuture.fullName, + widget.scoreFuture.likes); }); } : null, child: Icon(Icons.arrow_upward, color: widget.universeManager.isAuthenticated - ? widget.scoreFuture?.likes == true + ? widget.scoreFuture.likes == true ? chromaticSteps[11].textColor() : chromaticSteps[11] : musicForegroundColor.withOpacity(0.5))), Row(children: [ Expanded(child: SizedBox()), - Text(widget.scoreFuture?.voteCount?.toString() ?? '', + Text(widget.scoreFuture.voteCount.toString() ?? '', style: TextStyle( color: musicForegroundColor, fontWeight: FontWeight.w800)), Expanded(child: SizedBox()), ]), MyFlatButton( - color: widget.scoreFuture?.likes == false + color: widget.scoreFuture.likes == false ? chromaticSteps[10] : Colors.transparent, padding: EdgeInsets.symmetric(vertical: 5), onPressed: widget.universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = widget.scoreFuture?.likes; + bool oldValue = widget.scoreFuture.likes; setState(() { if (oldValue == false) { - widget.scoreFuture?.likes = null; + widget.scoreFuture.likes = null; widget.scoreFuture.voteCount += 1; } else { - widget.scoreFuture?.likes = false; + widget.scoreFuture.likes = false; widget.scoreFuture.voteCount -= oldValue == null ? 1 : 2; } widget.universeManager.vote( - widget.scoreFuture?.fullName, - widget.scoreFuture?.likes); + widget.scoreFuture.fullName, + widget.scoreFuture.likes); }); } : null, child: Icon(Icons.arrow_downward, color: widget.universeManager.isAuthenticated - ? widget.scoreFuture?.likes == false + ? widget.scoreFuture.likes == false ? chromaticSteps[10].textColor() : chromaticSteps[10] : musicForegroundColor.withOpacity(0.5))), diff --git a/lib/storage/universe_manager.dart b/lib/storage/universe_manager.dart index 437e1fac..b015011a 100644 --- a/lib/storage/universe_manager.dart +++ b/lib/storage/universe_manager.dart @@ -29,31 +29,29 @@ class UniverseManager { _initialize(); } - bool get useWebViewSignIn => _prefs?.getBool('useWebViewSignIn') ?? false; - set useWebViewSignIn(bool v) => _prefs?.setBool("useWebViewSignIn", v); + bool get useWebViewSignIn => _prefs.getBool('useWebViewSignIn') ?? false; + set useWebViewSignIn(bool v) => _prefs.setBool("useWebViewSignIn", v); String get currentUniverseScore => - _prefs?.getString('currentUniverseScore') ?? ''; + _prefs.getString('currentUniverseScore') ?? ''; set currentUniverseScore(String v) => - _prefs?.setString("currentUniverseScore", v); + _prefs.setString("currentUniverseScore", v); ScoreFuture get currentUniverseScoreFuture => currentUniverseScore == '' ? null : cachedUniverseData.firstWhere((d) => d.identity == currentUniverseScore, orElse: () => null); - String get redditRefreshToken => - _prefs?.getString('redditRefreshToken') ?? ""; + String get redditRefreshToken => _prefs.getString('redditRefreshToken') ?? ""; set redditRefreshToken(String value) => - _prefs?.setString("redditRefreshToken", value); + _prefs.setString("redditRefreshToken", value); - String get redditAccessToken => _prefs?.getString('redditAccessToken') ?? ""; + String get redditAccessToken => _prefs.getString('redditAccessToken') ?? ""; set redditAccessToken(String value) => - _prefs?.setString("redditAccessToken", value); + _prefs.setString("redditAccessToken", value); - String get redditUsername => _prefs?.getString('redditUsername') ?? ""; - set redditUsername(String value) => - _prefs?.setString("redditUsername", value); + String get redditUsername => _prefs.getString('redditUsername') ?? ""; + set redditUsername(String value) => _prefs.setString("redditUsername", value); static const String DEFAULT_UNIVERSE_DATA_STRING = '[{"filePath":null,"title":"Tropico-Pastoral","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/n5f1s1/tropicopastoral/","voteCount":1,"likes":true,"fullName":"t3_n5f1s1","scoreUrl":"https://beatscratch.io/app/#/s/CZZX0"},{"filePath":null,"title":"A cheesy educational intro","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/myliqr/a_cheesy_educational_intro/","voteCount":1,"likes":true,"fullName":"t3_myliqr","scoreUrl":"https://beatscratch.io/app/#/s/ORXsf"},{"filePath":null,"title":"A longer, original demo using 5 instruments","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/my7ajg/a_longer_original_demo_using_5_instruments/","voteCount":1,"likes":true,"fullName":"t3_my7ajg","scoreUrl":"https://beatscratch.io/app/#/s/Z4hZh"},{"filePath":null,"title":"2021, From Jacob Collier’s Insta","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/mwyv7m/2021_from_jacob_colliers_insta/","voteCount":1,"likes":null,"fullName":"t3_mwyv7m","scoreUrl":"https://beatscratch.io/app/#/s/5dVNM"},{"filePath":null,"title":"Tee Time 2.6","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/lnmxyh/tee_time_26/","voteCount":1,"likes":null,"fullName":"t3_lnmxyh","scoreUrl":"https://beatscratch.io/app/#/s/rx0w0"}]'; @@ -64,7 +62,7 @@ class UniverseManager { ..putIfAbsent("likes", () => null)))) .toList(); List get __cachedUniverseData => - (_prefs?.getStringList('cachedUniverseData') ?? DEFAULT_UNIVERSE_DATA) + (_prefs.getStringList('cachedUniverseData') ?? DEFAULT_UNIVERSE_DATA) .map((it) => ScoreFuture.fromJson(jsonDecode(it))) .toList(); List _cachedUniverseData = []; @@ -72,7 +70,7 @@ class UniverseManager { List get cachedUniverseData => _cachedUniverseData; set cachedUniverseData(List value) { _cachedUniverseData = value; - Future.microtask(() => _prefs?.setStringList("cachedUniverseData", + Future.microtask(() => _prefs.setStringList("cachedUniverseData", value.map((it) => jsonEncode(it.toJson())).toList())); } @@ -85,8 +83,8 @@ class UniverseManager { refreshAccessToken(andPoll: true); } - String get _authState => _prefs?.getString('redditAuthState') ?? ""; - set _authState(String value) => _prefs?.setString("redditAuthState", value); + String get _authState => _prefs.getString('redditAuthState') ?? ""; + set _authState(String value) => _prefs.setString("redditAuthState", value); initiateSignIn() { _authState = uuid.v4(); @@ -106,7 +104,7 @@ class UniverseManager { final uri = Uri.parse(authUrl); String state = uri.queryParameters["state"]; String code = uri.queryParameters["code"]; - if (state != null && code != null) { + if (code != null) { if (state != _authState) { messagesUI.sendMessage( message: "Auth codes did not match!", @@ -133,7 +131,7 @@ class UniverseManager { final data = jsonDecode(response.body); String accessToken = data['access_token']; String refreshToken = data['refresh_token']; - if (accessToken != null && refreshToken != null) { + if (refreshToken != null) { redditRefreshToken = refreshToken; redditAccessToken = accessToken; loadRedditUsername(); @@ -182,17 +180,13 @@ class UniverseManager { final username = data['name']; if (username != null) { redditUsername = username; - if (messagesUI != null) { - messagesUI.sendMessage( - message: "Reddit authentication successful!", andSetState: true); - } + messagesUI.sendMessage( + message: "Reddit authentication successful!", andSetState: true); } else { - if (messagesUI != null) { - messagesUI.sendMessage( - message: "Failed to load Reddit user information!", - isError: true, - andSetState: true); - } + messagesUI.sendMessage( + message: "Failed to load Reddit user information!", + isError: true, + andSetState: true); } }); } @@ -225,9 +219,7 @@ class UniverseManager { ).then((response) { final data = jsonDecode(response.body); String accessToken = data['access_token']; - if (accessToken != null) { - redditAccessToken = accessToken; - } + redditAccessToken = accessToken; }); } @@ -248,9 +240,7 @@ class UniverseManager { ).then((response) { final data = jsonDecode(response.body); String accessToken = data['access_token']; - if (accessToken != null) { - redditAccessToken = accessToken; - } + redditAccessToken = accessToken; }); } @@ -266,9 +256,6 @@ class UniverseManager { andSetState: true); return null; }); - if (response == null) { - return []; - } if (response.statusCode == 401) { await refreshAccessToken(); return await loadUniverseData(); @@ -415,13 +402,9 @@ class UniverseManager { ScoreFuture scoreFuture = cachedUniverseData.firstWhere( (it) => it.scoreUrl == scoreUrl, orElse: () => null); - if (scoreFuture != null) { - messagesUI.setAppState(() { - currentUniverseScore = scoreFuture.identity; - }); - } else if (retries > 0) { - tryToSelectScore(retries - 1); - } + messagesUI.setAppState(() { + currentUniverseScore = scoreFuture.identity; + }); }); } diff --git a/lib/universe_view/universe_icon.dart b/lib/universe_view/universe_icon.dart index d9ade944..d561da88 100644 --- a/lib/universe_view/universe_icon.dart +++ b/lib/universe_view/universe_icon.dart @@ -51,7 +51,7 @@ class _UniverseIconState extends State end: -2 * pi, ).animate(atomRotationController); - widget.animateIcon?.addListener(() { + widget.animateIcon.addListener(() { if (widget.interactionMode != InteractionMode.universe) { orbitRotationController.forward().then( (_) => (!disposed) ? orbitRotationController.reverse() : null); diff --git a/lib/util/dummydata.dart b/lib/util/dummydata.dart index 0e48dcc0..1d32aa25 100644 --- a/lib/util/dummydata.dart +++ b/lib/util/dummydata.dart @@ -227,7 +227,7 @@ Melody odeToJoyB() => baseMelody() final defaultSubdivisionsPerBeat = 4; -Melody defaultMelody({int sectionBeats}) => baseMelody() +Melody defaultMelody({int? sectionBeats}) => baseMelody() ..subdivisionsPerBeat = defaultSubdivisionsPerBeat ..length = (sectionBeats ?? defaultSectionBeats) * defaultSubdivisionsPerBeat ..interpretationType = MelodyInterpretationType.fixed diff --git a/lib/util/language_utils.dart b/lib/util/language_utils.dart index 5816e800..7c0eba74 100644 --- a/lib/util/language_utils.dart +++ b/lib/util/language_utils.dart @@ -6,7 +6,7 @@ extension Iterables on Iterable { (Map> map, E element) => map..putIfAbsent(keyFunction(element), () => []).add(element)); - E maxBy(num Function(E) valueFunction) => (isEmpty) + E? maxBy(num Function(E) valueFunction) => (isEmpty) ? null : reduce((value, element) { if (value == null) { diff --git a/lib/util/methodcache_utils.dart b/lib/util/methodcache_utils.dart index 8e60a682..4b7e44ef 100644 --- a/lib/util/methodcache_utils.dart +++ b/lib/util/methodcache_utils.dart @@ -31,14 +31,10 @@ class ArgumentList { @override int get hashCode { - int result; + int result = 0; arguments.forEach((arg) { - if (result == null) { - result = arg.hashCode; - } else { - result = result ^ arg.hashCode; - } + result = result ^ arg.hashCode; }); - return result ?? 0; + return result; } } diff --git a/lib/util/midi_theory.dart b/lib/util/midi_theory.dart index b33a3c12..23a2a3f9 100644 --- a/lib/util/midi_theory.dart +++ b/lib/util/midi_theory.dart @@ -1,20 +1,22 @@ -import 'package:dart_midi/dart_midi.dart'; -// ignore: implementation_imports -import 'package:dart_midi/src/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_events.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_parser.dart'; + +import 'package:flutter/foundation.dart'; import 'package:flutter_midi_command/flutter_midi_command.dart'; import '../generated/protos/protos.dart'; import 'util.dart'; extension MidiEventFilters on Iterable { - bool hasNoteOnEvent(int midiNote) => any((it) => - !(it is NoteOnEvent) || (it as NoteOnEvent).noteNumber != midiNote); - bool hasNoteOffEvent(int midiNote) => any((it) => - !(it is NoteOnEvent) || (it as NoteOnEvent).noteNumber != midiNote); - Iterable withoutNoteOnEvents(int midiNote) => where((it) => - !(it is NoteOnEvent) || (it as NoteOnEvent).noteNumber != midiNote); - Iterable withoutNoteOffEvents(int midiNote) => where((it) => - !(it is NoteOffEvent) || (it as NoteOffEvent).noteNumber != midiNote); + bool hasNoteOnEvent(int midiNote) => + any((it) => !(it is NoteOnEvent) || it.noteNumber != midiNote); + bool hasNoteOffEvent(int midiNote) => + any((it) => !(it is NoteOnEvent) || it.noteNumber != midiNote); + Iterable withoutNoteOnEvents(int midiNote) => + where((it) => !(it is NoteOnEvent) || it.noteNumber != midiNote); + Iterable withoutNoteOffEvents(int midiNote) => + where((it) => !(it is NoteOffEvent) || it.noteNumber != midiNote); } extension MidiChangeTheory on MidiChange { @@ -29,7 +31,7 @@ extension MidiChangeTheory on MidiChange { } Iterable get _midiEvents { - if (data == null || data.isEmpty) { + if (data.isEmpty) { return []; } var chunkedData = data.chunked(3); @@ -73,7 +75,7 @@ extension MidiEvents on MidiPacket { } Iterable get _midiEvents { - if (data == null || data.isEmpty) { + if (data.isEmpty) { return []; } var chunkedData = data.chunked(3); @@ -91,7 +93,7 @@ extension MidiEvents on MidiPacket { value.forEach((event) { event.writeEvent(writer); }); - data = writer.buffer; + data = Uint8List.fromList(writer.buffer); // print("done setting midiEvents; data1=${writer.buffer}"); // print("done setting midiEvents; data=$data"); } @@ -113,14 +115,11 @@ extension MidiMelodies on Melody { Map convertedData = Map(); List>> sortedData = simpleData.entries.toList() ..sort((e1, e2) => e1.key.compareTo(e2.key)); - Iterable prevTones; + Iterable prevTones = []; sortedData.forEach((entry) { int key = entry.key; Iterable tones = entry.value; List events = []; - if (prevTones == null) { - prevTones = sortedData.last.value; - } events.addAll(prevTones.map((tone) => NoteOffEvent() ..noteNumber = tone + 60 ..velocity = 127 diff --git a/lib/util/music_notation_theory.dart b/lib/util/music_notation_theory.dart index 1575447f..86e3a615 100644 --- a/lib/util/music_notation_theory.dart +++ b/lib/util/music_notation_theory.dart @@ -1,3 +1,5 @@ +import 'package:collection/collection.dart'; + import '../generated/protos/music.pb.dart'; import 'music_theory.dart'; import 'util.dart'; @@ -25,10 +27,12 @@ class NoteSpecification { @override String toString() => "NoteSpecification:$uiString"; - NoteSpecification({this.noteName, this.octave}); + NoteSpecification({required this.noteName, required this.octave}); NoteSpecification.name( - {NoteLetter letter, NoteSign sign = NoteSign.natural, int octave}) + {required NoteLetter letter, + NoteSign sign = NoteSign.natural, + required int octave}) : this( noteName: (NoteName() ..noteLetter = letter @@ -55,9 +59,9 @@ extension HeptatonicConversions on int { .groupBy(((note) => note.tone)); NoteSpecification get naturalOrSharpNote => - _notesFor[this].firstWhere((note) => note.sign == NoteSign.natural, - orElse: () => null) ?? - _notesFor[this].firstWhere((note) => note.sign == NoteSign.sharp); + _notesFor[this]! + .firstWhereOrNull((note) => note.sign == NoteSign.natural) ?? + _notesFor[this]!.firstWhere((note) => note.sign == NoteSign.sharp); // ignore: unused_field static final Map> _noteNameChordCache = @@ -75,73 +79,74 @@ extension HeptatonicConversions on int { int difference = (this - rootNote.tone).mod12; switch (difference) { case 0: - return _notesFor[this].firstWhere((it) => it.letter == rootNote.letter); + return _notesFor[this]! + .firstWhere((it) => it.letter == rootNote.letter); case 1: - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 1); // m2 case 2: - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 1); // M2 case 3: if (chord.hasAug2) { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 1); // A2 } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 2); // m3 } break; case 4: - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 2); // M3 case 5: - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 3); // P4 case 6: if (chord.hasAug4) { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 3); // A4 } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 4); // d5 } break; case 7: - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 4); // P5 case 8: if (chord.hasAug5) { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 4); // A5 } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 5); // m6 } break; case 9: if (chord.hasDim7) { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 5); // d7 } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 5); // M6 } break; case 10: if (chord.hasAug6) { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 5); // A6 } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 6); // m7 } break; case 11: if (rootNote.sign == NoteSign.double_sharp) { - return _notesFor[this].firstWhere((it) => + return _notesFor[this]!.firstWhere((it) => it.letter == rootNote.letter); // diminished 1 (for readability) } else { - return _notesFor[this] + return _notesFor[this]! .firstWhere((it) => it.letter == rootNote.letter + 6); //M7 } break; diff --git a/lib/util/music_theory.dart b/lib/util/music_theory.dart index 0b4b9eb0..48be725e 100644 --- a/lib/util/music_theory.dart +++ b/lib/util/music_theory.dart @@ -1,3 +1,5 @@ +import 'package:collection/collection.dart'; + import '../util/midi_theory.dart'; import '../generated/protos/music.pb.dart'; @@ -113,8 +115,8 @@ extension NoteConversions on int { extension PatternIndexConversions on int { int convertPatternIndex( - {int fromSubdivisionsPerBeat, - int toSubdivisionsPerBeat, + {int fromSubdivisionsPerBeat = 0, + int toSubdivisionsPerBeat = 0, int toLength = 1000000000}) { // In the storageContext of the "from" melody, in, say, sixteenth notes (subdivisionsPerBeat=4), // if this is 5, then currentBeat is 1.25. @@ -155,17 +157,8 @@ extension ChordTheory on Chord { /// Returns the nearest int closestTone(int tone) { - int result; - range(0, 11).forEach((i) { - if (result == null) { - if (containsTone(tone - i)) { - result = tone - i; - } - if (containsTone(tone + i)) { - result = tone + i; - } - } - }); + int? result; + range(0, 11).forEach((i) {}); if (chroma != 2047) { // print("closest to $tone for ${this.toString().replaceAll("\n", "")} is $result"); } @@ -198,7 +191,7 @@ extension HarmonyTheory on Harmony { Chord _changeBefore(int subdivision) { // final int initialSubdivision = subdivision; - Chord result = data[subdivision]; + Chord? result = data[subdivision]; while (result == null) { subdivision = subdivision - 1; if (subdivision < 0) { @@ -212,12 +205,12 @@ extension HarmonyTheory on Harmony { extension MelodyTheory on Melody { String get idName => "Melody ${id.substring(0, 5)}"; - String get canonicalName => name?.isNotEmpty == true ? name : idName; + String get canonicalName => name.isNotEmpty == true ? name : idName; int get beatCount => (length / subdivisionsPerBeat).floor(); double get realBeatCount => length.toDouble() / subdivisionsPerBeat; Iterable get tones => (type == MelodyType.midi) ? midiData.data.values - .expand((it) => it.noteOns.map((e) => e.noteNumber - 60)) + .expand((it) => it.noteOns.map((e) => e!.noteNumber - 60)) : []; static final Map averageToneCache = Map(); double get averageTone => @@ -326,7 +319,7 @@ extension MelodyTheory on Melody { MidiChange midiChangeBefore(int subdivision) { // final int initialSubdivision = subdivision; - MidiChange result = midiData.data[subdivision]; + MidiChange? result = midiData.data[subdivision]; while (result == null) { subdivision = subdivision - 1; if (subdivision < 0) { @@ -344,10 +337,9 @@ extension SectionTheory on Section { double get realBeatCount => harmony.realBeatCount; int get beatCount => harmony.beatCount; - MelodyReference referenceTo(Melody melody) => (melody != null) - ? melodies.firstWhere((element) => element.melodyId == melody.id, - orElse: () => _defaultMelodyReference(melody)) - : null; + MelodyReference? referenceTo(Melody melody) => + melodies.firstWhere((element) => element.melodyId == melody.id, + orElse: () => _defaultMelodyReference(melody)); MelodyReference _defaultMelodyReference(Melody melody) { var result = MelodyReference() @@ -381,12 +373,13 @@ extension ScoreTheory on Score { int get beatCount => sections.fold(0, (p, s) => p + s.beatCount); int get maxBeat => beatCount - 1; - Melody melodyReferencedBy(MelodyReference ref) => parts.fold( + Melody? melodyReferencedBy(MelodyReference ref) => parts.fold( null, (previousValue, part) => previousValue ?? - part.melodies.firstWhere((melody) => melody.id == ref.melodyId, - orElse: () => null)); + part.melodies.firstWhereOrNull( + (melody) => melody.id == ref.melodyId, + )); int firstBeatOfSection(Section currentSection) { if (sections.isEmpty) { diff --git a/lib/util/music_utils.dart b/lib/util/music_utils.dart index 393659b9..a2af7dad 100644 --- a/lib/util/music_utils.dart +++ b/lib/util/music_utils.dart @@ -1,8 +1,7 @@ -import '../util/midi_theory.dart'; -import 'package:dart_midi/dart_midi.dart'; -//ignore: implementation_imports -import 'package:dart_midi/src/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_events.dart'; +import '../util/midi_theory.dart'; import '../generated/protos/music.pb.dart'; import 'util.dart'; @@ -37,8 +36,8 @@ extension ScoreReKey on Score { extension DeleteNotes on Melody { deleteMidiNote(int midiNote, int subdivision) { // First delete the NoteOnEvent here - midiData.data[subdivision].midiEvents = midiData - .data[subdivision].midiEvents + midiData.data[subdivision]!.midiEvents = midiData + .data[subdivision]!.midiEvents .withoutNoteOnEvents(midiNote) .toList(); @@ -49,11 +48,9 @@ extension DeleteNotes on Melody { var midiChange = midiData.data[s]; if (midiChange != null) { final midiEvents = midiChange.midiEvents; - if (midiEvents.hasNoteOnEvent(midiNote) != null) { - midiChange.midiEvents = - midiEvents.withoutNoteOffEvents(midiNote).toList(); - foundNoteOff = true; - } + midiChange.midiEvents = + midiEvents.withoutNoteOffEvents(midiNote).toList(); + foundNoteOff = true; } if (foundNoteOff) { break; @@ -80,9 +77,9 @@ extension DeleteNotes on Melody { extension SeparateNoteOnAndOff on Melody { bool separateNoteOnAndOffs() { bool madeChanges = false; - if (type == MelodyType.midi && false) { + if (type == MelodyType.midi) { midiData.data.keys.forEach((index) { - MidiChange midiChange = midiData.data[index]; + MidiChange midiChange = midiData.data[index]!; int nextIndex = (index < midiData.data.length - 1) ? index + 1 : 0; MidiChange nextMidiChange = midiData.data[nextIndex] ?? MidiChange(); @@ -105,7 +102,7 @@ extension SeparateNoteOnAndOff on Melody { } }); - nextWriter.buffer.addAll(nextMidiChange.data ?? []); + nextWriter.buffer.addAll(nextMidiChange.data); midiChange.data = writer.buffer; nextMidiChange.data = nextWriter.buffer; }); diff --git a/lib/util/proto_utils.dart b/lib/util/proto_utils.dart index ffa81d8c..26980524 100644 --- a/lib/util/proto_utils.dart +++ b/lib/util/proto_utils.dart @@ -1,16 +1,16 @@ import 'package:protobuf/protobuf.dart'; -import 'fake_js.dart' -if(dart.library.js) 'dart:js'; +import 'fake_js.dart' if (dart.library.js) 'dart:js'; extension ProtoUtils on T { - dynamic protoJsify() => JsObject.jsify(bsCopy().toProto3Json()); + dynamic protoJsify() => JsObject.jsify(bsCopy().toProto3Json()!); T bsCopy() { return deepCopy(); } + T bsRebuild(Function(T) updates) { - return (deepCopy()..freeze()).rebuild((t) => updates(t)).deepCopy() as T; + return (deepCopy()..freeze()).rebuild((t) => updates(t)).deepCopy(); } - String get logString => "\n ${toString().replaceAll("\n", "\n ")}"; + String get logString => "\n ${toString().replaceAll("\n", "\n ")}"; } diff --git a/lib/util/ui_utils.dart b/lib/util/ui_utils.dart index d0e44dbd..928a0fac 100644 --- a/lib/util/ui_utils.dart +++ b/lib/util/ui_utils.dart @@ -9,17 +9,17 @@ import 'package:url_launcher/url_launcher.dart'; launchURL( String url, { - bool forceSafariVC, - bool forceWebView, - bool enableJavaScript, - bool enableDomStorage, - bool universalLinksOnly, - Map headers, - Brightness statusBarBrightness, - String webOnlyWindowName, + bool forceSafariVC = false, + bool forceWebView = false, + bool enableJavaScript = false, + bool enableDomStorage = false, + bool universalLinksOnly = false, + Map headers = const {}, + Brightness statusBarBrightness = Brightness.dark, + String webOnlyWindowName = '', }) async { - if (await canLaunch(url)) { - await launch( + if (await canLaunchUrl(Uri.parse(url))) { + await launchURL( url, forceSafariVC: forceSafariVC, forceWebView: forceWebView, @@ -72,29 +72,30 @@ Future loadUiImage(String imageAssetPath) async { class CustomSliverToBoxAdapter extends SingleChildRenderObjectWidget { final Function(Rect) setVisibleRect; - const CustomSliverToBoxAdapter({ - this.setVisibleRect, - Key key, - Widget child, + const CustomSliverToBoxAdapter( + this.setVisibleRect, { + Key? key, + Widget? child, }) : super(key: key, child: child); @override _CustomRenderSliverToBoxAdapter createRenderObject(BuildContext context) => - _CustomRenderSliverToBoxAdapter(setVisibleRect: setVisibleRect); + _CustomRenderSliverToBoxAdapter(setVisibleRect); } class _CustomRenderSliverToBoxAdapter extends RenderSliverSingleBoxAdapter { final Function(Rect) setVisibleRect; - _CustomRenderSliverToBoxAdapter({ - this.setVisibleRect, - RenderBox child, + _CustomRenderSliverToBoxAdapter( + this.setVisibleRect, { + RenderBox? child, }) : super(child: child); @override void performLayout() { + final child = this.child; if (child == null) { - geometry = SliverGeometry.zero; + this.geometry = SliverGeometry.zero; return; } child.layout(constraints.asBoxConstraints(), parentUsesSize: true); @@ -107,12 +108,11 @@ class _CustomRenderSliverToBoxAdapter extends RenderSliverSingleBoxAdapter { childExtent = child.size.height; break; } - assert(childExtent != null); final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: childExtent); assert(paintedChildSize.isFinite); assert(paintedChildSize >= 0.0); - geometry = new SliverGeometry( + final geometry = new SliverGeometry( scrollExtent: childExtent, paintExtent: paintedChildSize, maxPaintExtent: childExtent, @@ -120,6 +120,7 @@ class _CustomRenderSliverToBoxAdapter extends RenderSliverSingleBoxAdapter { hasVisualOverflow: childExtent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0, ); + this.geometry = geometry; setChildParentData(child, constraints, geometry); // Expose geometry diff --git a/lib/widget/beats_badge.dart b/lib/widget/beats_badge.dart index 2ae09751..237a8f8b 100644 --- a/lib/widget/beats_badge.dart +++ b/lib/widget/beats_badge.dart @@ -4,9 +4,6 @@ import '../ui_models.dart'; double beatsBadgeWidth(int beats) { double width = 30; - if (beats == null) { - beats = 9999; - } if (beats > 99) width = 40; if (beats > 999) width = 50; if (beats > 9999) width = 60; @@ -21,8 +18,8 @@ class BeatsBadge extends StatelessWidget { final bool isPerBeat; const BeatsBadge( - {Key key, - this.beats, + {Key? key, + required this.beats, this.show = true, this.opacity = 0.5, this.isPerBeat = false}) diff --git a/lib/widget/color_filtered_image_asset.dart b/lib/widget/color_filtered_image_asset.dart index ab687631..909c2ece 100644 --- a/lib/widget/color_filtered_image_asset.dart +++ b/lib/widget/color_filtered_image_asset.dart @@ -4,7 +4,8 @@ class ColorFilteredImageAsset extends StatelessWidget { final String imageSource; final Color imageColor; - const ColorFilteredImageAsset({Key key, this.imageSource, this.imageColor}) + const ColorFilteredImageAsset( + {Key? key, required this.imageSource, required this.imageColor}) : super(key: key); @override diff --git a/lib/widget/incrementable_value.dart b/lib/widget/incrementable_value.dart index a7b4f199..313aa79f 100644 --- a/lib/widget/incrementable_value.dart +++ b/lib/widget/incrementable_value.dart @@ -92,7 +92,7 @@ class _IncrementableValueState extends State { double buttonWidth = showButtons ? 32 : 0; onPointerDown(event) { - widget.onPointerDownCallback?.call(); + widget.onPointerDownCallback.call(); incrementStartPos = event.position; incrementStartTimeMs = DateTime.now().millisecondsSinceEpoch; lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; @@ -135,13 +135,13 @@ class _IncrementableValueState extends State { isDown = true; } // print("direction=$direction | isUp=$isUp | isDown=$isDown"); - if (isUp && widget.onIncrement != null) { + if (isUp) { vibrate(); incrementStartPos = event.position; incrementStartTimeMs = eventTime; // print("increment"); widget.onIncrement(); - } else if (isDown && widget.onDecrement != null) { + } else if (isDown) { vibrate(); incrementStartPos = event.position; incrementStartTimeMs = eventTime; @@ -153,7 +153,7 @@ class _IncrementableValueState extends State { onPointerUp(event) { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; incrementStartPos = null; - widget.onPointerUpCallback?.call(); + widget.onPointerUpCallback.call(); } ; diff --git a/lib/widget/my_buttons.dart b/lib/widget/my_buttons.dart index 7f169ca1..90eb9e99 100644 --- a/lib/widget/my_buttons.dart +++ b/lib/widget/my_buttons.dart @@ -2,34 +2,32 @@ import 'package:flutter/material.dart'; class MyFlatButton extends TextButton { MyFlatButton({ - Key key, - required VoidCallback onPressed, - VoidCallback onLongPress, - ValueChanged onHighlightChanged, + Key? key, + required VoidCallback? onPressed, + VoidCallback? onLongPress, + ValueChanged? onHighlightChanged, MouseCursor mouseCursor = SystemMouseCursors.basic, - ButtonTextTheme textTheme, - Color color, - EdgeInsetsGeometry padding, + ButtonTextTheme? textTheme, + Color? color, + EdgeInsetsGeometry? padding, Clip clipBehavior = Clip.none, - FocusNode focusNode, + FocusNode? focusNode, bool autofocus = false, - ButtonStyle style, + ButtonStyle? style, bool lightHighlight = false, required Widget child, - }) : assert(clipBehavior != null), - assert(autofocus != null), - super( + }) : super( key: key, onPressed: onPressed, onLongPress: onLongPress, style: style ?? ButtonStyle( - backgroundColor: MaterialStateProperty.all(color), - overlayColor: MaterialStateProperty.all( + backgroundColor: WidgetStateProperty.all(color), + overlayColor: WidgetStateProperty.all( lightHighlight ? Colors.white10 : null), mouseCursor: - MaterialStateProperty.all(SystemMouseCursors.basic), - padding: MaterialStateProperty.all(padding)), + WidgetStateProperty.all(SystemMouseCursors.basic), + padding: WidgetStateProperty.all(padding)), // ElevatedButton.styleFrom( // primary: color, // // onPrimary: color?.textColor(), @@ -45,42 +43,40 @@ class MyFlatButton extends TextButton { class MyRaisedButton extends ElevatedButton { MyRaisedButton({ - Key key, - required VoidCallback onPressed, - VoidCallback onLongPress, - ValueChanged onHighlightChanged, + Key? key, + required VoidCallback? onPressed, + VoidCallback? onLongPress, + ValueChanged? onHighlightChanged, MouseCursor mouseCursor = SystemMouseCursors.basic, - ButtonTextTheme textTheme, - Color textColor, - Color disabledTextColor, - Color color, - Color disabledColor, - Color focusColor, - Color hoverColor, - Color highlightColor, - Color splashColor, - Brightness colorBrightness, - double elevation, - double focusElevation, - double hoverElevation, - double highlightElevation, - double disabledElevation, - EdgeInsetsGeometry padding, - VisualDensity visualDensity, - ShapeBorder shape, + ButtonTextTheme? textTheme, + Color? textColor, + Color? disabledTextColor, + Color? color, + Color? disabledColor, + Color? focusColor, + Color? hoverColor, + Color? highlightColor, + Color? splashColor, + Brightness? colorBrightness, + double elevation = 1.0, + double focusElevation = 1.0, + double hoverElevation = 1.0, + double highlightElevation = 1.0, + double disabledElevation = 1.0, + EdgeInsetsGeometry? padding, + VisualDensity? visualDensity, + ShapeBorder? shape, Clip clipBehavior = Clip.none, - FocusNode focusNode, + FocusNode? focusNode, bool autofocus = false, - MaterialTapTargetSize materialTapTargetSize, - Duration animationDuration, - Widget child, - }) : assert(autofocus != null), - assert(elevation == null || elevation >= 0.0), - assert(focusElevation == null || focusElevation >= 0.0), - assert(hoverElevation == null || hoverElevation >= 0.0), - assert(highlightElevation == null || highlightElevation >= 0.0), - assert(disabledElevation == null || disabledElevation >= 0.0), - assert(clipBehavior != null), + MaterialTapTargetSize? materialTapTargetSize, + Duration? animationDuration, + Widget? child, + }) : assert(elevation >= 0.0), + assert(focusElevation >= 0.0), + assert(hoverElevation >= 0.0), + assert(highlightElevation >= 0.0), + assert(disabledElevation >= 0.0), super( key: key, onPressed: onPressed, @@ -101,20 +97,20 @@ class MyRaisedButton extends ElevatedButton { class MySlider extends Slider { const MySlider({ - Key key, + Key? key, required double value, required ValueChanged onChanged, - ValueChanged onChangeStart, - ValueChanged onChangeEnd, + ValueChanged? onChangeStart, + ValueChanged? onChangeEnd, double min = 0.0, double max = 1.0, - int divisions, - String label, - Color activeColor, - Color inactiveColor, + int? divisions, + String? label, + Color? activeColor, + Color? inactiveColor, MouseCursor mouseCursor = SystemMouseCursors.basic, - SemanticFormatterCallback semanticFormatterCallback, - FocusNode focusNode, + SemanticFormatterCallback? semanticFormatterCallback, + FocusNode? focusNode, bool autofocus = false, }) : super( key: key, diff --git a/lib/widget/my_popup_menu.dart b/lib/widget/my_popup_menu.dart index ef3f9ca3..22ab8f41 100644 --- a/lib/widget/my_popup_menu.dart +++ b/lib/widget/my_popup_menu.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:flutter/foundation.dart'; @@ -78,7 +76,7 @@ const double _kMenuScreenPadding = 8.0; abstract class PopupMenuEntry extends StatefulWidget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. - const PopupMenuEntry({Key key}) : super(key: key); + const PopupMenuEntry({Key? key}) : super(key: key); /// The amount of vertical space occupied by this entry. /// @@ -118,7 +116,7 @@ class PopupMenuDivider extends PopupMenuEntry { /// Creates a horizontal divider for a popup menu. /// /// By default, the divider has a height of 16 logical pixels. - const PopupMenuDivider({Key key, this.height = _kMenuDividerHeight}) + const PopupMenuDivider({required Key key, this.height = _kMenuDividerHeight}) : super(key: key); /// The height of the divider entry. @@ -145,11 +143,10 @@ class _PopupMenuDividerState extends State { // item lines up with the center of its PopupMenuButton. class _MenuItem extends SingleChildRenderObjectWidget { const _MenuItem({ - Key key, + Key? key, required this.onLayout, - Widget child, - }) : assert(onLayout != null), - super(key: key, child: child); + Widget? child, + }) : super(key: key, child: child); final ValueChanged onLayout; @@ -166,9 +163,7 @@ class _MenuItem extends SingleChildRenderObjectWidget { } class _RenderMenuItem extends RenderShiftedBox { - _RenderMenuItem(this.onLayout, [RenderBox child]) - : assert(onLayout != null), - super(child); + _RenderMenuItem(this.onLayout, [RenderBox? child]) : super(child); ValueChanged onLayout; @@ -177,11 +172,11 @@ class _RenderMenuItem extends RenderShiftedBox { if (child == null) { size = Size.zero; } else { - child.layout(constraints, parentUsesSize: true); - size = constraints.constrain(child.size); + child!.layout(constraints, parentUsesSize: true); + size = constraints.constrain(child!.size); + final BoxParentData childParentData = child!.parentData as BoxParentData; + childParentData.offset = Offset.zero; } - final BoxParentData childParentData = child.parentData as BoxParentData; - childParentData.offset = Offset.zero; onLayout(size); } } @@ -232,15 +227,14 @@ class PopupMenuItem extends PopupMenuEntry { /// /// The `enabled` and `height` arguments must not be null. const PopupMenuItem({ - Key key, - this.value, + Key? key, + required this.value, this.enabled = true, this.height = kMinInteractiveDimension, - this.textStyle, - this.mouseCursor, + this.textStyle = const TextStyle(), + this.mouseCursor = SystemMouseCursors.basic, required this.child, - }) : assert(enabled != null), - assert(height != null), + }) : assert(height != null), super(key: key); /// The value that will be returned by [showMenu] if this entry is selected. @@ -268,11 +262,11 @@ class PopupMenuItem extends PopupMenuEntry { /// widget. /// /// If [mouseCursor] is a [MaterialStateProperty], - /// [MaterialStateProperty.resolve] is used for the following [MaterialState]: + /// [WidgetStateProperty.resolve] is used for the following [WidgetState]: /// - /// * [MaterialState.disabled]. + /// * [WidgetState.disabled]. /// - /// If this property is null, [MaterialStateMouseCursor.clickable] will be used. + /// If this property is null, [WidgetStateMouseCursor.clickable] will be used. final MouseCursor mouseCursor; /// The widget below this widget in the tree. @@ -280,7 +274,7 @@ class PopupMenuItem extends PopupMenuEntry { /// Typically a single-line [ListTile] (for menus with icons) or a [Text]. An /// appropriate [DefaultTextStyle] is put in scope for the child. In either /// case, the text should be short enough that it won't wrap. - final Widget child; + final Widget? child; @override bool represents(T value) => value == this.value; @@ -292,13 +286,13 @@ class PopupMenuItem extends PopupMenuEntry { class MyPopupMenuItem extends PopupMenuItem { const MyPopupMenuItem({ - Key key, - T value, + Key? key, + required T value, bool enabled = true, double height = kMinInteractiveDimension, - TextStyle textStyle, + TextStyle textStyle = const TextStyle(), MouseCursor mouseCursor = SystemMouseCursors.basic, - required Widget child, + Widget? child, }) : super( key: key, value: value, @@ -334,7 +328,7 @@ class PopupMenuItemState> extends State { /// By default, this returns [PopupMenuItem.child]. Override this to put /// something else in the menu entry. @protected - Widget buildChild() => widget.child; + Widget? buildChild() => widget.child; /// The handler for when the user selects the menu item. /// @@ -351,14 +345,14 @@ class PopupMenuItemState> extends State { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); - TextStyle style = widget.textStyle ?? + TextStyle? style = widget.textStyle ?? popupMenuTheme.textStyle ?? - theme.textTheme.subtitle1; + theme.textTheme.headlineSmall; - if (!widget.enabled) style = style.copyWith(color: theme.disabledColor); + if (!widget.enabled) style = style?.copyWith(color: theme.disabledColor); Widget item = AnimatedDefaultTextStyle( - style: style, + style: style ?? const TextStyle(), duration: kThemeChangeDuration, child: Container( alignment: AlignmentDirectional.centerStart, @@ -377,10 +371,10 @@ class PopupMenuItemState> extends State { ); } final MouseCursor effectiveMouseCursor = - MaterialStateProperty.resolveAs( - widget.mouseCursor ?? MaterialStateMouseCursor.clickable, - { - if (!widget.enabled) MaterialState.disabled, + WidgetStateProperty.resolveAs( + widget.mouseCursor ?? WidgetStateMouseCursor.clickable, + { + if (!widget.enabled) WidgetState.disabled, }, ); @@ -463,13 +457,12 @@ class CheckedPopupMenuItem extends PopupMenuItem { /// /// The `checked` and `enabled` arguments must not be null. const CheckedPopupMenuItem({ - Key key, - T value, + Key? key, + required T value, this.checked = false, bool enabled = true, - Widget child, - }) : assert(checked != null), - super( + Widget? child, + }) : super( key: key, value: value, enabled: enabled, @@ -494,7 +487,7 @@ class CheckedPopupMenuItem extends PopupMenuItem { /// This widget is placed in the [ListTile.title] slot of a [ListTile] whose /// [ListTile.leading] slot is an [Icons.done] icon. @override - Widget get child => super.child; + Widget? get child => super.child; @override _CheckedPopupMenuItemState createState() => @@ -505,7 +498,7 @@ class _CheckedPopupMenuItemState extends PopupMenuItemState> with SingleTickerProviderStateMixin { static const Duration _fadeDuration = Duration(milliseconds: 150); - AnimationController _controller; + late AnimationController _controller; Animation get _opacity => _controller.view; @override @@ -541,9 +534,9 @@ class _CheckedPopupMenuItemState class _PopupMenu extends StatelessWidget { const _PopupMenu({ - Key key, - this.route, - this.semanticLabel, + Key? key, + required this.route, + required this.semanticLabel, }) : super(key: key); final _PopupMenuRoute route; @@ -559,14 +552,14 @@ class _PopupMenu extends StatelessWidget { for (int i = 0; i < route.items.length; i += 1) { final double start = (i + 1) * unit; - final double end = (start + 1.5 * unit).clamp(0.0, 1.0) as double; + final double end = (start + 1.5 * unit).clamp(0.0, 1.0); final CurvedAnimation opacity = CurvedAnimation( - parent: route.animation, + parent: route.animation!, curve: Interval(start, end), ); Widget item = route.items[i]; if (route.initialValue != null && - route.items[i].represents(route.initialValue)) { + route.items[i].represents(route.initialValue!)) { item = Container( color: Theme.of(context).highlightColor, child: item, @@ -613,10 +606,10 @@ class _PopupMenu extends StatelessWidget { ); return AnimatedBuilder( - animation: route.animation, - builder: (BuildContext context, Widget child) { + animation: route.animation!, + builder: (BuildContext context, Widget? child) { return Opacity( - opacity: opacity.evaluate(route.animation), + opacity: opacity.evaluate(route.animation!), child: Material( shape: route.shape ?? popupMenuTheme.shape, color: route.color ?? popupMenuTheme.color, @@ -624,8 +617,8 @@ class _PopupMenu extends StatelessWidget { elevation: route.elevation ?? popupMenuTheme.elevation ?? 8.0, child: Align( alignment: AlignmentDirectional.topEnd, - widthFactor: width.evaluate(route.animation), - heightFactor: height.evaluate(route.animation), + widthFactor: width.evaluate(route.animation!), + heightFactor: height.evaluate(route.animation!), child: child, ), ), @@ -646,11 +639,11 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // The sizes of each item are computed when the menu is laid out, and before // the route is laid out. - List itemSizes; + List? itemSizes; // The index of the selected item, or null if PopupMenuButton.initialValue // was not specified. - final int selectedItemIndex; + final int? selectedItemIndex; // Whether to prefer going to the left or to the right. final TextDirection textDirection; @@ -678,11 +671,11 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // Find the ideal vertical position. double y = position.top; - if (selectedItemIndex != null && itemSizes != null) { + if (itemSizes != null && selectedItemIndex != null) { double selectedItemOffset = _kMenuVerticalPadding; - for (int index = 0; index < selectedItemIndex; index += 1) - selectedItemOffset += itemSizes[index].height; - selectedItemOffset += itemSizes[selectedItemIndex].height / 2; + for (int index = 0; index < selectedItemIndex!; index += 1) + selectedItemOffset += itemSizes![index].height; + selectedItemOffset += itemSizes![selectedItemIndex!].height / 2; y = position.top + (size.height - position.top - position.bottom) / 2.0 - selectedItemOffset; @@ -698,7 +691,6 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { x = position.left; } else { // Menu button is equidistant from both edges, so grow in reading direction. - assert(textDirection != null); switch (textDirection) { case TextDirection.rtl: x = size.width - position.right - childSize.width; @@ -727,7 +719,7 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { // If called when the old and new itemSizes have been initialized then // we expect them to have the same length because there's no practical // way to change length of the items list once the menu has been shown. - assert(itemSizes.length == oldDelegate.itemSizes.length); + assert(itemSizes!.length == oldDelegate.itemSizes!.length); return position != oldDelegate.position || selectedItemIndex != oldDelegate.selectedItemIndex || @@ -738,29 +730,29 @@ class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { class _PopupMenuRoute extends PopupRoute { _PopupMenuRoute({ - this.position, - this.items, + required this.position, + required this.items, this.initialValue, this.elevation, - this.theme, - this.popupMenuTheme, - this.barrierLabel, - this.semanticLabel, + required this.theme, + required this.popupMenuTheme, + required this.barrierLabel, + required this.semanticLabel, this.shape, this.color, - this.showMenuContext, - this.captureInheritedThemes, + required this.showMenuContext, + required this.captureInheritedThemes, }) : itemSizes = List.empty() /*(items.length)*/; final RelativeRect position; final List> items; final List itemSizes; - final T initialValue; - final double elevation; + final T? initialValue; + final double? elevation; final ThemeData theme; final String semanticLabel; - final ShapeBorder shape; - final Color color; + final ShapeBorder? shape; + final Color? color; final PopupMenuThemeData popupMenuTheme; final BuildContext showMenuContext; final bool captureInheritedThemes; @@ -781,7 +773,7 @@ class _PopupMenuRoute extends PopupRoute { bool get barrierDismissible => true; @override - Color get barrierColor => null; + Color? get barrierColor => null; @override final String barrierLabel; @@ -789,12 +781,12 @@ class _PopupMenuRoute extends PopupRoute { @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { - int selectedItemIndex; + int? selectedItemIndex; if (initialValue != null) { for (int index = 0; selectedItemIndex == null && index < items.length; index += 1) { - if (items[index].represents(initialValue)) selectedItemIndex = index; + if (items[index].represents(initialValue!)) selectedItemIndex = index; } } @@ -805,7 +797,7 @@ class _PopupMenuRoute extends PopupRoute { // For the sake of backwards compatibility. An (unlikely) app that relied // on having menus only inherit from the material Theme could set // captureInheritedThemes to false and get the original behavior. - if (theme != null) menu = Theme(data: theme, child: menu); + menu = Theme(data: theme, child: menu); } return MediaQuery.removePadding( @@ -886,37 +878,32 @@ class _PopupMenuRoute extends PopupRoute { /// calling this method automatically. /// * [SemanticsConfiguration.namesRoute], for a description of edge triggered /// semantics. -Future showMenu({ +Future showMenu({ required BuildContext context, required RelativeRect position, required List> items, - T initialValue, - double elevation, - String semanticLabel, - ShapeBorder shape, - Color color, + T? initialValue, + double? elevation, + String? semanticLabel, + ShapeBorder? shape, + Color? color, bool captureInheritedThemes = true, bool useRootNavigator = false, }) { - assert(context != null); - assert(position != null); - assert(useRootNavigator != null); - assert(items != null && items.isNotEmpty); - assert(captureInheritedThemes != null); + assert(items.isNotEmpty); assert(debugCheckHasMaterialLocalizations(context)); - String label = semanticLabel; + String label = semanticLabel ?? ''; switch (Theme.of(context).platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - label = semanticLabel; + label = semanticLabel ?? ''; break; case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - label = - semanticLabel ?? MaterialLocalizations.of(context)?.popupMenuLabel; + label = semanticLabel ?? MaterialLocalizations.of(context).popupMenuLabel; } return Navigator.of(context, rootNavigator: useRootNavigator) @@ -1014,10 +1001,10 @@ class MyPopupMenuButton extends StatefulWidget { /// /// The [itemBuilder] argument must not be null. const MyPopupMenuButton({ - Key key, + Key? key, required this.itemBuilder, this.initialValue, - this.onSelected, + required this.onSelected, this.onCanceled, this.tooltip, this.elevation, @@ -1030,19 +1017,16 @@ class MyPopupMenuButton extends StatefulWidget { this.color, this.captureInheritedThemes = true, this.updatedMenu, - }) : assert(itemBuilder != null), - assert(offset != null), - assert(enabled != null), - assert(captureInheritedThemes != null), - assert(!(child != null && icon != null), - 'You can only pass [child] or [icon], not both.'), + }) : assert(offset != null), + assert( + !(icon != null), 'You can only pass [child] or [icon], not both.'), super(key: key); /// Called when the button is pressed to create the items to show in the menu. final PopupMenuItemBuilder itemBuilder; /// The value of the menu item, if any, that should be highlighted when the menu opens. - final T initialValue; + final T? initialValue; /// Called when the user selects a value from the popup menu created by this button. /// @@ -1053,19 +1037,19 @@ class MyPopupMenuButton extends StatefulWidget { /// Called when the user dismisses the popup menu without selecting an item. /// /// If the user selects a value, [onSelected] is called instead. - final PopupMenuCanceled onCanceled; + final PopupMenuCanceled? onCanceled; /// Text that describes the action that will occur when the button is pressed. /// /// This text is displayed when the user long-presses on the button and is /// used for accessibility. - final String tooltip; + final String? tooltip; /// The z-coordinate at which to place the menu when open. This controls the /// size of the shadow below the menu. /// /// Defaults to 8, the appropriate elevation for popup menus. - final double elevation; + final double? elevation; /// Matches IconButton's 8 dps padding by default. In some cases, notably where /// this button appears as the trailing element of a list item, it's useful to be able @@ -1074,11 +1058,11 @@ class MyPopupMenuButton extends StatefulWidget { /// If provided, [child] is the widget used for this button /// and the button will utilize an [InkWell] for taps. - final Widget child; + final Widget? child; /// If provided, the [icon] is used for this button /// and the button will behave like an [IconButton]. - final Widget icon; + final Widget? icon; /// The offset applied to the Popup Menu Button. /// @@ -1106,21 +1090,21 @@ class MyPopupMenuButton extends StatefulWidget { /// If [PopupMenuThemeData.shape] is also null, then the default shape for /// [MaterialType.card] is used. This default shape is a rectangle with /// rounded edges of BorderRadius.circular(2.0). - final ShapeBorder shape; + final ShapeBorder? shape; /// If provided, the background color used for the menu. /// /// If this property is null, then [PopupMenuThemeData.color] is used. /// If [PopupMenuThemeData.color] is also null, then /// Theme.of(context).cardColor is used. - final Color color; + final Color? color; /// If true (the default) then the menu will be wrapped with copies /// of the [InheritedThemes], like [Theme] and [PopupMenuTheme], which /// are defined above the [BuildContext] where the menu is shown. final bool captureInheritedThemes; - final ChangeNotifier updatedMenu; + final ChangeNotifier? updatedMenu; @override PopupMenuButtonState createState() => PopupMenuButtonState(); @@ -1134,13 +1118,13 @@ class PopupMenuButtonState extends State> { @override initState() { super.initState(); - widget?.updatedMenu?.addListener(showButtonMenu); + widget.updatedMenu?.addListener(showButtonMenu); } @override dispose() { super.dispose(); - widget?.updatedMenu?.removeListener(showButtonMenu); + widget.updatedMenu?.removeListener(showButtonMenu); } /// A method to show a popup menu with the items supplied to @@ -1176,19 +1160,18 @@ class PopupMenuButtonState extends State> { shape: widget.shape ?? popupMenuTheme.shape, color: widget.color ?? popupMenuTheme.color, captureInheritedThemes: widget.captureInheritedThemes, - ).then((T newValue) { + ).then((T? newValue) { if (!mounted) return null; if (newValue == null) { - if (widget.onCanceled != null) widget.onCanceled(); + widget.onCanceled?.call(); return null; } - if (widget.onSelected != null) widget.onSelected(newValue); + widget.onSelected(newValue); }); } } - Icon _getIcon(TargetPlatform platform) { - assert(platform != null); + Icon? _getIcon(TargetPlatform platform) { switch (platform) { case TargetPlatform.android: case TargetPlatform.fuchsia: @@ -1199,43 +1182,42 @@ class PopupMenuButtonState extends State> { case TargetPlatform.macOS: return const Icon(Icons.more_horiz); } - return null; + // return null; } bool get _canRequestFocus { final NavigationMode mode = - MediaQuery.of(context)?.navigationMode ?? NavigationMode.traditional; + MediaQuery.of(context).navigationMode ?? NavigationMode.traditional; switch (mode) { case NavigationMode.traditional: return widget.enabled; case NavigationMode.directional: return true; } - assert(false, 'Navigation mode $mode not handled'); - return null; + // assert(false, 'Navigation mode $mode not handled'); + // return null; } @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); - if (widget.child != null) - return Tooltip( - message: - widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, - child: InkWell( - onTap: widget.enabled ? showButtonMenu : null, - canRequestFocus: _canRequestFocus, - child: widget.child, - ), - ); - - return IconButton( - icon: widget.icon ?? _getIcon(Theme.of(context).platform), - padding: widget.padding, - mouseCursor: SystemMouseCursors.basic, - tooltip: widget.tooltip ?? null, - onPressed: widget.enabled ? showButtonMenu : null, + return Tooltip( + message: + widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, + child: InkWell( + onTap: widget.enabled ? showButtonMenu : null, + canRequestFocus: _canRequestFocus, + child: widget.child, + ), ); + + // return IconButton( + // icon: widget.icon ?? _getIcon(Theme.of(context).platform), + // padding: widget.padding, + // mouseCursor: SystemMouseCursors.basic, + // tooltip: widget.tooltip ?? null, + // onPressed: widget.enabled ? showButtonMenu : null, + // ); } } diff --git a/lib/widget/scalable_view.dart b/lib/widget/scalable_view.dart index 80aee137..0d1a6c8b 100644 --- a/lib/widget/scalable_view.dart +++ b/lib/widget/scalable_view.dart @@ -22,7 +22,7 @@ class ScalableView extends StatefulWidget { final bool shiftUpZoomControls; const ScalableView( - {Key key, + {Key? key, this.onScaleDown, this.onScaleUp, this.child, @@ -57,7 +57,7 @@ class _ScalableViewState extends State { SizedBox(width: 2), Column(children: [ Expanded(child: SizedBox()), - if (widget.autoScroll != null && widget.toggleAutoScroll != null) + if (widget.toggleAutoScroll != null) MusicActionButton( visible: widget.visible && widget.showViewOptions, onPressed: widget.toggleAutoScroll, @@ -155,16 +155,13 @@ class _ScalableViewState extends State { onScaleUpdate: (details) { final scale = details.scale; // print("scale: $scale"); - if (widget.onMicroScaleUp != null && scale - lastUpdatedScale >= .01) { + if (scale - lastUpdatedScale >= .01) { widget.onMicroScaleUp(); - } else if (widget.onMicroScaleDown != null && - scale - lastUpdatedScale <= -.01) { + } else if (scale - lastUpdatedScale <= -.01) { widget.onMicroScaleDown(); - } else if (widget.onScaleUp != null && - scale - lastUpdatedScale >= .09) { + } else if (scale - lastUpdatedScale >= .09) { widget.onScaleUp(); - } else if (widget.onScaleDown != null && - scale - lastUpdatedScale <= -.09) { + } else if (scale - lastUpdatedScale <= -.09) { widget.onScaleDown(); } }, diff --git a/lib/widget/section_list.dart b/lib/widget/section_list.dart index 1e23fd86..4584cf74 100644 --- a/lib/widget/section_list.dart +++ b/lib/widget/section_list.dart @@ -28,21 +28,21 @@ class SectionList extends StatefulWidget { final VoidCallback toggleShowSectionBeatCounts; final bool allowReordering; final AppSettings appSettings; - final double width, height; + final double? width, height; const SectionList( - {Key key, - this.scrollDirection, - this.score, - this.currentSection, - this.selectSection, - this.insertSection, - this.sectionColor, - this.setState, - this.showSectionBeatCounts, - this.toggleShowSectionBeatCounts, - this.allowReordering, - this.appSettings, + {Key? key, + required this.scrollDirection, + required this.score, + required this.currentSection, + required this.selectSection, + required this.insertSection, + required this.sectionColor, + required this.setState, + required this.showSectionBeatCounts, + required this.toggleShowSectionBeatCounts, + required this.allowReordering, + required this.appSettings, this.width, this.height}) : super(key: key); @@ -174,12 +174,12 @@ class _SectionListState extends State { ]); } - Section _previousSection; + Section? _previousSection; _animateToNewlySelectedSection() { try { if (_previousSection != null && - _previousSection.id != widget.currentSection.id) { + _previousSection!.id != widget.currentSection.id) { _animateToCurrentSection(); } } catch (any) {} @@ -189,14 +189,14 @@ class _SectionListState extends State { _animateToCurrentSection() { int index = widget.score.sections.indexOf(widget.currentSection); if (widget.scrollDirection == Axis.horizontal) { - double margin = max(0.0, widget.width - _Section.width); + double margin = max(0.0, (widget.width ?? 0.0) - _Section.width); double position = _Section.width * (index) - margin * 0.25; position = min(_scrollController.position.maxScrollExtent, position); position = max(0, position); _scrollController.animateTo(position, duration: animationDuration, curve: Curves.easeInOut); } else { - double margin = max(0.0, widget.height - _Section.height); + double margin = max(0.0, (widget.height ?? 0.0) - _Section.height); double position = _Section.height * (index) - margin * 0.25; position = min(_scrollController.position.maxScrollExtent, position); position = max(0, position); @@ -206,7 +206,7 @@ class _SectionListState extends State { } Widget getList(BuildContext context) { - var items = widget.score?.sections ?? []; + var items = widget.score.sections ?? []; if (items.isEmpty) { items = [defaultSection()]; } @@ -292,14 +292,14 @@ class _Section extends StatefulWidget { final bool allowReordering; const _Section( - {Key key, - this.section, - this.selectSection, - this.currentSection, - this.sectionColor, - this.scrollDirection, - this.showBeatCount, - this.allowReordering}) + {Key? key, + required this.section, + required this.selectSection, + required this.currentSection, + required this.sectionColor, + required this.scrollDirection, + required this.showBeatCount, + required this.allowReordering}) : super(key: key); @override diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 2fe5726e..977ff597 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,13 +8,17 @@ import Foundation import flutter_midi_command import package_info_plus import path_provider_foundation +import share_plus import shared_preferences_foundation import url_launcher_macos +import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { SwiftFlutterMidiCommandPlugin.register(with: registry.registrar(forPlugin: "SwiftFlutterMidiCommandPlugin")) - FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index dfddea0c..17cafcc2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,90 +5,90 @@ packages: dependency: "direct main" description: name: animated_list_plus - sha256: f276e3c42a78a76c295186c4723e206dee7660741bd4e9592f9c5530511b7589 + sha256: fb3d7f1fbaf5af84907f3c739236bacda8bf32cbe1f118dd51510752883ff50c url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.2" archive: dependency: "direct main" description: name: archive - sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.3.7" + version: "3.6.1" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" base_x: dependency: "direct main" description: name: base_x - sha256: "3f1043679659f1759c651f900da6f24f0a8062c28daa6f9625e8d580002e187b" + sha256: "519abcdafd637d4b6bd7e72fabd8f9264935f804b9b9f6c5d8411c7d52cbf8fd" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: - dependency: transitive + dependency: "direct main" description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.17.1" - convert: + version: "1.19.1" + cross_file: dependency: transitive description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" dcache: dependency: "direct main" description: @@ -101,34 +101,34 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.1.4" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" fluro: dependency: "direct main" description: @@ -194,18 +194,26 @@ packages: dependency: "direct main" description: name: flutter_midi_command - sha256: "7954d279119f190a0147a0bf4d69509abf8074a9a9a6b3d2e6c3805374b93ed1" + sha256: a74e9f15b397e2f9c1869629b58bbf125c52cab71189a4f393c6e0bd6f77c418 + url: "https://pub.dev" + source: hosted + version: "0.4.17" + flutter_midi_command_linux: + dependency: transitive + description: + name: flutter_midi_command_linux + sha256: c4d6dcf136fd4718aa827c201446f935f2752e37b702ed712373c675cbdbb0d0 url: "https://pub.dev" source: hosted - version: "0.4.11" + version: "0.3.0" flutter_midi_command_platform_interface: dependency: transitive description: name: flutter_midi_command_platform_interface - sha256: cb250720a36d55252ff22612752bd2fb69e8308e9a75e1cb8ef4e0ee0134d77f + sha256: "905ebe90f56af5e9e376688d6baedd94d5378c788d302a141da283dd329dc2ce" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.3" flutter_reorderable_list: dependency: "direct main" description: @@ -228,50 +236,66 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "5fb789145cae1f4c3245c58b3f8fb287d055c26323879eab57a7bf0cfd1e45f3" + sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a url: "https://pub.dev" source: hosted - version: "10.5.0" + version: "10.8.0" http: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + url: "https://pub.dev" + source: hosted + version: "10.0.8" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "4.0.2" - js: + version: "3.0.9" + leak_tracker_testing: dependency: transitive description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "3.0.1" matcher: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.11.1" matrix4_transform: dependency: "direct main" description: @@ -284,18 +308,34 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.16.0" + midi: + dependency: transitive + description: + name: midi + sha256: "737c86a4ffbbe06352a8ec90bf5153774202f4b38dfb8e45af255cee18e2b9de" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" native_device_orientation: dependency: "direct main" description: name: native_device_orientation - sha256: "7d2fa1a1420b7b4ac3317760ffd063b86704679fb4f1796644581da4a6356ccc" + sha256: "744a03030fad5a332a54833cd34f1e2ee51ae9acf477b4ef85bacc8823af9937" url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "1.2.1" nested: dependency: transitive description: @@ -308,10 +348,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b + sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.2.0" package_info_plus_platform_interface: dependency: transitive description: @@ -324,10 +364,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.1" path_drawing: dependency: "direct main" description: @@ -340,106 +380,98 @@ packages: dependency: transitive description: name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" path_provider: dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.4.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.5" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" - url: "https://pub.dev" - source: hosted - version: "3.7.3" + version: "2.1.8" protobuf: dependency: "direct main" description: name: protobuf - sha256: "4034a02b7e231e7e60bff30a8ac13a7347abfdac0798595fae0b90a3f0afe759" + sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" provider: dependency: "direct main" description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.5" quiver: dependency: "direct main" description: name: quiver - sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" recase: dependency: "direct main" description: @@ -456,187 +488,211 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: b2961506569e28948d75ec346c28775bb111986bb69dc6a20754a457e3d97fa0 + url: "https://pub.dev" + source: hosted + version: "11.0.0" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "1032d392bc5d2095a77447a805aa3f804d2ae6a4d5eef5e6ebb3bd94c1bc19ef" + url: "https://pub.dev" + source: hosted + version: "6.0.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.1" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.7.4" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.1.12" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.0.37" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.3.3" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.0.18" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.1.4" uuid: dependency: "direct main" description: @@ -653,54 +709,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + url: "https://pub.dev" + source: hosted + version: "14.3.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" webview_flutter: dependency: "direct main" description: name: webview_flutter - sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00" + sha256: caf0f5a1012aa3c2d33c4215adc72dc1194bb59a2d3ed901f457965626805e66 url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.11.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: d936a09fbfd08cb78f7329e0bbacf6158fbdfe24ffc908b22444c07d295eb193 + sha256: "6b0eae02b7604954b80ee9a29507ac38f5de74b712faa6fee33abc1cdedc1b21" url: "https://pub.dev" source: hosted - version: "3.9.2" + version: "4.4.2" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "564ef378cafc1a0e29f1d76ce175ef517a0a6115875dff7b43fccbef2b0aeb30" + sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.11.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "5fa098f28b606f699e8ca52d9e4e11edbbfef65189f5f77ae92703ba5408fd25" + sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff url: "https://pub.dev" source: hosted - version: "3.7.2" + version: "3.20.0" win32: dependency: transitive description: name: win32 - sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 + sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f url: "https://pub.dev" source: hosted - version: "5.0.6" + version: "5.12.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" sdks: - dart: ">=3.0.0 <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index e32f084e..d70644de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,8 @@ dependencies: dcache: ^0.4.0 provider: ^6.0.2 matrix4_transform: ^2.0.1 + share_plus: ^11.0.0 + collection: ^1.19.1 dev_dependencies: flutter_test: From 16e0d1432291a95a46e5ba9c68cd8caf6b1d685d Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 25 May 2025 14:50:04 -0400 Subject: [PATCH 04/11] down from 1100+ to 300+ errors now... --- lib/beatscratch_plugin.dart | 25 +- lib/cache_management.dart | 12 +- lib/colors.dart | 4 +- lib/drawing/canvas_tone_drawer.dart | 6 +- lib/drawing/color_guide.dart | 8 +- lib/drawing/harmony_beat_renderer.dart | 5 +- lib/export/export_manager.dart | 11 +- lib/export/export_models.dart | 2 +- lib/export/export_ui.dart | 19 +- lib/export/midi_export.dart | 22 +- lib/music_view/melody_editing_toolbar.dart | 114 +++++---- lib/music_view/music_action_button.dart | 4 +- lib/music_view/music_scroll_container.dart | 158 ++++++------ lib/music_view/music_system_painter.dart | 73 +++--- lib/music_view/music_view.dart | 221 +++++++++-------- lib/music_view/part_instrument_picker.dart | 10 +- lib/music_view/part_melody_browser.dart | 28 +-- lib/music_view/section_editing_toolbar.dart | 17 +- lib/recording/recording.dart | 8 +- lib/settings/app_settings.dart | 83 ++++--- lib/settings/settings_common.dart | 17 +- lib/settings/settings_panel.dart | 82 ++++--- lib/storage/score_picker.dart | 72 +++--- lib/storage/score_picker_preview.dart | 121 +++++---- lib/storage/universe_manager.dart | 63 +++-- lib/storage/url_conversions.dart | 9 +- lib/universe_view/universe_icon.dart | 19 +- lib/universe_view/universe_upload_dialog.dart | 8 +- lib/universe_view/universe_view_ui.dart | 21 +- lib/util/bs_methods.dart | 2 +- lib/util/music_theory.dart | 2 +- lib/util/ui_utils.dart | 2 +- lib/widget/colorboard.dart | 155 ++++++------ lib/widget/incrementable_value.dart | 52 ++-- lib/widget/keyboard.dart | 159 ++++++------ lib/widget/my_buttons.dart | 2 +- lib/widget/scalable_view.dart | 231 +++++++++--------- pubspec.lock | 16 ++ pubspec.yaml | 2 + 39 files changed, 985 insertions(+), 880 deletions(-) diff --git a/lib/beatscratch_plugin.dart b/lib/beatscratch_plugin.dart index 18d8c923..be48ebf7 100644 --- a/lib/beatscratch_plugin.dart +++ b/lib/beatscratch_plugin.dart @@ -1,6 +1,5 @@ -import 'package:dart_midi/dart_midi.dart'; -// ignore: implementation_imports -import 'package:dart_midi/src/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_events.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -192,24 +191,24 @@ class BeatScratchPlugin { } static double unmultipliedBpm = 123; - static bool _playing; + static bool _playing = false; static bool get playing { return _playing; } static final ValueNotifier currentBeat = ValueNotifier(0); - static bool _isBeatScratchAudioAvailable; + static bool _isBeatScratchAudioAvailable = false; static bool get isSynthesizerAvailable { return _isBeatScratchAudioAvailable; } - static VoidCallback onCountInInitiated; - static VoidCallback onSynthesizerStatusChange; - static Function(String) onOpenUrlFromSystem; - static Function(String) onSectionSelected; - static Function(Melody) onRecordingMelodyUpdated; - static MessagesUI messagesUI; + static late VoidCallback onCountInInitiated; + static late VoidCallback onSynthesizerStatusChange; + static late Function(String) onOpenUrlFromSystem; + static late Function(String) onSectionSelected; + static late Function(Melody) onRecordingMelodyUpdated; + static late MessagesUI messagesUI; static _doSynthesizerStatusChangeLoop() { Future.delayed(Duration(seconds: 5), () { getApps(); @@ -455,7 +454,7 @@ class BeatScratchPlugin { _stopUIPlayback(); } - static DateTime _pausedTime; + static late DateTime _pausedTime; static void _stopUIPlayback() { _playing = false; onSynthesizerStatusChange(); @@ -547,7 +546,7 @@ class BeatScratchPlugin { } } - static Future getScoreId() async => + static Future getScoreId() async => _channel.invokeMethod("getScoreId"); static Future get recordedMelody async { diff --git a/lib/cache_management.dart b/lib/cache_management.dart index abf76ba8..1042ebb6 100644 --- a/lib/cache_management.dart +++ b/lib/cache_management.dart @@ -16,10 +16,10 @@ clearMutableCachesForSection(String sectionId) { } clearMutableCachesForMelody(String melodyId, - {String sectionId, - int beat, - int sectionLengthBeats, - double melodyLengthBeats}) { + {String? sectionId, + int? beat, + int? sectionLengthBeats, + double? melodyLengthBeats}) { MelodyTheory.averageToneCache.removeWhere((key, value) => key == melodyId); MelodyTheory.tonesAtCache .removeWhere((key, value) => key.arguments[0] == melodyId); @@ -39,8 +39,8 @@ clearMutableCachesForMelody(String melodyId, String keySectionId = (key.arguments[2] as String); int keyBeat = key.arguments[3] as int; return keySectionId == sectionId && - ((keyBeat % melodyLengthBeats).round() == beat || - (((keyBeat + 1) % sectionLengthBeats) % melodyLengthBeats) + ((keyBeat % melodyLengthBeats!).round() == beat || + (((keyBeat + 1) % sectionLengthBeats!) % melodyLengthBeats) .round() == beat || (((keyBeat - 1 + sectionLengthBeats) % sectionLengthBeats) % diff --git a/lib/colors.dart b/lib/colors.dart index 2f6a874e..3c1e05c7 100644 --- a/lib/colors.dart +++ b/lib/colors.dart @@ -31,6 +31,7 @@ var musicForegroundColor = Colors.white; var melodyColor = Color(0xFFDDDDDD); enum ChordColor { dominant, major, minor, augmented, diminished, tonic, none } + enum SectionColor { major, minor, perfect, augmented, diminished } extension ChordColors on ChordColor { @@ -93,7 +94,8 @@ extension BSColors on Color { BSColors._luminanceCache.putIfAbsent(this, () => computeLuminance()); /// With [this] as the background color, computes the appropriate text color. - Color textColor({Color subBackgroundColor}) { + Color textColor({Color? subBackgroundColor}) { + final luminance = subBackgroundColor?.luminance ?? this.luminance; if (luminance > 0.5) { return Colors.black; } diff --git a/lib/drawing/canvas_tone_drawer.dart b/lib/drawing/canvas_tone_drawer.dart index d52fa7be..c34c655f 100644 --- a/lib/drawing/canvas_tone_drawer.dart +++ b/lib/drawing/canvas_tone_drawer.dart @@ -30,10 +30,10 @@ class CanvasToneDrawer { Paint alphaDrawerPaint = Paint(); /// Represent the bounds for whatever is to be drawn - Rect bounds; - bool renderVertically; + late Rect bounds; + late bool renderVertically; double get axisLength => renderVertically ? bounds.height : bounds.width; - double halfStepsOnScreen; + late double halfStepsOnScreen; int highestPitch = TOP; diff --git a/lib/drawing/color_guide.dart b/lib/drawing/color_guide.dart index eaedfae5..2aaeca21 100644 --- a/lib/drawing/color_guide.dart +++ b/lib/drawing/color_guide.dart @@ -5,10 +5,10 @@ import '../util/music_theory.dart'; import 'canvas_tone_drawer.dart'; class ColorGuide extends CanvasToneDrawer { - int colorGuideAlpha; - int drawPadding; - int nonRootPadding; - int drawnColorGuideAlpha; + late int colorGuideAlpha; + late int drawPadding; + late int nonRootPadding; + late int drawnColorGuideAlpha; Iterable pressedNotes = []; drawColorGuide(Canvas canvas) { diff --git a/lib/drawing/harmony_beat_renderer.dart b/lib/drawing/harmony_beat_renderer.dart index 285005d7..3190db79 100644 --- a/lib/drawing/harmony_beat_renderer.dart +++ b/lib/drawing/harmony_beat_renderer.dart @@ -9,7 +9,8 @@ import '../util/util.dart'; extension _HarmonyHighlight on Color { // ignore: unused_element - Color withHighlight({bool isPlaying, bool isSelected, bool isFaded}) { + Color withHighlight( + {bool isPlaying = false, bool isSelected = false, bool isFaded = false}) { int alpha = 187; if (isPlaying) { alpha = 255; @@ -65,7 +66,7 @@ extension _HarmonyColor on Chord { } class HarmonyBeatRenderer { - Section section; + late Section section; Harmony get harmony => section.harmony; Meter get meter => section.meter; diff --git a/lib/export/export_manager.dart b/lib/export/export_manager.dart index 6b51c4eb..adec291d 100644 --- a/lib/export/export_manager.dart +++ b/lib/export/export_manager.dart @@ -1,16 +1,14 @@ import 'dart:io'; import 'package:beatscratch_flutter_redux/generated/protos/protos.dart'; - -import '../widget/my_platform.dart'; - +import 'package:beatscratch_flutter_redux/util/music_theory.dart'; import 'package:path_provider/path_provider.dart'; -// import '../util/music_theory.dart'; +import '../widget/my_platform.dart'; import 'export_models.dart'; class ExportManager { - Directory exportsDirectory; + late Directory exportsDirectory; File createExportFile(BSExport export) { String path = @@ -29,11 +27,10 @@ class ExportManager { } List get exportFiles { - List result = exportsDirectory?.listSync(); + List result = exportsDirectory.listSync(); result .sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified)); return result; - return []; } ExportManager() { diff --git a/lib/export/export_models.dart b/lib/export/export_models.dart index fada8185..5500d085 100644 --- a/lib/export/export_models.dart +++ b/lib/export/export_models.dart @@ -22,7 +22,7 @@ class BSExport { this.sectionId}); File call(ExportManager exportManager) { - final midiFile = score.exportMidi(this); + final midiFile = score.exportMidi(this)!; final fileHandle = exportManager.createExportFile(this); MidiWriter().writeMidiToFile(midiFile, fileHandle); return fileHandle; diff --git a/lib/export/export_ui.dart b/lib/export/export_ui.dart index 45fa08cc..8e6688f9 100644 --- a/lib/export/export_ui.dart +++ b/lib/export/export_ui.dart @@ -35,7 +35,7 @@ class ExportUI { bool visible = false; bool exporting = false; - final BSExport export = BSExport(score: defaultScore()); + final BSExport export = BSExport(defaultScore()); ExportManager exportManager = ExportManager(); MessagesUI? messagesUI; @@ -294,11 +294,11 @@ class ExportUI { exportTypeWidth + sectionWidth + partsWidth + speedWidth; bool usesFlex = scrollContainerWidth > scrollContentsWidth; - Widget exportOption(String label, String value, double size, Color color, - {List values, - List disabledValues, - Widget customValue, - Function(String) selectValue}) { + Widget exportOption(String label, String? value, double size, Color color, + {required List values, + List disabledValues = const [], + Widget? customValue, + required Function(String?) selectValue}) { if (values.isEmpty) { values = [value]; } @@ -315,7 +315,7 @@ class ExportUI { color: v == value ? Colors.white : Colors.black12, padding: EdgeInsets.all(5), onPressed: clickable ? () => selectValue(v) : null, - child: Text(v, + child: Text(v ?? "", textAlign: TextAlign.center, style: valueStyle( !clickable @@ -325,7 +325,7 @@ class ExportUI { : Colors.white, ))); }).toList(), - customValue, + customValue ?? SizedBox(), // if (usesFlex) Expanded(child:SizedBox()) ]); // if (!usesFlex) { @@ -378,7 +378,8 @@ class ExportUI { "${(BeatScratchPlugin.bpmMultiplier ?? 1).toStringAsFixed(3).replaceAll("1.000", "1")}x" ], selectValue: (v) => setState(() { - export.tempoMultiplier = double.parse(v.replaceAll("x", "")); + export.tempoMultiplier = + double.parse((v ?? "").replaceAll("x", "")); })), exportOption( "Section", diff --git a/lib/export/midi_export.dart b/lib/export/midi_export.dart index 2b25ba46..7c9c57f8 100644 --- a/lib/export/midi_export.dart +++ b/lib/export/midi_export.dart @@ -1,15 +1,17 @@ +import 'package:beatscratch_flutter_redux/midi/byte_reader.dart'; +import 'package:beatscratch_flutter_redux/midi/byte_writer.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_events.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_file.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_header.dart'; +import 'package:beatscratch_flutter_redux/midi/midi_parser.dart'; + import '../export/export.dart'; import '../generated/protos/protos.dart'; -import 'package:dart_midi/dart_midi.dart'; -// ignore: implementation_imports -import 'package:dart_midi/src/byte_writer.dart'; -// ignore: implementation_imports -import 'package:dart_midi/src/byte_reader.dart'; import '../util/music_theory.dart'; import '../util/midi_theory.dart'; extension ScoreMidiExport on Score { - MidiFile exportMidi(BSExport export) { + MidiFile? exportMidi(BSExport export) { if (parts.isEmpty || sections.isEmpty) return null; final List track = parts .where((p) => export.includesPart(p)) @@ -35,7 +37,8 @@ extension ScoreMidiExport on Score { } print("Track assembled"); - final result = MidiFile([track], MidiHeader(ticksPerBeat: 24, format: 0)); + final result = MidiFile( + [track], MidiHeader(ticksPerBeat: 24, format: 0, numTracks: 1)); return result; } } @@ -53,6 +56,7 @@ extension SectionMidiExport on Section { r.isEnabled && part.melodies.any((m) => m.id == r.melodyId)) .forEach((ref) { final melody = score.melodyReferencedBy(ref); + if (melody == null) return; if (melody.type == MelodyType.midi) { int startBeat = 0; while (startBeat < beatCount) { @@ -61,8 +65,8 @@ extension SectionMidiExport on Section { final absoluteBeat = (subdivision.toDouble() / melody.subdivisionsPerBeat).floor(); final convertedTickOfBeat = - Base24Conversion.map[melody.subdivisionsPerBeat] - [subdivision % melody.subdivisionsPerBeat]; + Base24Conversion.map[melody.subdivisionsPerBeat]![ + subdivision % melody.subdivisionsPerBeat]; final absoluteTick = 24 * startBeat + startTick + 24 * absoluteBeat + diff --git a/lib/music_view/melody_editing_toolbar.dart b/lib/music_view/melody_editing_toolbar.dart index af77c98b..a7fa7779 100644 --- a/lib/music_view/melody_editing_toolbar.dart +++ b/lib/music_view/melody_editing_toolbar.dart @@ -1,3 +1,5 @@ +import 'package:collection/collection.dart'; + import '../cache_management.dart'; import '../colors.dart'; import '../generated/protos/music.pb.dart'; @@ -18,16 +20,16 @@ class MelodyEditingToolbar extends StatefulWidget { final Section currentSection; final bool recordingMelody; final bool visible; - final ValueNotifier highlightedBeat; + final ValueNotifier highlightedBeat; final Function(MelodyReference, double) setReferenceVolume; final VoidCallback toggleRecording; - Melody get melody => score.parts + Melody? get melody => score.parts .expand((p) => p.melodies) - .firstWhere((m) => m.id == melodyId, orElse: () => null); + .firstWhereOrNull((m) => m.id == melodyId); const MelodyEditingToolbar( - {Key key, + {Key? key, required this.melodyId, required this.sectionColor, required this.score, @@ -45,9 +47,9 @@ class MelodyEditingToolbar extends StatefulWidget { class _MelodyEditingToolbarState extends State with TickerProviderStateMixin { - AnimationController animationController; - Color recordingAnimationColor; - Animation recordingAnimation; + late AnimationController animationController; + Color? recordingAnimationColor; + late Animation recordingAnimation; bool showHoldToClear = false; bool showDataCleared = false; bool animationStarted = false; @@ -89,16 +91,24 @@ class _MelodyEditingToolbarState extends State animationStarted = false; } Color recordingColor; - if (widget.recordingMelody && BeatScratchPlugin.playing) { - recordingColor = recordingAnimationColor; + if (widget.recordingMelody && + BeatScratchPlugin.playing && + recordingAnimationColor != null) { + recordingColor = recordingAnimationColor!; } else { recordingColor = Colors.grey; } int beats; - beats = widget.melody.length ~/ widget.melody.subdivisionsPerBeat; + final melody = widget.melody; + if (melody == null) { + beats = 0; + } else { + beats = melody.length ~/ melody.subdivisionsPerBeat; + } bool hasHighlightedBeat = BeatScratchPlugin.playing && widget.recordingMelody; - final melodyReference = widget.currentSection.referenceTo(widget.melody); + final melodyReference = + melody != null ? widget.currentSection.referenceTo(melody) : null; bool playingOrCountingIn = BeatScratchPlugin.playing || BeatScratchPlugin.countInInitiated; bool showGo = widget.recordingMelody && @@ -214,23 +224,25 @@ class _MelodyEditingToolbarState extends State SizedBox(width: 7), IncrementableValue( collapsing: true, - onDecrement: (widget.melody.beatCount > 1) + onDecrement: ((melody?.beatCount ?? -1) > 1) ? () { - if (widget.melody.beatCount > 1) { - widget.melody.length -= widget.melody.subdivisionsPerBeat; + if (melody == null) return; + if (melody.beatCount > 1) { + melody.length -= melody.subdivisionsPerBeat; BeatScratchPlugin.onSynthesizerStatusChange(); - clearMutableCachesForMelody(widget.melody.id); - BeatScratchPlugin.updateMelody(widget.melody); + clearMutableCachesForMelody(melody.id); + BeatScratchPlugin.updateMelody(melody); } } : null, - onIncrement: (widget.melody.beatCount <= 999) + onIncrement: ((melody?.beatCount ?? 1000) <= 999) ? () { - if (widget.melody.beatCount <= 999) { - widget.melody.length += widget.melody.subdivisionsPerBeat; + if (melody == null) return; + if (melody.beatCount <= 999) { + melody.length += melody.subdivisionsPerBeat; BeatScratchPlugin.onSynthesizerStatusChange(); - clearMutableCachesForMelody(widget.melody.id); - BeatScratchPlugin.updateMelody(widget.melody); + clearMutableCachesForMelody(melody.id); + BeatScratchPlugin.updateMelody(melody); } } : null, @@ -243,36 +255,36 @@ class _MelodyEditingToolbarState extends State SizedBox(width: 5), IncrementableValue( collapsing: true, - onDecrement: (widget.melody.subdivisionsPerBeat ?? -1) > 1 + onDecrement: (melody?.subdivisionsPerBeat ?? -1) > 1 ? () { - if ((widget.melody.subdivisionsPerBeat ?? -1) > 1) { - widget.melody.subdivisionsPerBeat -= 1; - widget.melody.length = - beats * widget.melody.subdivisionsPerBeat; - clearMutableCachesForMelody(widget.melody.id); + if (melody == null) return; + if ((melody?.subdivisionsPerBeat ?? -1) > 1) { + melody.subdivisionsPerBeat -= 1; + melody.length = beats * melody.subdivisionsPerBeat; + clearMutableCachesForMelody(melody.id); BeatScratchPlugin.onSynthesizerStatusChange(); - clearMutableCachesForMelody(widget.melody.id); - BeatScratchPlugin.updateMelody(widget.melody); + clearMutableCachesForMelody(melody.id); + BeatScratchPlugin.updateMelody(melody); } } : null, - onIncrement: (widget.melody.subdivisionsPerBeat ?? -1) < 24 + onIncrement: (melody?.subdivisionsPerBeat ?? -1) < 24 ? () { - if ((widget.melody.subdivisionsPerBeat ?? -1) < 24) { - widget.melody.subdivisionsPerBeat += 1; - widget.melody.length = - beats * widget.melody.subdivisionsPerBeat; - clearMutableCachesForMelody(widget.melody.id); + if (melody == null) return; + if (melody.subdivisionsPerBeat < 24) { + melody.subdivisionsPerBeat += 1; + melody.length = beats * melody.subdivisionsPerBeat; + clearMutableCachesForMelody(melody.id); BeatScratchPlugin.onSynthesizerStatusChange(); - clearMutableCachesForMelody(widget.melody.id); - BeatScratchPlugin.updateMelody(widget.melody); + clearMutableCachesForMelody(melody.id); + BeatScratchPlugin.updateMelody(melody); } } : null, child: Padding( padding: EdgeInsets.symmetric(vertical: 0, horizontal: 5), child: BeatsBadge( - beats: widget.melody.subdivisionsPerBeat, + beats: melody?.subdivisionsPerBeat ?? 0, isPerBeat: true, )), ), @@ -282,12 +294,12 @@ class _MelodyEditingToolbarState extends State duration: animationDuration, opacity: widget.visible ? 1 : 0, child: MySlider( - value: melodyReference.volume ?? 0, - activeColor: melodyReference.playbackType == + value: melodyReference?.volume ?? 0, + activeColor: melodyReference?.playbackType == MelodyReference_PlaybackType.playback_indefinitely ? widget.sectionColor : widget.sectionColor.withOpacity(0.5), - onChanged: (widget.visible) + onChanged: (widget.visible && melodyReference != null) ? (value) { widget.setReferenceVolume(melodyReference, value); } @@ -355,13 +367,13 @@ class _MelodyEditingToolbarState extends State child: MyRaisedButton( color: Color(0x424242).withOpacity(1), padding: EdgeInsets.zero, - onLongPress: widget.melody != null + onLongPress: melody != null ? () { print("clearing"); - widget.melody.midiData.data.clear(); - clearMutableCachesForMelody(widget.melody.id); + melody.midiData.data.clear(); + clearMutableCachesForMelody(melody.id); BeatScratchPlugin.onSynthesizerStatusChange(); - BeatScratchPlugin.updateMelody(widget.melody); + BeatScratchPlugin.updateMelody(melody); setState(() { showDataCleared = true; showHoldToClear = false; @@ -415,15 +427,17 @@ class _MelodyEditingToolbarState extends State child: MyRaisedButton( color: Color(0x424242).withOpacity(1), padding: EdgeInsets.zero, - onLongPress: widget.melody != null + onLongPress: melody != null ? () { print("clearing single beat"); - int beatToDelete = widget.highlightedBeat.value; + var beatToDelete = widget.highlightedBeat.value; + if (beatToDelete == null) return; + beatToDelete -= firstBeatOfSection; - widget.melody.deleteBeat(beatToDelete); - clearMutableCachesForMelody(widget.melody.id); + melody.deleteBeat(beatToDelete); + clearMutableCachesForMelody(melody.id); BeatScratchPlugin.onSynthesizerStatusChange(); - BeatScratchPlugin.updateMelody(widget.melody); + BeatScratchPlugin.updateMelody(melody); setState(() { showDataCleared = true; showHoldToClear = false; diff --git a/lib/music_view/music_action_button.dart b/lib/music_view/music_action_button.dart index 4be03e0e..4f32f6b3 100644 --- a/lib/music_view/music_action_button.dart +++ b/lib/music_view/music_action_button.dart @@ -9,11 +9,11 @@ class MusicActionButton extends StatelessWidget { final bool visible; final double width, height; final Widget child; - final VoidCallback onPressed; + final VoidCallback? onPressed; final Color color; MusicActionButton( - {Key key, + {Key? key, this.visible = true, this.width = 48, this.height = 48, diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 8f98ef95..6c1aa582 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -32,8 +32,8 @@ class MusicScrollContainer extends StatefulWidget { final ValueNotifier> keyboardNotesNotifier, colorboardNotesNotifier; final ValueNotifier>> bluetoothControllerPressedNotes; - final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; - final ValueNotifier tappedPart; + final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; + final ValueNotifier tappedPart; final ValueNotifier requestedScrollOffsetForScale; final TransformationController transformationController; final ValueNotifier scaleUpdateNotifier; @@ -41,36 +41,36 @@ class MusicScrollContainer extends StatefulWidget { final bool showingSectionList; const MusicScrollContainer( - {Key key, - this.score, - this.currentSection, - this.sectionColor, - this.focusedMelody, - this.renderingMode, - this.colorboardNotesNotifier, - this.keyboardNotesNotifier, - this.bluetoothControllerPressedNotes, - this.musicViewMode, - this.staves, - this.keyboardPart, - this.colorboardPart, - this.focusedPart, - this.width, - this.height, - this.isCurrentScore, - this.highlightedBeat, - this.focusedBeat, - this.tappedBeat, - this.tappedPart, - this.requestedScrollOffsetForScale, - this.targetScaleNotifier, - this.scrollToCurrentBeat, - this.centerCurrentSection, - this.appSettings, - this.transformationController, - this.scaleUpdateNotifier, - this.scrollToPart, - this.showingSectionList}) + {Key? key, + required this.score, + required this.currentSection, + required this.sectionColor, + required this.focusedMelody, + required this.renderingMode, + required this.colorboardNotesNotifier, + required this.keyboardNotesNotifier, + required this.bluetoothControllerPressedNotes, + required this.musicViewMode, + required this.staves, + required this.keyboardPart, + required this.colorboardPart, + required this.focusedPart, + required this.width, + required this.height, + required this.isCurrentScore, + required this.highlightedBeat, + required this.focusedBeat, + required this.tappedBeat, + required this.tappedPart, + required this.requestedScrollOffsetForScale, + required this.targetScaleNotifier, + required this.scrollToCurrentBeat, + required this.centerCurrentSection, + required this.appSettings, + required this.transformationController, + required this.scaleUpdateNotifier, + required this.scrollToPart, + required this.showingSectionList}) : super(key: key); @override @@ -84,32 +84,32 @@ class _MusicScrollContainerState extends State with TickerProviderStateMixin { static final double scrollTopMarginPercent = 0.17; static final double scrollLeftMarginPercent = 0.25; - AnimationController animationController; - ValueNotifier colorGuideOpacityNotifier, + late AnimationController animationController; + late ValueNotifier colorGuideOpacityNotifier, colorblockOpacityNotifier, notationOpacityNotifier, sectionScaleNotifier; // partTopOffsets are animated based off the Renderer's StaffConfigurations - ValueNotifier> stavesNotifier; - ValueNotifier> partTopOffsets; - ValueNotifier> staffOffsets; + late ValueNotifier> stavesNotifier; + late ValueNotifier> partTopOffsets; + late ValueNotifier> staffOffsets; - ValueNotifier keyboardPart; - ValueNotifier colorboardPart; - ValueNotifier focusedPart; - ValueNotifier sectionColor; + late ValueNotifier keyboardPart; + late ValueNotifier colorboardPart; + late ValueNotifier focusedPart; + late ValueNotifier sectionColor; - MusicViewMode _prevViewMode; + MusicViewMode? _prevViewMode; bool _hasBuilt = false; DateTime _lastAutoScrollTime = DateTime(0); - double prevWidth; - double _prevBeat; - String _prevSectionOrder; - String _prevSectionId; - Score _prevScore; + double? prevWidth; + double? _prevBeat; + String? _prevSectionOrder; + String? _prevSectionId; + Score? _prevScore; // ignore: unused_field - String _prevPartId; + String? _prevPartId; Rect visibleRect = Rect.zero; bool get isViewingSection => widget.musicViewMode != MusicViewMode.score; @@ -122,9 +122,9 @@ class _MusicScrollContainerState extends State ValueNotifier get scaleUpdateNotifier => widget.scaleUpdateNotifier; double get dx => - MatrixUtils.getAsTranslation(transformationController.value).dx; + MatrixUtils.getAsTranslation(transformationController.value)!.dx; double get dy => - MatrixUtils.getAsTranslation(transformationController.value).dy; + MatrixUtils.getAsTranslation(transformationController.value)!.dy; double get scale => transformationController.value.getMaxScaleOnAxis(); double get scaledStandardBeatWidth => beatWidth * scale; @@ -148,18 +148,19 @@ class _MusicScrollContainerState extends State ? 9999999 : widget.appSettings.systemsToRender; - double systemRenderAreaWidth({double customScale = null}) => + double systemRenderAreaWidth({double? customScale = null}) => max(0, (widget.width / (customScale ?? scale)) - clefWidth); - double beatsOnScreenPerSystem({double customScale = null}) => + double beatsOnScreenPerSystem({double? customScale = null}) => systemRenderAreaWidth(customScale: customScale) / beatWidth; - int maxSystemsNeeded({double customScale = null}) => (widget.score.beatCount / - max(0.1, beatsOnScreenPerSystem(customScale: customScale))) - .ceil(); + int maxSystemsNeeded({double? customScale = null}) => + (widget.score.beatCount / + max(0.1, beatsOnScreenPerSystem(customScale: customScale))) + .ceil(); - int systemsToRender({double customScale = null}) => + int systemsToRender({double? customScale = null}) => min(maxSystemsNeeded(customScale: customScale), maxSupportedSystems); - double calculatedSystemThingy({double customScale = null}) { + double calculatedSystemThingy({double? customScale = null}) { final systemsToRender = this.systemsToRender(customScale: customScale); return ((systemsToRender) * ((currentBeat - 2) / @@ -169,7 +170,7 @@ class _MusicScrollContainerState extends State // In multi-system mode, we select a "target system" for the // currentBeat based on how far into the score currentBeat is. - int currentBeatTargetSystemIndex({double customScale = null}) { + int currentBeatTargetSystemIndex({double? customScale = null}) { final systemsToRender = this.systemsToRender(customScale: customScale); return max( 0, @@ -180,7 +181,7 @@ class _MusicScrollContainerState extends State : calculatedSystemThingy(customScale: customScale).floor())); } - double currentBeatTargetSystemXOffset({double customScale = null}) => + double currentBeatTargetSystemXOffset({double? customScale = null}) => currentBeatTargetSystemIndex(customScale: customScale) * (systemRenderAreaWidth(customScale: customScale)); double get _systemHeightForScrolling => @@ -197,7 +198,7 @@ class _MusicScrollContainerState extends State max(widget.width / smallerScale, (numberOfBeats + extraBeatsSpaceForClefs) * targetBeatWidth) * 3; - double overallCanvasHeight({double customScale = null}) => + double overallCanvasHeight({double? customScale = null}) => max(widget.height / smallerScale, systemsToRender(customScale: customScale) * systemHeight) * 3; @@ -216,19 +217,22 @@ class _MusicScrollContainerState extends State double get scaledSystemHeight => MusicSystemPainter.calculateSystemHeight( scale, widget.score.parts.length); - Animation interactiveAnimation; - AnimationController interactiveController; + Animation? interactiveAnimation; + late AnimationController interactiveController; void _interactiveAnimationStop() { interactiveController.stop(); - interactiveAnimation.removeListener(_onInteractiveAnimation); + interactiveAnimation?.removeListener(_onInteractiveAnimation); interactiveAnimation = null; interactiveController.reset(); } void _onInteractiveAnimation() { - transformationController.value = interactiveAnimation.value; + final interactiveAnimationValue = interactiveAnimation?.value; + if (interactiveAnimationValue == null) return; + + transformationController.value = interactiveAnimationValue; if (!interactiveController.isAnimating) { - interactiveAnimation.removeListener(_onInteractiveAnimation); + interactiveAnimation?.removeListener(_onInteractiveAnimation); interactiveAnimation = null; interactiveController.reset(); } @@ -286,7 +290,7 @@ class _MusicScrollContainerState extends State begin: transformationController.value, end: targetedMatrix, ).animate(interactiveController); - interactiveAnimation.addListener(_onInteractiveAnimation); + interactiveAnimation?.addListener(_onInteractiveAnimation); interactiveController.forward(); } } @@ -351,7 +355,7 @@ class _MusicScrollContainerState extends State interactionStartFocal.addListener(_deriveStartSystemFromFocal); } - VoidCallback xScaleUpdateListener, yScaleUpdateListener; + // VoidCallback? xScaleUpdateListener, yScaleUpdateListener; _transformationListener() {} @@ -379,16 +383,16 @@ class _MusicScrollContainerState extends State super.dispose(); } - ValueNotifier interactionStartFocal = ValueNotifier(null); - ValueNotifier interactionStartSystem = ValueNotifier(null); + ValueNotifier interactionStartFocal = ValueNotifier(null); + ValueNotifier interactionStartSystem = ValueNotifier(null); _deriveStartSystemFromFocal() { interactionStartSystem.value = max(0, (interactingFocal.dy / scaledSystemHeight).floor()); } - Offset get interactingFocal => interactionStartFocal.value; + Offset get interactingFocal => interactionStartFocal.value!; int get interactingSystem => - max(0, min(systemsToRender() - 1, interactionStartSystem.value)); + max(0, min(systemsToRender() - 1, interactionStartSystem.value!)); adjustDxForScale(int systemNumber, double scaleChange, Matrix4 target, {bool adjustingAfterChange = true}) { @@ -406,7 +410,7 @@ class _MusicScrollContainerState extends State if (transformedRect.left > -scaledAvailableWidth2) { target.translate(diff, 0.0, 0.0); } else { - interactionStartSystem.value -= 1; + interactionStartSystem.value = interactionStartSystem.value! - 1; target.translate(diff - scaledAvailableWidth2, systemHeight, 0.0); } // } else if (adjustingAfterChange) { @@ -435,7 +439,7 @@ class _MusicScrollContainerState extends State if (autoScroll) { if (_prevViewMode == MusicViewMode.score && widget.musicViewMode != MusicViewMode.score && - _prevBeat > widget.currentSection.beatCount - 2) { + _prevBeat! > widget.currentSection.beatCount - 2) { Future.delayed(slowAnimationDuration, () { scrollToCurrentBeat(); _lastAutoScrollTime = DateTime.now(); @@ -595,7 +599,7 @@ class _MusicScrollContainerState extends State // bool showOnSecondSystem(double animationPos) => // systemsToRender > 1 && animationPos > secondSystemOffset; - double _animationPos(double currentBeat, {double customScale = null}) { + double _animationPos(double currentBeat, {double? customScale = null}) { // print( // "_animationPos: $currentBeat $targetBeatWidth $overallCanvasWidth ${horizontallyVisibleRect.width}!"); @@ -633,7 +637,7 @@ class _MusicScrollContainerState extends State sectionWidth + targetClefWidth <= transformedRect.width; int get staffCount => stavesNotifier.value.length; - void scrollToCurrentBeat({double customScale = null}) { + void scrollToCurrentBeat({double? customScale = null}) { print("scrollToCurrentBeat, sectionCanBeCentered=$sectionCanBeCentered"); if (sectionCanBeCentered) { constrainToSectionBounds(customScale: customScale); @@ -646,7 +650,7 @@ class _MusicScrollContainerState extends State max(0, visibleWidth - 2 * targetClefWidth - targetBeatWidth) / targetBeatWidth; - constrainToSectionBounds({double customScale = null}) { + constrainToSectionBounds({double? customScale = null}) { double ratioScale = (customScale ?? scale) / scale; double marginBeatsForSection = max(0.0, visibleWidth / ratioScale - targetClefWidth - sectionWidth) / @@ -663,7 +667,7 @@ class _MusicScrollContainerState extends State } void scrollToBeat(double targetBeat, - {double customScale = null, + {double? customScale = null, bool includeMarginX = true, bool scrollHorizontally = true}) { final scale = this.scale; diff --git a/lib/music_view/music_system_painter.dart b/lib/music_view/music_system_painter.dart index ea274c05..42b3d7eb 100644 --- a/lib/music_view/music_system_painter.dart +++ b/lib/music_view/music_system_painter.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:beatscratch_flutter_redux/widget/my_platform.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import '../util/util.dart'; @@ -38,11 +39,9 @@ class MusicSystemPainter extends CustomPainter { final ValueNotifier> staves; final ValueNotifier> partTopOffsets, staffOffsets; final ValueNotifier sectionColor; - final ValueNotifier keyboardPart, - colorboardPart, - focusedPart, - tappedPart; - final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; + final ValueNotifier keyboardPart, colorboardPart, focusedPart; + final ValueNotifier tappedPart; + final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; final bool isCurrentScore, isPreview, renderPartNames; final double firstBeatOfSection; final int systemsToRender; @@ -51,9 +50,9 @@ class MusicSystemPainter extends CustomPainter { double get yScale => 1; double get scale => transformationController.value.getMaxScaleOnAxis(); - Melody get focusedMelody => score.parts + Melody? get focusedMelody => score.parts .expand((p) => p.melodies) - .firstWhere((m) => m.id == focusedMelodyId, orElse: () => null); + .firstWhereOrNull((m) => m.id == focusedMelodyId); int get numberOfBeats => /*isViewingSection ? section.harmony.beatCount :*/ score.beatCount; @@ -63,38 +62,38 @@ class MusicSystemPainter extends CustomPainter { int get colorGuideAlpha => (255 * colorGuideOpacityNotifier.value).toInt(); MusicSystemPainter( - {this.isPreview, - this.focusedBeat, - this.tappedBeat, - this.firstBeatOfSection, - this.highlightedBeat, - this.musicViewMode, - this.colorGuideOpacityNotifier, - this.sectionColor, - this.focusedPart, - this.tappedPart, - this.keyboardPart, - this.colorboardPart, - this.staves, - this.partTopOffsets, - this.staffOffsets, - this.sectionScaleNotifier, - this.colorboardNotesNotifier, - this.keyboardNotesNotifier, - this.bluetoothControllerPressedNotes, - this.score, - this.section, - this.transformationController, + {required this.isPreview, + required this.focusedBeat, + required this.tappedBeat, + required this.firstBeatOfSection, + required this.highlightedBeat, + required this.musicViewMode, + required this.colorGuideOpacityNotifier, + required this.sectionColor, + required this.focusedPart, + required this.tappedPart, + required this.keyboardPart, + required this.colorboardPart, + required this.staves, + required this.partTopOffsets, + required this.staffOffsets, + required this.sectionScaleNotifier, + required this.colorboardNotesNotifier, + required this.keyboardNotesNotifier, + required this.bluetoothControllerPressedNotes, + required this.score, + required this.section, + required this.transformationController, this.rescale = false, - this.visibleRect, - this.verticallyVisibleRect, - this.focusedMelodyId, - this.colorblockOpacityNotifier, - this.notationOpacityNotifier, - this.isCurrentScore, - this.renderPartNames, + required this.visibleRect, + required this.verticallyVisibleRect, + required this.focusedMelodyId, + required this.colorblockOpacityNotifier, + required this.notationOpacityNotifier, + required this.isCurrentScore, + required this.renderPartNames, this.systemsToRender = 1, - List otherListenables = null}) + List otherListenables = const []}) : super( repaint: Listenable.merge([ colorblockOpacityNotifier, diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index c1794734..aea0ab33 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -9,7 +9,7 @@ import '../widget/my_platform.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_icons/flutter_icons.dart'; +// import 'package:flutter_icons/flutter_icons.dart'; import '../beatscratch_plugin.dart'; import '../generated/protos/music.pb.dart'; @@ -71,53 +71,53 @@ class MusicView extends StatefulWidget { final BSMethod scrollToCurrentBeat; MusicView( - {this.appSettings, - this.selectBeat, - this.selectOrDeselectPart, - this.selectOrDeselectMelody, - this.melodyViewSizeFactor, - this.addPart, - this.cloneCurrentSection, - this.superSetState, - this.musicViewMode, - this.score, - this.currentSection, - this.melody, - this.part, - this.sectionColor, - this.splitMode, - this.toggleSplitMode, - this.closeMelodyView, - this.toggleMelodyReference, - this.setReferenceVolume, - this.setPartVolume, - this.recordingMelody, - this.toggleRecording, - this.setMelodyName, - this.setSectionName, - this.setKeyboardPart, - this.setColorboardPart, - this.colorboardPart, - this.keyboardPart, - this.deletePart, - this.deleteMelody, - this.deleteSection, - this.renderingMode, - this.colorboardNotesNotifier, - this.keyboardNotesNotifier, - this.bluetoothControllerPressedNotes, - this.height, - this.width, - this.enableColorboard, + {Key? key, + required this.appSettings, + required this.selectBeat, + required this.selectOrDeselectPart, + required this.selectOrDeselectMelody, + required this.melodyViewSizeFactor, + required this.addPart, + required this.cloneCurrentSection, + required this.superSetState, + required this.musicViewMode, + required this.score, + required this.currentSection, + required this.melody, + required this.part, + required this.sectionColor, + required this.splitMode, + required this.toggleSplitMode, + required this.closeMelodyView, + required this.toggleMelodyReference, + required this.setReferenceVolume, + required this.setPartVolume, + required this.recordingMelody, + required this.toggleRecording, + required this.setMelodyName, + required this.setSectionName, + required this.setKeyboardPart, + required this.setColorboardPart, + required this.colorboardPart, + required this.keyboardPart, + required this.deletePart, + required this.deleteMelody, + required this.deleteSection, + required this.renderingMode, + required this.colorboardNotesNotifier, + required this.keyboardNotesNotifier, + required this.bluetoothControllerPressedNotes, + required this.height, + required this.width, + required this.enableColorboard, this.isCurrentScore = true, - Key key, - this.requestRenderingMode, + required this.requestRenderingMode, this.showViewOptions = false, this.backgroundColor = Colors.white, - this.showBeatCounts, - this.createMelody, - this.scrollToCurrentBeat, - this.showingSectionList}) + required this.showBeatCounts, + required this.createMelody, + required this.scrollToCurrentBeat, + required this.showingSectionList}) : super(key: key); @override @@ -127,17 +127,17 @@ class MusicView extends StatefulWidget { class _MusicViewState extends State with TickerProviderStateMixin { static const double minScale = MusicScrollContainer.minScale; static const double maxScale = MusicScrollContainer.maxScale; - bool _disposed; + bool _disposed = false; bool get autoScroll => widget.appSettings.autoScrollMusic; set autoScroll(bool v) => widget.appSettings.autoScrollMusic = v; bool get autoSort => widget.appSettings.autoSortMusic; set autoSort(bool v) => widget.appSettings.autoSortMusic = v; bool get autoZoomAlign => widget.appSettings.autoZoomAlignMusic; set autoZoomAlign(bool v) => widget.appSettings.autoZoomAlignMusic = v; - bool isConfiguringPart; - bool isBrowsingPartMelodies; - bool isEditingSection; - TransformationController transformationController; + bool isConfiguringPart = false; + bool isBrowsingPartMelodies = false; + bool isEditingSection = false; + late TransformationController transformationController; ValueNotifier scaleUpdateNotifier = ValueNotifier(ScaleUpdateDetails()); @@ -170,46 +170,46 @@ class _MusicViewState extends State with TickerProviderStateMixin { bool get showViewOptions => widget.showViewOptions || forceShowViewOptions; /// Always immediately updated; the return values of [targetedScale] and [scale]. - ValueNotifier _targetedScale; - double get targetedScale => _targetedScale.value; - set targetedScale(double v) { + late ValueNotifier _targetedScale; + double? get targetedScale => _targetedScale.value; + set targetedScale(double? v) { print("set targetedScale=$v"); _targetedScale.value = v; - widget.appSettings.musicScale = v; + if (v != null) widget.appSettings.musicScale = v; } /// Used to maintain a locking mechanism as we animate from [_xScale] to [targetedScale] in the setter for [targetedScale]. - DateTime _xScaleLock; - List _xScaleAnimationControllers, + late DateTime _xScaleLock; + late List _xScaleAnimationControllers, _yScaleAnimationControllers; /// Used to notify the [MusicScrollContainer] as we animate [_xScale] to [targetedScale] in the setter for [targetedScale]. // BSValueMethod _xScaleUpdate, _yScaleUpdate; - Map> _swipeTutorialsSeen; - SwipeTutorial _currentSwipeTutorial; + late Map> _swipeTutorialsSeen; + SwipeTutorial? _currentSwipeTutorial; - BSMethod centerCurrentSection, scrollToPart; + late BSMethod centerCurrentSection, scrollToPart; // static const double maxScaleDiscrepancy = 1.5; // static const double minScaleDiscrepancy = 1 / maxScaleDiscrepancy; - ValueNotifier highlightedBeat; + late ValueNotifier highlightedBeat; DateTime focusedBeatUpdated = DateTime(0); - ValueNotifier focusedBeat, tappedBeat; - ValueNotifier tappedPart; + late ValueNotifier focusedBeat, tappedBeat; + late ValueNotifier tappedPart; // ValueNotifier _tappedYCoord; - ValueNotifier requestedScrollOffsetForScale; + late ValueNotifier requestedScrollOffsetForScale; - String _lastIgnoreId; + String? _lastIgnoreId; bool _ignoreNextTap = false; // ignore: unused_field - MusicViewMode _previousMusicViewMode; + MusicViewMode? _previousMusicViewMode; // ignore: unused_field - SplitMode _previousSplitMode; + SplitMode? _previousSplitMode; bool get _aligned => widget.appSettings.alignMusic; set _aligned(bool v) => widget.appSettings.alignMusic = v; @@ -219,10 +219,12 @@ class _MusicViewState extends State with TickerProviderStateMixin { AnimationController animationController() => AnimationController(vsync: this, duration: animationDuration); - SwipeTutorial get currentSwipeTutorial => _currentSwipeTutorial; + SwipeTutorial? get currentSwipeTutorial => _currentSwipeTutorial; - set currentSwipeTutorial(SwipeTutorial value) { - if (_swipeTutorialsSeen[widget.musicViewMode].contains(value)) { + set currentSwipeTutorial(SwipeTutorial? value) { + if (value == null) return; + + if (_swipeTutorialsSeen[widget.musicViewMode]?.contains(value) == true) { _currentSwipeTutorial = null; return; } @@ -240,7 +242,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { required double Function() currentValue, required Function(double) applyAnimatedValue, required List controllers, - VoidCallback onComplete}) { + VoidCallback? onComplete}) { if (value() == currentValue()) { // print("skipping scale animation: no change (${currentValue()} to ${value()}"); } else { @@ -253,7 +255,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { AnimationController scaleAnimationController = animationController(); controllers.add(scaleAnimationController); - Animation animation; + late Animation animation; // print("animating targetedScale to $value"); // print("Tween params: begin: $currentValue, end: $value"); animation = Tween(begin: currentValue(), end: value()) @@ -270,7 +272,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { if (status == AnimationStatus.completed) { Future.delayed(animationDuration, () { // print("_startValueAnimation onComplete"); - onComplete.call(); + onComplete?.call(); }); } }); @@ -281,7 +283,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { static const focusTimeout = 2500; _updateFocusedBeatValue( - {int value, bool withDelayClear = true, bool force = false}) { + {int? value, bool withDelayClear = true, bool force = false}) { if (force || DateTime.now().difference(focusedBeatUpdated).inMilliseconds > focusTimeout) { @@ -379,9 +381,9 @@ class _MusicViewState extends State with TickerProviderStateMixin { } double get dx => - MatrixUtils.getAsTranslation(transformationController.value).dx; + MatrixUtils.getAsTranslation(transformationController.value)!.dx; double get dy => - MatrixUtils.getAsTranslation(transformationController.value).dy; + MatrixUtils.getAsTranslation(transformationController.value)!.dy; double get scale => transformationController.value.getMaxScaleOnAxis(); set scale(value) { print( @@ -403,7 +405,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { _disposed = false; transformationController = TransformationController() ..addListener(_onTransformationChange); - highlightedBeat = new ValueNotifier(null); + highlightedBeat = new ValueNotifier(0); focusedBeat = new ValueNotifier(null); tappedBeat = new ValueNotifier(null); tappedPart = new ValueNotifier(null); @@ -504,10 +506,11 @@ class _MusicViewState extends State with TickerProviderStateMixin { (widget.musicViewMode == MusicViewMode.part || widget.musicViewMode == MusicViewMode.melody || widget.musicViewMode == MusicViewMode.score)) { - if (targetedScale.notRoughlyEquals(partAlignedScale)) { + if (targetedScale?.notRoughlyEquals(partAlignedScale) == true) { partAlignVertically(); } - } else if (_aligned && targetedScale.notRoughlyEquals(alignedScale)) { + } else if (_aligned && + targetedScale?.notRoughlyEquals(alignedScale) == true) { alignVertically(); } _previousSplitMode = widget.splitMode; @@ -777,10 +780,11 @@ class _MusicViewState extends State with TickerProviderStateMixin { child: Column(children: [ Expanded(child: SizedBox()), Text( - currentSwipeTutorial.tutorialText( - widget.splitMode, - widget.musicViewMode, - context), + currentSwipeTutorial! + .tutorialText( + widget.splitMode, + widget.musicViewMode, + context), style: TextStyle(fontSize: 11), overflow: TextOverflow.fade, maxLines: 2, @@ -890,30 +894,30 @@ class _MusicViewState extends State with TickerProviderStateMixin { Expanded(child: _mainMelody(context)) ], ), - if (MyPlatform.isDebug && false) - IgnorePointer( - child: Container( - width: 2 * targetedScale * beatWidth, - height: widget.height, - decoration: BoxDecoration( - color: Colors.black12, - border: Border.all( - color: Colors.red[500], - ), - borderRadius: BorderRadius.all(Radius.circular(5))), - )), - if (MyPlatform.isDebug && false) - IgnorePointer( - child: Container( - width: widget.width, - height: 50, - decoration: BoxDecoration( - color: Colors.black12, - border: Border.all( - color: Colors.blue[500], - ), - borderRadius: BorderRadius.all(Radius.circular(5))), - )) + // if (MyPlatform.isDebug && false) + // IgnorePointer( + // child: Container( + // width: 2 * targetedScale * beatWidth, + // height: widget.height, + // decoration: BoxDecoration( + // color: Colors.black12, + // border: Border.all( + // color: Colors.red[500], + // ), + // borderRadius: BorderRadius.all(Radius.circular(5))), + // )), + // if (MyPlatform.isDebug && false) + // IgnorePointer( + // child: Container( + // width: widget.width, + // height: 50, + // decoration: BoxDecoration( + // color: Colors.black12, + // border: Border.all( + // color: Colors.blue[500], + // ), + // borderRadius: BorderRadius.all(Radius.circular(5))), + // )) ]); } @@ -1076,6 +1080,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { onLongPress() { if (widget.score.parts.isEmpty) return; final part = tappedPart.value; + if (part == null) return; HapticFeedback.lightImpact(); if (widget.musicViewMode == MusicViewMode.score) { widget.setKeyboardPart(part); @@ -1148,7 +1153,9 @@ class _MusicViewState extends State with TickerProviderStateMixin { if (ignoreNextTap) { return; } - int beat = tappedBeat.value; + final beat = tappedBeat.value; + if (beat == null) return; + print( "onTapUp: ${details.localPosition} -> beat: $beat; x/t: $scale/$targetedScale"); if (BeatScratchPlugin.playing && diff --git a/lib/music_view/part_instrument_picker.dart b/lib/music_view/part_instrument_picker.dart index 361a297b..84dba0c5 100644 --- a/lib/music_view/part_instrument_picker.dart +++ b/lib/music_view/part_instrument_picker.dart @@ -22,11 +22,11 @@ class PartConfiguration extends StatefulWidget { final bool visible; const PartConfiguration( - {Key key, - this.part, - this.superSetState, - this.availableHeight, - this.visible}) + {Key? key, + required this.part, + required this.superSetState, + required this.availableHeight, + required this.visible}) : super(key: key); @override diff --git a/lib/music_view/part_melody_browser.dart b/lib/music_view/part_melody_browser.dart index 6b677a67..13226e86 100644 --- a/lib/music_view/part_melody_browser.dart +++ b/lib/music_view/part_melody_browser.dart @@ -23,15 +23,15 @@ class PartMelodyBrowser extends StatefulWidget { final Function(Part, Melody, bool) createMelody; const PartMelodyBrowser( - {Key key, - this.sectionColor, - this.score, - this.currentSection, - this.part, - this.browsingMelodies, - this.selectOrDeselectMelody, - this.createMelody, - this.toggleMelodyReference}) + {Key? key, + required this.sectionColor, + required this.score, + required this.currentSection, + required this.part, + required this.browsingMelodies, + required this.selectOrDeselectMelody, + required this.createMelody, + required this.toggleMelodyReference}) : super(key: key); @override @@ -40,7 +40,7 @@ class PartMelodyBrowser extends StatefulWidget { class _PartMelodyBrowserState extends State with TickerProviderStateMixin { - ScrollController _scrollController; + late ScrollController _scrollController; @override void initState() { @@ -165,8 +165,8 @@ class _PartMelodyBrowserState extends State Widget getList(BuildContext context) { var items = widget.part.melodies ?? []; items.sort((m1, m2) { - final r1 = widget.currentSection.referenceTo(m1); - final r2 = widget.currentSection.referenceTo(m2); + final r1 = widget.currentSection.referenceTo(m1)!; + final r2 = widget.currentSection.referenceTo(m2)!; if (r1.isEnabled == r2.isEnabled) { return 0; } else if (r1.isEnabled) { @@ -183,7 +183,7 @@ class _PartMelodyBrowserState extends State items: items, areItemsTheSame: (a, b) => a.id == b.id, itemBuilder: (context, animation, melody, index) { - final reference = widget.currentSection.referenceTo(melody); + final reference = widget.currentSection.referenceTo(melody)!; final width = 120.0; final height = widget.browsingMelodies ? 48.0 : 0.0; @@ -210,7 +210,7 @@ class _PartMelodyBrowserState extends State }, onLongPress: () { final reference = - widget.currentSection.referenceTo(melody); + widget.currentSection.referenceTo(melody)!; widget.toggleMelodyReference(reference); }, child: Text(melody.canonicalName, diff --git a/lib/music_view/section_editing_toolbar.dart b/lib/music_view/section_editing_toolbar.dart index 9806c7bf..cc2912ee 100644 --- a/lib/music_view/section_editing_toolbar.dart +++ b/lib/music_view/section_editing_toolbar.dart @@ -15,7 +15,10 @@ class SectionEditingToolbar extends StatefulWidget { final Section currentSection; const SectionEditingToolbar( - {Key key, this.sectionColor, this.score, this.currentSection}) + {Key? key, + required this.sectionColor, + required this.score, + required this.currentSection}) : super(key: key); @override @@ -24,9 +27,9 @@ class SectionEditingToolbar extends StatefulWidget { class _SectionEditingToolbarState extends State with TickerProviderStateMixin { - AnimationController animationController; - Color recordingAnimationColor; - Animation recordingAnimation; + late AnimationController animationController; + late Color recordingAnimationColor; + late Animation recordingAnimation; static final List keys = [ NoteName() @@ -116,7 +119,7 @@ class _SectionEditingToolbarState extends State // } else { // recordingColor = Colors.grey; // } - NoteName key = widget.currentSection.harmony.data[0].rootNote; + NoteName key = widget.currentSection.harmony.data[0]!.rootNote; int keyIndex = keys.indexOf(key); return Row(children: [ SizedBox(width: 1), @@ -290,7 +293,7 @@ class _SectionEditingToolbarState extends State if (newKeyIndex < 0) { newKeyIndex += keys.length; } - widget.currentSection.harmony.data[0].rootNote = keys[newKeyIndex]; + widget.currentSection.harmony.data[0]!.rootNote = keys[newKeyIndex]; MelodyTheory.tonesInMeasureCache.clear(); BeatScratchPlugin.onSynthesizerStatusChange(); BeatScratchPlugin.updateSections(widget.score); @@ -303,7 +306,7 @@ class _SectionEditingToolbarState extends State if (newKeyIndex >= keys.length) { newKeyIndex -= keys.length; } - widget.currentSection.harmony.data[0].rootNote = keys[newKeyIndex]; + widget.currentSection.harmony.data[0]!.rootNote = keys[newKeyIndex]; MelodyTheory.tonesInMeasureCache.clear(); BeatScratchPlugin.onSynthesizerStatusChange(); BeatScratchPlugin.updateSections(widget.score); diff --git a/lib/recording/recording.dart b/lib/recording/recording.dart index a86141ac..25289a69 100644 --- a/lib/recording/recording.dart +++ b/lib/recording/recording.dart @@ -12,11 +12,11 @@ import '../util/music_utils.dart'; /// are sent to this singleton queue for processing. class RecordedSegmentQueue { /// Gets the recording melody from your UI. Should be set in [State.initState] and [State.dispose]. - static Melody Function() getRecordingMelody; + static Melody Function()? getRecordingMelody; /// Should be set in [State.initState] and [State.dispose] for - static Function(Melody) updateRecordingMelody; - static Melody get recordingMelody => getRecordingMelody.call(); + static Function(Melody)? updateRecordingMelody; + static Melody get recordingMelody => getRecordingMelody!.call(); // static set recordingMelody(Melody melody) => updateRecordingMelody(melody); static final Queue segments = ListQueue(); static final BSValueMethod enabled = BSValueMethod(false) @@ -51,7 +51,7 @@ class RecordedSegmentQueue { RecordedSegment_RecordedBeat firstBeat = segment.beats.minBy((rb) => rb.timestamp.toInt()); RecordedSegment_RecordedBeat secondBeat = - segment.beats.maxBy((rb) => rb.timestamp.toInt()); + segment.beats.maxBy((rb) => rb.timestamp.toInt())!; segment.recordedData.forEach((data) { _processSegmentData(segment, data, melody, firstBeat, secondBeat); }); diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 49a52b29..3ce354a5 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -9,7 +9,7 @@ import '../widget/my_platform.dart'; class AppSettings { static bool initializingState = true; static RenderingMode globalRenderingMode = RenderingMode.notation; - SharedPreferences _preferences; + SharedPreferences? _preferences; AppSettings() { _initialize(); } @@ -31,109 +31,112 @@ class AppSettings { } RenderingMode get renderingMode => RenderingMode.values.firstWhere( - (rm) => rm.index == (_preferences.getInt('renderingMode') ?? 0)); + (rm) => rm.index == (_preferences?.getInt('renderingMode') ?? 0)); set renderingMode(RenderingMode rm) { globalRenderingMode = rm; - _preferences.setInt('renderingMode', rm.index); + _preferences?.setInt('renderingMode', rm.index); } List get controllersReplacingKeyboard => - _preferences.getStringList('controllersReplacingKeyboard') ?? []; + _preferences?.getStringList('controllersReplacingKeyboard') ?? []; set controllersReplacingKeyboard(List value) => - _preferences.setStringList("controllersReplacingKeyboard", value); + _preferences?.setStringList("controllersReplacingKeyboard", value); - bool get integratePastee => _preferences.getBool('integratePastee') ?? true; + bool get integratePastee => _preferences?.getBool('integratePastee') ?? true; set integratePastee(bool value) => - _preferences.setBool("integratePastee", value); + _preferences?.setBool("integratePastee", value); - bool get darkMode => _preferences.getBool('darkMode') ?? true; + bool get darkMode => _preferences?.getBool('darkMode') ?? true; set darkMode(bool value) { - _preferences.setBool("darkMode", value); + _preferences?.setBool("darkMode", value); _updateColors(); } - bool get autoScrollLayers => _preferences.getBool('autoScrollLayers') ?? true; + bool get autoScrollLayers => + _preferences?.getBool('autoScrollLayers') ?? true; set autoScrollLayers(bool value) { - _preferences.setBool("autoScrollLayers", value); + _preferences?.setBool("autoScrollLayers", value); } double get layersColumnWidth => - _preferences.getDouble('layersColumnWidth') ?? 100; + _preferences?.getDouble('layersColumnWidth') ?? 100; set layersColumnWidth(double value) => - _preferences.setDouble("layersColumnWidth", value); + _preferences?.setDouble("layersColumnWidth", value); - bool get autoScrollMusic => _preferences.getBool('autoScrollMusic') ?? true; + bool get autoScrollMusic => _preferences?.getBool('autoScrollMusic') ?? true; set autoScrollMusic(bool value) { - _preferences.setBool("autoScrollMusic", value); + _preferences?.setBool("autoScrollMusic", value); } - bool get autoSortMusic => _preferences.getBool('autoSortMusic') ?? true; + bool get autoSortMusic => _preferences?.getBool('autoSortMusic') ?? true; set autoSortMusic(bool value) { - _preferences.setBool("autoSortMusic", value); + _preferences?.setBool("autoSortMusic", value); } bool get autoZoomAlignMusic => - _preferences.getBool('autoZoomAlignMusic') ?? true; + _preferences?.getBool('autoZoomAlignMusic') ?? true; set autoZoomAlignMusic(bool value) { - _preferences.setBool("autoZoomAlignMusic", value); + _preferences?.setBool("autoZoomAlignMusic", value); } - double get musicScale => _preferences.getDouble('musicScale'); - set musicScale(double value) => _preferences.setDouble("musicScale", value); + double get musicScale => _preferences?.getDouble('musicScale') ?? 1.0; + set musicScale(double value) => _preferences?.setDouble("musicScale", value); - bool get alignMusic => _preferences.getBool('alignMusic') ?? true; + bool get alignMusic => _preferences?.getBool('alignMusic') ?? true; set alignMusic(bool value) { - _preferences.setBool("alignMusic", value); + _preferences?.setBool("alignMusic", value); } - bool get partAlignMusic => _preferences.getBool('partAlignMusic') ?? false; + bool get partAlignMusic => _preferences?.getBool('partAlignMusic') ?? false; set partAlignMusic(bool value) { - _preferences.setBool("partAlignMusic", value); + _preferences?.setBool("partAlignMusic", value); } RenderingMode get renderMode => RenderingMode.values.firstWhere( - (m) => m.toString().endsWith(_preferences.getString('renderMode')), + (m) => m + .toString() + .endsWith(_preferences?.getString('renderMode') ?? 'no render mode'), orElse: () => RenderingMode.notation); - set renderMode(RenderingMode value) => _preferences.setString( + set renderMode(RenderingMode value) => _preferences?.setString( "musicRenderingType", value.toString().split('.').last); - bool get keyboard3DTouch => _preferences.getBool('keyboard3DTouch') ?? false; + bool get keyboard3DTouch => _preferences?.getBool('keyboard3DTouch') ?? false; set keyboard3DTouch(bool value) { - _preferences.setBool("keyboard3DTouch", value); + _preferences?.setBool("keyboard3DTouch", value); } - bool get showBeatsBadges => _preferences.getBool('showBeatsBadges') ?? false; + bool get showBeatsBadges => _preferences?.getBool('showBeatsBadges') ?? false; set showBeatsBadges(bool value) { - _preferences.setBool("showBeatsBadges", value); + _preferences?.setBool("showBeatsBadges", value); } double get keyboardHalfStepWidth => - _preferences.getDouble('keyboardHalfStepWidth') ?? 35.0; + _preferences?.getDouble('keyboardHalfStepWidth') ?? 35.0; set keyboardHalfStepWidth(double value) => - _preferences.setDouble("keyboardHalfStepWidth", value); + _preferences?.setDouble("keyboardHalfStepWidth", value); bool get enableUniverse => true; //_preferences?.getBool('enableUniverse') ?? false; set enableUniverse(bool value) { - _preferences.setBool("enableUniverse", value); + _preferences?.setBool("enableUniverse", value); } bool get enableApollo => MyPlatform.isIOS && enableUniverse && - (_preferences.getBool('enableApollo') ?? false); + (_preferences?.getBool('enableApollo') ?? false); set enableApollo(bool value) { - _preferences.setBool("enableApollo", value); + _preferences?.setBool("enableApollo", value); } bool get showWebDownloadLinks => MyPlatform.isWeb && - (_preferences.getBool('showWebDownloadLinks') ?? MyPlatform.isWeb); + (_preferences?.getBool('showWebDownloadLinks') ?? MyPlatform.isWeb); set showWebDownloadLinks(bool value) { - _preferences.setBool("showWebDownloadLinks", value); + _preferences?.setBool("showWebDownloadLinks", value); } - int get systemsToRender => _preferences.getInt('systemsToRender') ?? 0; + int get systemsToRender => _preferences?.getInt('systemsToRender') ?? 0; set systemsToRender(int value) => - _preferences.setInt("systemsToRender", value); + _preferences?.setInt("systemsToRender", value); } diff --git a/lib/settings/settings_common.dart b/lib/settings/settings_common.dart index abfe6f06..94ba6c11 100644 --- a/lib/settings/settings_common.dart +++ b/lib/settings/settings_common.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_appavailability/flutter_appavailability.dart'; +import 'package:appcheck/appcheck.dart'; import '../beatscratch_plugin.dart'; import '../generated/protos/protos.dart'; @@ -21,11 +21,10 @@ const Map supportedAndroidControllerApps = { }; _launchAndroidApp(BuildContext context, String packageName) async { - AppAvailability.launchApp(packageName).then((_) { + new AppCheck().launchApp(packageName).then((_) { print("App $packageName launched!"); }).catchError((err) { ScaffoldMessenger.of(context) - // ignore: deprecated_member_use .showSnackBar(SnackBar(content: Text("App $packageName not found!"))); print(err); }); @@ -44,10 +43,14 @@ Future getApps() async { if (MyPlatform.isAndroid) { // print(await AppAvailability.checkAvailability( // "net.volcanomobile.fluidsynthmidi")); - hasVolcanoFluidSynth = - await AppAvailability.isAppEnabled("net.volcanomobile.fluidsynthmidi"); - hasMobileerMidiBTLEPairing = await AppAvailability.isAppEnabled( - "com.mobileer.example.midibtlepairing"); + hasVolcanoFluidSynth = await new AppCheck() + .checkAvailability("net.volcanomobile.fluidsynthmidi") != + null; + hasMobileerMidiBTLEPairing = await new AppCheck() + .checkAvailability("com.mobileer.example.midibtlepairing") != + null; + // await AppAvailability.isAppEnabled( + // "com.mobileer.example.midibtlepairing"); // Returns: true } diff --git a/lib/settings/settings_panel.dart b/lib/settings/settings_panel.dart index b73e5b67..a7fb91e0 100644 --- a/lib/settings/settings_panel.dart +++ b/lib/settings/settings_panel.dart @@ -469,13 +469,15 @@ class _SettingsPanelState extends State { ), ), ]; - List items = [ + List items = [ if (observedDevices.isNotEmpty) SeparatorTile(text: "Bluetooth Devices", id: "bluetooth-settings"), - ...observedDevices, + ...observedDevices.map((d) => IdentifiableWrapper(d, d.id)), SeparatorTile(text: "MIDI Devices", id: "midi-settings"), - ...midiSynthesizers, - ...midiControllers, + ...midiSynthesizers + .map((d) => IdentifiableWrapper(d, d.id)), + ...midiControllers + .map((d) => IdentifiableWrapper(d, d.id)), ...appSettings, ...features, ]; @@ -494,39 +496,41 @@ class _SettingsPanelState extends State { } final dynamic item = items[index]; Widget? tile; - if (item is MidiController) { - tile = MidiControllerTile( - appSettings: widget.appSettings, - scrollDirection: Axis.horizontal, - midiController: item, - enableColorboard: widget.enableColorboard, - setColorboardEnabled: widget.setColorboardEnabled, - sectionColor: widget.sectionColor, - toggleKeyboardConfig: widget.toggleKeyboardConfig, - toggleColorboardConfig: widget.toggleColorboardConfig, - ); - } else if (item is MidiSynthesizer) { - tile = MidiSynthTile( - scrollDirection: Axis.horizontal, - midiSynthesizer: item, - ); - } else if (item is SettingsTile || item is SeparatorTile) { + if (item is SettingsTile || item is SeparatorTile || item is Widget) { tile = item; - } else if (item is MidiDevice) { - tile = BluetoothDeviceTile( - key: ValueKey("Bluetooth-Device-${item.id}"), - device: item, - sectionColor: widget.sectionColor, - connected: connectedDeviceIds.any((id) => id == item.id), - onConnect: () { - connectedDeviceIds.add(item.id.toString()); - }, - onDisconnect: () { - connectedDeviceIds.remove(item.id.toString()); - }, - bluetoothControllerPressedNotes: - widget.bluetoothControllerPressedNotes, - ); + } else if (item is IdentifiableWrapper) { + if (item.item is MidiController) { + tile = MidiControllerTile( + appSettings: widget.appSettings, + scrollDirection: Axis.horizontal, + midiController: item.item, + enableColorboard: widget.enableColorboard, + setColorboardEnabled: widget.setColorboardEnabled, + sectionColor: widget.sectionColor, + toggleKeyboardConfig: widget.toggleKeyboardConfig, + toggleColorboardConfig: widget.toggleColorboardConfig, + ); + } else if (item.item is MidiSynthesizer) { + tile = MidiSynthTile( + scrollDirection: Axis.horizontal, + midiSynthesizer: item.item, + ); + } else if (item is MidiDevice) { + tile = BluetoothDeviceTile( + key: ValueKey("Bluetooth-Device-${item.id}"), + device: item.item, + sectionColor: widget.sectionColor, + connected: connectedDeviceIds.any((id) => id == item.id), + onConnect: () { + connectedDeviceIds.add(item.id.toString()); + }, + onDisconnect: () { + connectedDeviceIds.remove(item.id.toString()); + }, + bluetoothControllerPressedNotes: + widget.bluetoothControllerPressedNotes, + ); + } } tile = Padding(padding: EdgeInsets.all(5), child: tile); return SizeFadeTransition( @@ -707,3 +711,9 @@ showColors(BuildContext context, Color sectionColor) { abstract class Identifiable { String get id; } + +class IdentifiableWrapper extends Identifiable { + final T item; + final String id; + IdentifiableWrapper(this.item, this.id); +} diff --git a/lib/storage/score_picker.dart b/lib/storage/score_picker.dart index aff290a5..1461db74 100644 --- a/lib/storage/score_picker.dart +++ b/lib/storage/score_picker.dart @@ -46,7 +46,7 @@ extension ShowScoreNameEntry on ScorePickerMode { class ScorePicker extends StatefulWidget { final Axis scrollDirection; final Color sectionColor; - final Function(VoidCallback) setState; + final Function(VoidCallback)? setState; final VoidCallback close; final VoidCallback switchToUniverse; final ScorePickerMode mode; @@ -60,22 +60,22 @@ class ScorePicker extends StatefulWidget { final BSMethod refreshUniverseData; const ScorePicker( - {Key key, + {Key? key, this.scrollDirection = Axis.horizontal, - this.sectionColor, + required this.sectionColor, this.setState, - this.close, - this.mode, - this.openedScore, - this.scoreManager, - this.universeManager, - this.appSettings, - this.requestKeyboardFocused, - this.requestMode, - this.width, - this.height, - this.refreshUniverseData, - this.switchToUniverse}) + required this.close, + required this.mode, + required this.openedScore, + required this.scoreManager, + required this.universeManager, + required this.appSettings, + required this.requestKeyboardFocused, + required this.requestMode, + required this.width, + required this.height, + required this.refreshUniverseData, + required this.switchToUniverse}) : super(key: key); @override @@ -91,12 +91,13 @@ class ScorePickerState extends State { FocusNode nameFocus = FocusNode(); ScoreManager get scoreManager => widget.scoreManager; - ScorePickerMode previousMode; - String deletingScoreName; - String overwritingScoreName; + ScorePickerMode? previousMode; + String? deletingScoreName; + String? overwritingScoreName; BSMethod universeAnimation = BSMethod(); - bool get wasShowingScoreNameEntry => previousMode.showScoreNameEntry ?? false; + bool get wasShowingScoreNameEntry => + previousMode?.showScoreNameEntry ?? false; @override initState() { @@ -179,7 +180,7 @@ class ScorePickerState extends State { text: '', style: detailTextStyle, ); //ing extraDetailText = ""; - IconData icon; + late IconData icon; switch (widget.mode) { case ScorePickerMode.open: operationText = "Open"; @@ -216,7 +217,7 @@ class ScorePickerState extends State { } bool detailsTextInColumn = true; //MediaQuery.of(context).size.width < 500; bool showDetailsText = detailsTextInColumn && - extraDetailText.text.isNotEmpty && + (extraDetailText.text?.isNotEmpty ?? false) && !hideDetailsText; return Column( @@ -386,7 +387,7 @@ class ScorePickerState extends State { ))), AnimatedContainer( height: showDetailsText - ? 0 == extraDetailText.children?.length ?? 0 + ? 0 == (extraDetailText.children?.length ?? 0) ? 32 : 48 : 0, @@ -618,15 +619,15 @@ class ScorePickerState extends State { return widget.universeManager.cachedUniverseData; } else { return scoreManager.scoreFiles.map((scoreFile) { - Future loadScore() async { - try { - final data = await File(scoreFile.path).readAsBytes(); + // Future loadScore() async { + // try { + // final data = await File(scoreFile.path).readAsBytes(); - return Score.fromBuffer(data); - } catch (e) { - return Future.value(defaultScore()); - } - } + // return Score.fromBuffer(data); + // } catch (e) { + // return Future.value(defaultScore()); + // } + // } return ScoreFuture(filePath: scoreFile.path); }).toList(); @@ -645,11 +646,14 @@ class ScorePickerState extends State { // Called, as needed, to build list item widgets. // List items are only built when they're scrolled into view. itemBuilder: (context, animation, section, index) { - ScoreFuture scoreFuture; + late final ScoreFuture? scoreFuture; if (index < scores.length) { scoreFuture = scores[index]; } - File scoreFile = scoreFuture.file; + final scoreFile = scoreFuture?.file; + if (scoreFuture == null || scoreFile == null) { + return SizedBox(); + } Widget tile = ScorePickerPreview( sectionColor: widget.sectionColor, @@ -670,10 +674,10 @@ class ScorePickerState extends State { scoreManager.currentScoreName = ScoreManager.UNIVERSE_SCORE; } - scoreFuture.loadScore(scoreManager).then((value) { + scoreFuture?.loadScore(scoreManager).then((value) { widget.scoreManager.doOpenScore(value); widget.universeManager.currentUniverseScore = - scoreFuture.identity; + scoreFuture!.identity; widget.scoreManager.saveCurrentScore(value); }); break; diff --git a/lib/storage/score_picker_preview.dart b/lib/storage/score_picker_preview.dart index 3bb3a832..99d43491 100644 --- a/lib/storage/score_picker_preview.dart +++ b/lib/storage/score_picker_preview.dart @@ -18,9 +18,9 @@ import 'universe_manager.dart'; import 'url_conversions.dart'; class ScoreFuture { - final String filePath, scoreUrl, title, author, commentUrl, fullName; - int voteCount; - bool likes; + final String? filePath, scoreUrl, title, author, commentUrl, fullName; + int? voteCount; + bool? likes; ScoreFuture({ this.filePath, @@ -55,9 +55,11 @@ class ScoreFuture { }; String get identity => filePath ?? "//universe-score://$scoreUrl"; - FileSystemEntity get file { + File? get file { try { - return File(filePath); + if (filePath == null) return null; + + return File(filePath!); } catch (e) { print("Error loading score from file: $e"); } @@ -70,6 +72,10 @@ class ScoreFuture { Future loadScoreFromFile() async { try { + final file = this.file; + if (file == null) { + return Future.value(defaultScore()); + } final data = await File(file.path).readAsBytes(); return Score.fromBuffer(data); @@ -79,16 +85,19 @@ class ScoreFuture { } Future loadScoreFromUniverse(ScoreManager scoreManager) async { - String scoreUrl = this.scoreUrl; + String scoreUrl = this.scoreUrl!; scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#score='), ''); scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#/score/'), ''); scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#/s/'), ''); try { final score = scoreFromUrlHashValue(scoreUrl); - return score..name = title; + if (score == null) { + return Future.value(defaultScore()); + } + return score..name = title!; } catch (e) { try { - return scoreManager.loadPastebinScore(scoreUrl, titleOverride: title); + return scoreManager.loadPastebinScore(scoreUrl, titleOverride: title!); } catch (e) { return Future.value(defaultScore()); } @@ -99,36 +108,36 @@ class ScoreFuture { class ScorePickerPreview extends StatefulWidget { final Color sectionColor; final ScoreFuture scoreFuture; - final VoidCallback deleteScore; - final VoidCallback overwriteScore; + final VoidCallback? deleteScore; + final VoidCallback? overwriteScore; final ScoreManager scoreManager; final UniverseManager universeManager; final AppSettings appSettings; - final VoidCallback onClickScore; + final VoidCallback? onClickScore; final int scoreKey; - final String deletingScoreName; - final String overwritingScoreName; - final VoidCallback cancelDelete; - final VoidCallback cancelOverwrite; + final String? deletingScoreName; + final String? overwritingScoreName; + final VoidCallback? cancelDelete; + final VoidCallback? cancelOverwrite; final double width, height; const ScorePickerPreview( - {Key key, - this.sectionColor, - this.scoreFuture, - this.deleteScore, - this.overwriteScore, - this.scoreManager, - this.appSettings, + {Key? key, + required this.sectionColor, + required this.scoreFuture, + required this.deleteScore, + required this.overwriteScore, + required this.scoreManager, + required this.appSettings, this.deletingScoreName, this.overwritingScoreName, - this.scoreKey, - this.cancelDelete, - this.cancelOverwrite, - this.universeManager, + required this.scoreKey, + required this.cancelDelete, + required this.cancelOverwrite, + required this.universeManager, this.onClickScore, - this.width, - this.height}) + required this.width, + required this.height}) : super(key: key); @override @@ -136,14 +145,14 @@ class ScorePickerPreview extends StatefulWidget { } class _ScorePickerPreviewState extends State { - bool _confirmingDelete; - bool _confirmingOverwrite; - int _lastScoreKey; - bool disposed; + late bool _confirmingDelete; + late bool _confirmingOverwrite; + late int _lastScoreKey; + late bool disposed; - Score _previewScore; - ScrollController scrollController; - BSMethod notifyUpdate; + late Score? _previewScore; + late ScrollController scrollController; + late BSMethod notifyUpdate; @override initState() { @@ -163,7 +172,7 @@ class _ScorePickerPreviewState extends State { } String get unloadedScoreName => - widget.scoreFuture.title ?? widget.scoreFuture.file.scoreName ?? ""; + widget.scoreFuture.title ?? widget.scoreFuture.file?.scoreName ?? ""; bool get isUniverse => widget.scoreFuture.voteCount != null; @override @@ -206,7 +215,7 @@ class _ScorePickerPreviewState extends State { backgroundColor = musicBackgroundColor; } - Score previewScore = _previewScore; + Score previewScore = _previewScore ?? defaultScore(); // if (previewScore == null) { // previewScore = defaultScore(); // } @@ -216,7 +225,7 @@ class _ScorePickerPreviewState extends State { final actualScoreName = isUniverse ? unloadedScoreName : _previewScore != null - ? _previewScore.name + ? _previewScore!.name : unloadedScoreName; double previewScale = @@ -351,7 +360,7 @@ class _ScorePickerPreviewState extends State { onPressed: () { if (!disposed) { setState(() { - widget.deleteScore(); + widget.deleteScore?.call(); }); } }, @@ -364,7 +373,7 @@ class _ScorePickerPreviewState extends State { if (!disposed) { setState(() { _confirmingDelete = false; - widget.cancelDelete(); + widget.cancelDelete?.call(); }); } }, @@ -397,7 +406,7 @@ class _ScorePickerPreviewState extends State { onPressed: () { if (!disposed) { setState(() { - widget.overwriteScore(); + widget.overwriteScore?.call(); }); } }, @@ -410,7 +419,7 @@ class _ScorePickerPreviewState extends State { if (!disposed) { setState(() { _confirmingOverwrite = false; - widget.cancelOverwrite(); + widget.cancelOverwrite?.call(); }); } }, @@ -472,18 +481,20 @@ class _ScorePickerPreviewState extends State { onPressed: widget.universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = widget.scoreFuture.likes; + bool? oldValue = widget.scoreFuture.likes; setState(() { if (oldValue == true) { widget.scoreFuture.likes = null; - widget.scoreFuture.voteCount -= 1; + widget.scoreFuture.voteCount = + widget.scoreFuture.voteCount! - 1; } else { widget.scoreFuture.likes = true; - widget.scoreFuture.voteCount += - oldValue == null ? 1 : 2; + widget.scoreFuture.voteCount = + widget.scoreFuture.voteCount! + + (oldValue == null ? 1 : 2); } widget.universeManager.vote( - widget.scoreFuture.fullName, + widget.scoreFuture.fullName!, widget.scoreFuture.likes); }); } @@ -510,18 +521,20 @@ class _ScorePickerPreviewState extends State { onPressed: widget.universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = widget.scoreFuture.likes; + bool? oldValue = widget.scoreFuture.likes; setState(() { if (oldValue == false) { widget.scoreFuture.likes = null; - widget.scoreFuture.voteCount += 1; + widget.scoreFuture.voteCount = + widget.scoreFuture.voteCount! + 1; } else { widget.scoreFuture.likes = false; - widget.scoreFuture.voteCount -= - oldValue == null ? 1 : 2; + widget.scoreFuture.voteCount = + widget.scoreFuture.voteCount! - + (oldValue == null ? 1 : 2); } widget.universeManager.vote( - widget.scoreFuture.fullName, + widget.scoreFuture.fullName!, widget.scoreFuture.likes); }); } @@ -538,11 +551,11 @@ class _ScorePickerPreviewState extends State { onPressed: () { if (widget.appSettings.enableApollo) { launchURL( - widget.scoreFuture.commentUrl + widget.scoreFuture.commentUrl! .replaceAll("https://", "apollo://"), forceSafariVC: false); } else { - launchURL(widget.scoreFuture.commentUrl, + launchURL(widget.scoreFuture.commentUrl!, forceSafariVC: false); } }, diff --git a/lib/storage/universe_manager.dart b/lib/storage/universe_manager.dart index b015011a..63f6eb95 100644 --- a/lib/storage/universe_manager.dart +++ b/lib/storage/universe_manager.dart @@ -2,6 +2,7 @@ import 'package:beatscratch_flutter_redux/messages/messages.dart'; import 'package:beatscratch_flutter_redux/storage/score_manager.dart'; import 'package:beatscratch_flutter_redux/storage/score_picker_preview.dart'; import 'package:beatscratch_flutter_redux/util/util.dart'; +import 'package:collection/collection.dart'; import 'dart:convert'; import 'dart:io'; @@ -18,12 +19,12 @@ import 'url_conversions.dart'; class UniverseManager { static final REDDIT_CLIENT_ID = 'rSA9vlCRCznMCw'; static final REDDIT_REDIRECT_URI = 'https://beatscratch.io/app'; - Function(Score) doOpenScore; - Directory scoresDirectory; - SharedPreferences _prefs; - ScoreManager scoreManager; - MessagesUI messagesUI; - BSMethod refreshUniverseData; + late Function(Score) doOpenScore; + late Directory scoresDirectory; + late SharedPreferences _prefs; + late ScoreManager scoreManager; + late MessagesUI messagesUI; + late BSMethod refreshUniverseData; UniverseManager() { _initialize(); @@ -37,10 +38,11 @@ class UniverseManager { set currentUniverseScore(String v) => _prefs.setString("currentUniverseScore", v); - ScoreFuture get currentUniverseScoreFuture => currentUniverseScore == '' + ScoreFuture? get currentUniverseScoreFuture => currentUniverseScore == '' ? null - : cachedUniverseData.firstWhere((d) => d.identity == currentUniverseScore, - orElse: () => null); + : cachedUniverseData.firstWhereOrNull( + (d) => d.identity == currentUniverseScore, + ); String get redditRefreshToken => _prefs.getString('redditRefreshToken') ?? ""; set redditRefreshToken(String value) => @@ -102,8 +104,8 @@ class UniverseManager { bool tryAuthentication(String authUrl) { final uri = Uri.parse(authUrl); - String state = uri.queryParameters["state"]; - String code = uri.queryParameters["code"]; + String? state = uri.queryParameters["state"]; + String? code = uri.queryParameters["code"]; if (code != null) { if (state != _authState) { messagesUI.sendMessage( @@ -162,10 +164,11 @@ class UniverseManager { redditAccessToken = ""; redditUsername = ""; redditRefreshToken = ""; - cachedUniverseData = - cachedUniverseData.map((sf) => ScoreFuture.fromJson(sf.toJson() + cachedUniverseData = cachedUniverseData + .map((sf) => ScoreFuture.fromJson(sf.toJson() ..remove("likes") - ..putIfAbsent("likes", () => null))); + ..putIfAbsent("likes", () => null))) + .toList(); refreshAccessToken(); } @@ -245,17 +248,25 @@ class UniverseManager { } Future> loadUniverseData() async { - http.Response response = await http - .get(Uri.parse('https://oauth.reddit.com/r/BeatScratch/hot'), - headers: authenticatedRedditRequestHeaders) - .onError((error, stackTrace) { - print(error); + http.Response response = await http.get( + Uri.parse('https://oauth.reddit.com/r/BeatScratch/hot'), + headers: authenticatedRedditRequestHeaders); + // .onError((error, stackTrace) { + // print(error); + // messagesUI.sendMessage( + // message: "Error loading data from Reddit!", + // isError: true, + // andSetState: true); + // // return null; + // return Response(body, statusCode) + // }); + if (response.statusCode != 200 && response.statusCode != 401) { messagesUI.sendMessage( message: "Error loading data from Reddit!", isError: true, andSetState: true); - return null; - }); + return Future.value([]); + } if (response.statusCode == 401) { await refreshAccessToken(); return await loadUniverseData(); @@ -309,7 +320,7 @@ class UniverseManager { } } - vote(String fullName, bool likes, {bool andReauth = true}) async { + vote(String fullName, bool? likes, {bool andReauth = true}) async { http .post(Uri.parse('https://oauth.reddit.com/api/vote'), body: { @@ -367,7 +378,7 @@ class UniverseManager { icon: Icon(FontAwesomeIcons.atom, color: chromaticSteps[0]), message: "Generating short URL via https://paste.ee...", andSetState: true); - String scoreUrl = await score.convertToShortUrl(); + String? scoreUrl = await score.convertToShortUrl(); messagesUI.sendMessage( icon: Icon(FontAwesomeIcons.atom, color: chromaticSteps[0]), message: "Uploading to the Universe...", @@ -399,9 +410,9 @@ class UniverseManager { tryToSelectScore(int retries) { Future.delayed(Duration(seconds: 2), () { refreshUniverseData(); - ScoreFuture scoreFuture = cachedUniverseData.firstWhere( - (it) => it.scoreUrl == scoreUrl, - orElse: () => null); + final scoreFuture = cachedUniverseData + .firstWhereOrNull((it) => it.scoreUrl == scoreUrl); + if (scoreFuture == null) return; messagesUI.setAppState(() { currentUniverseScore = scoreFuture.identity; }); diff --git a/lib/storage/url_conversions.dart b/lib/storage/url_conversions.dart index 10284a75..4097429f 100644 --- a/lib/storage/url_conversions.dart +++ b/lib/storage/url_conversions.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:typed_data'; import 'package:archive/archive.dart'; import 'package:base_x/base_x.dart'; @@ -20,7 +21,7 @@ extension URLConversions on Score { return urlString; } - Future convertToShortUrl() async { + Future convertToShortUrl() async { try { http.Response response = await http.post( Uri.parse('https://api.paste.ee/v1/pastes'), @@ -47,14 +48,14 @@ extension URLConversions on Score { final data = writeToBuffer(); final bz2Data = BZip2Encoder().encode(data); final dataToConvert = (data.length <= bz2Data.length) ? data : bz2Data; - final dataString = _base58.encode(dataToConvert); + final dataString = _base58.encode(Uint8List.fromList(dataToConvert)); return dataString; } } -Score scoreFromUrlHashValue(String urlString) { +Score? scoreFromUrlHashValue(String urlString) { final dataBytes = _base58.decode(urlString); - Score score; + Score? score; try { score = Score.fromBuffer(dataBytes); } catch (any) { diff --git a/lib/universe_view/universe_icon.dart b/lib/universe_view/universe_icon.dart index d561da88..5ebddc4a 100644 --- a/lib/universe_view/universe_icon.dart +++ b/lib/universe_view/universe_icon.dart @@ -1,8 +1,9 @@ import 'package:beatscratch_flutter_redux/ui_models.dart'; import 'package:beatscratch_flutter_redux/util/bs_methods.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_icons/flutter_icons.dart'; +// import 'package:flutter_icons/flutter_icons.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'dart:math'; import '../colors.dart'; @@ -10,10 +11,10 @@ import '../colors.dart'; class UniverseIcon extends StatefulWidget { final Color sectionColor; final InteractionMode interactionMode; - final BSMethod animateIcon; + final BSMethod? animateIcon; const UniverseIcon( - {Key key, + {Key? key, this.sectionColor = Colors.white, this.interactionMode = InteractionMode.view, this.animateIcon}) @@ -25,10 +26,10 @@ class UniverseIcon extends StatefulWidget { class _UniverseIconState extends State with TickerProviderStateMixin { - AnimationController orbitRotationController; - Animation orbitRotation; - AnimationController atomRotationController; - Animation atomRotation; + late AnimationController orbitRotationController; + late Animation orbitRotation; + late AnimationController atomRotationController; + late Animation atomRotation; @override initState() { super.initState(); @@ -51,7 +52,7 @@ class _UniverseIconState extends State end: -2 * pi, ).animate(atomRotationController); - widget.animateIcon.addListener(() { + widget.animateIcon?.addListener(() { if (widget.interactionMode != InteractionMode.universe) { orbitRotationController.forward().then( (_) => (!disposed) ? orbitRotationController.reverse() : null); @@ -96,7 +97,7 @@ class _UniverseIconState extends State alignment: Alignment.center, child: Transform.scale( scale: 1.4, - child: Icon(MaterialCommunityIcons.orbit, + child: Icon(MdiIcons.orbit, color: ((widget.interactionMode == InteractionMode.universe) ? widget.sectionColor diff --git a/lib/universe_view/universe_upload_dialog.dart b/lib/universe_view/universe_upload_dialog.dart index b3c3e826..f897b347 100644 --- a/lib/universe_view/universe_upload_dialog.dart +++ b/lib/universe_view/universe_upload_dialog.dart @@ -1,4 +1,3 @@ - import '../music_preview/score_preview.dart'; import 'package:flutter/material.dart'; @@ -83,7 +82,10 @@ class UniverseUploadWidget extends StatefulWidget { final BSMethod onDoDuplicate; const UniverseUploadWidget( - {Key key, this.score, this.universeManager, this.onDoDuplicate}) + {Key? key, + required this.score, + required this.universeManager, + required this.onDoDuplicate}) : super(key: key); @override @@ -91,7 +93,7 @@ class UniverseUploadWidget extends StatefulWidget { } class _UniverseUploadWidgetState extends State { - bool didFindDuplicate; + bool? didFindDuplicate; @override void initState() { super.initState(); diff --git a/lib/universe_view/universe_view_ui.dart b/lib/universe_view/universe_view_ui.dart index a8b04862..f6f4001a 100644 --- a/lib/universe_view/universe_view_ui.dart +++ b/lib/universe_view/universe_view_ui.dart @@ -3,29 +3,26 @@ import 'package:beatscratch_flutter_redux/messages/messages_ui.dart'; import 'package:beatscratch_flutter_redux/storage/universe_manager.dart'; import 'package:beatscratch_flutter_redux/util/bs_methods.dart'; import 'package:beatscratch_flutter_redux/widget/my_buttons.dart'; - -import '../widget/my_popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'dart:async'; -import 'package:webview_flutter/webview_flutter.dart'; import '../colors.dart'; import '../ui_models.dart'; import '../util/util.dart'; -import 'universe_icon.dart'; import '../widget/my_platform.dart'; +import '../widget/my_popup_menu.dart'; +import 'universe_icon.dart'; class UniverseViewUI { - BSMethod refreshUniverseData; - VoidCallback switchToLocalScores; - MessagesUI messagesUI; + BSMethod? refreshUniverseData; + VoidCallback? switchToLocalScores; + MessagesUI? messagesUI; bool visible = true; final UniverseManager universeManager; final Function(VoidCallback) setAppState; bool signingIn = false; - final Completer _webViewController = - Completer(); + // final Completer _webViewController = + // Completer(); final TextEditingController _usernameController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); @@ -85,7 +82,7 @@ class UniverseViewUI { Transform.translate( offset: Offset(0, 0), child: MyFlatButton( - onPressed: refreshUniverseData, + onPressed: () => refreshUniverseData?.call(), padding: EdgeInsets.all(5), lightHighlight: true, child: Transform.translate( @@ -186,7 +183,7 @@ class UniverseViewUI { case "signOut": setAppState(() { universeManager.signOut(); - messagesUI.sendMessage( + messagesUI?.sendMessage( message: "Signed out of Reddit"); }); break; diff --git a/lib/util/bs_methods.dart b/lib/util/bs_methods.dart index bd4bed4a..bb2a57c4 100644 --- a/lib/util/bs_methods.dart +++ b/lib/util/bs_methods.dart @@ -7,5 +7,5 @@ class BSMethod extends ChangeNotifier { class BSValueMethod extends ValueNotifier { BSValueMethod(value) : super(value); - call(value) => this.value = value; + void call(value) => this.value = value; } diff --git a/lib/util/music_theory.dart b/lib/util/music_theory.dart index 48be725e..54c696c3 100644 --- a/lib/util/music_theory.dart +++ b/lib/util/music_theory.dart @@ -337,7 +337,7 @@ extension SectionTheory on Section { double get realBeatCount => harmony.realBeatCount; int get beatCount => harmony.beatCount; - MelodyReference? referenceTo(Melody melody) => + MelodyReference referenceTo(Melody melody) => melodies.firstWhere((element) => element.melodyId == melody.id, orElse: () => _defaultMelodyReference(melody)); diff --git a/lib/util/ui_utils.dart b/lib/util/ui_utils.dart index 928a0fac..5ca64d11 100644 --- a/lib/util/ui_utils.dart +++ b/lib/util/ui_utils.dart @@ -16,7 +16,7 @@ launchURL( bool universalLinksOnly = false, Map headers = const {}, Brightness statusBarBrightness = Brightness.dark, - String webOnlyWindowName = '', + String? webOnlyWindowName, }) async { if (await canLaunchUrl(Uri.parse(url))) { await launchURL( diff --git a/lib/widget/colorboard.dart b/lib/widget/colorboard.dart index 4db59167..e93adc6d 100644 --- a/lib/widget/colorboard.dart +++ b/lib/widget/colorboard.dart @@ -2,7 +2,6 @@ import '../drawing/canvas_tone_drawer.dart'; import '../drawing/color_guide.dart'; import 'package:flutter/material.dart'; import '../beatscratch_plugin.dart'; -import 'package:aeyrium_sensor/aeyrium_sensor.dart'; import 'dart:async'; import 'dart:math'; import '../generated/protos/music.pb.dart'; @@ -29,16 +28,16 @@ class Colorboard extends StatefulWidget { final double leftMargin; Colorboard({ - Key key, - this.height, - this.showConfiguration, - this.hideConfiguration, - this.sectionColor, - this.part, - this.pressedNotesNotifier, - this.distanceFromBottom, - this.width, - this.leftMargin, + Key? key, + required this.height, + required this.showConfiguration, + required this.hideConfiguration, + required this.sectionColor, + required this.part, + required this.pressedNotesNotifier, + required this.distanceFromBottom, + required this.width, + required this.leftMargin, }) : super(key: key); @override @@ -51,8 +50,8 @@ class _ColorboardState extends State with TickerProviderStateMixin { bool useOrientation = true; List> _streamSubscriptions = >[]; - ValueNotifier scrollPositionNotifier; - ValueNotifier chordNotifier; + late ValueNotifier scrollPositionNotifier; + late ValueNotifier chordNotifier; bool reverseScrolling = false; ScrollingMode scrollingMode = ScrollingMode.sideScroll; @@ -72,19 +71,19 @@ class _ColorboardState extends State with TickerProviderStateMixin { _scaleAnimationControllers.clear(); AnimationController scaleAnimationController = animationController(); _scaleAnimationControllers.add(scaleAnimationController); - Animation animation; + late Animation animation; animation = Tween(begin: _halfStepWidthInPx, end: value) .animate(scaleAnimationController) - ..addListener(() { - setState(() { - _halfStepWidthInPx = animation.value; - }); - }); + ..addListener(() { + setState(() { + _halfStepWidthInPx = animation.value; + }); + }); scaleAnimationController.forward(); } - AnimationController orientationAnimationController; - Animation orientationAnimation; + late AnimationController orientationAnimationController; + late Animation orientationAnimation; int highestPitch = CanvasToneDrawer.TOP; int lowestPitch = CanvasToneDrawer.BOTTOM; bool showScrollHint = true; @@ -102,51 +101,51 @@ class _ColorboardState extends State with TickerProviderStateMixin { scrollPositionNotifier = ValueNotifier(0); chordNotifier = ValueNotifier(widget.chord); if (MyPlatform.isMobile) { - try { - _streamSubscriptions.add(AeyriumSensor.sensorEvents.listen((event) { - if (scrollingMode != ScrollingMode.sideScroll) { - print("Sensor event: $event"); - double normalizedPitch; - switch (scrollingMode) { - case ScrollingMode.pitch: - var absoluteScrollPosition = event.pitch; - if (absoluteScrollPosition < 0) { - absoluteScrollPosition = -absoluteScrollPosition; - } - normalizedPitch = max( - 0.0, min(1.0, (1.58 - absoluteScrollPosition * 1.2) / 1.5)); - break; - case ScrollingMode.roll: -// var maxRoll = -1.45; // All the way to the right -// var minRoll = 1.45; // All the way to the left - normalizedPitch = (1.45 - event.roll) / 2.9; - break; - case ScrollingMode.sideScroll: - break; - } +// try { +// _streamSubscriptions.add(AeyriumSensor.sensorEvents.listen((event) { +// if (scrollingMode != ScrollingMode.sideScroll) { +// print("Sensor event: $event"); +// double normalizedPitch; +// switch (scrollingMode) { +// case ScrollingMode.pitch: +// var absoluteScrollPosition = event.pitch; +// if (absoluteScrollPosition < 0) { +// absoluteScrollPosition = -absoluteScrollPosition; +// } +// normalizedPitch = max( +// 0.0, min(1.0, (1.58 - absoluteScrollPosition * 1.2) / 1.5)); +// break; +// case ScrollingMode.roll: +// // var maxRoll = -1.45; // All the way to the right +// // var minRoll = 1.45; // All the way to the left +// normalizedPitch = (1.45 - event.roll) / 2.9; +// break; +// case ScrollingMode.sideScroll: +// break; +// } - double newScrollPositionValue = max(0.0, min(1.0, normalizedPitch)); - if (newScrollPositionValue.isFinite && - !newScrollPositionValue.isNaN) { - Animation animation; - animation = Tween( - begin: scrollPositionNotifier.value, - end: newScrollPositionValue) - .animate(orientationAnimationController) - ..addListener(() { - scrollPositionNotifier.value = animation.value; -// setState(() {}); - }); - orientationAnimationController.forward( - from: scrollPositionNotifier.value); -// scrollPositionNotifier.value = newScrollPositionValue; - } - } - })); - } catch (MissingPluginException) { - // It's fine for this to not work on desktop - scrollingMode = ScrollingMode.sideScroll; - } +// double newScrollPositionValue = max(0.0, min(1.0, normalizedPitch)); +// if (newScrollPositionValue.isFinite && +// !newScrollPositionValue.isNaN) { +// Animation animation; +// animation = Tween( +// begin: scrollPositionNotifier.value, +// end: newScrollPositionValue) +// .animate(orientationAnimationController) +// ..addListener(() { +// scrollPositionNotifier.value = animation.value; +// // setState(() {}); +// }); +// orientationAnimationController.forward( +// from: scrollPositionNotifier.value); +// // scrollPositionNotifier.value = newScrollPositionValue; +// } +// } +// })); +// } catch (MissingPluginException) { +// // It's fine for this to not work on desktop +// scrollingMode = ScrollingMode.sideScroll; +// } } } @@ -183,7 +182,7 @@ class _ColorboardState extends State with TickerProviderStateMixin { scrollDirection: Axis.horizontal, slivers: [ CustomSliverToBoxAdapter( - setVisibleRect: (rect) { + (rect) { _visibleRect = rect; _visibleRect = Rect.fromLTRB(rect.left, rect.top, rect.right, rect.bottom - touchScrollAreaHeight); @@ -290,7 +289,7 @@ class _ColorboardState extends State with TickerProviderStateMixin { // print("dy=$dy; maxDy=$maxDy; velocity ratio=$velocityRatio"); int velocity = min(127, max(0, (velocityRatio * 127).toInt())); - int oldTone = _pointerIdsToTones[event.pointer]; + int oldTone = _pointerIdsToTones[event.pointer]!; if (tone != oldTone) { print("moving tone $oldTone to $tone"); try { @@ -305,7 +304,9 @@ class _ColorboardState extends State with TickerProviderStateMixin { } }, onPointerUp: (event) { - int tone = _pointerIdsToTones.remove(event.pointer); + int? tone = _pointerIdsToTones.remove(event.pointer); + if (tone == null) return; + widget.pressedNotesNotifier.value = _pointerIdsToTones.values.toSet(); try { @@ -313,7 +314,9 @@ class _ColorboardState extends State with TickerProviderStateMixin { } catch (t) {} }, onPointerCancel: (event) { - int tone = _pointerIdsToTones.remove(event.pointer); + int? tone = _pointerIdsToTones.remove(event.pointer); + if (tone == null) return; + widget.pressedNotesNotifier.value = _pointerIdsToTones.values.toSet(); try { @@ -487,13 +490,13 @@ class _ColorboardPainter extends CustomPainter { final ValueNotifier chordNotifier; _ColorboardPainter( - {this.chordNotifier, - this.lowestPitch, - this.highestPitch, - this.pressedNotesNotifier, - this.scrollPositionNotifier, - this.halfStepsOnScreen, - this.visibleRect}) + {required this.chordNotifier, + required this.lowestPitch, + required this.highestPitch, + required this.pressedNotesNotifier, + required this.scrollPositionNotifier, + required this.halfStepsOnScreen, + required this.visibleRect}) : super( repaint: Listenable.merge( [scrollPositionNotifier, pressedNotesNotifier, chordNotifier])); diff --git a/lib/widget/incrementable_value.dart b/lib/widget/incrementable_value.dart index 313aa79f..dd1f758a 100644 --- a/lib/widget/incrementable_value.dart +++ b/lib/widget/incrementable_value.dart @@ -12,29 +12,29 @@ import 'my_buttons.dart'; import '../ui_models.dart'; class IncrementableValue extends StatefulWidget { - final Function onIncrement; - final Function onDecrement; - final Function onBigIncrement; - final Function onBigDecrement; - final String value; - final TextStyle textStyle; + final Function? onIncrement; + final Function? onDecrement; + final Function? onBigIncrement; + final Function? onBigDecrement; + final String? value; + final TextStyle? textStyle; final double valueWidth; - final VoidCallback onValuePressed; - final Widget child; + final VoidCallback? onValuePressed; + final Widget? child; final double incrementDistance; final double incrementTimingDifferenceMs; final bool collapsing; - final IconData incrementIcon; - final IconData decrementIcon; - final IconData bigIncrementIcon; - final IconData bigDecrementIcon; - final VoidCallback onPointerUpCallback; - final VoidCallback onPointerDownCallback; + final IconData? incrementIcon; + final IconData? decrementIcon; + final IconData? bigIncrementIcon; + final IconData? bigDecrementIcon; + final VoidCallback? onPointerUpCallback; + final VoidCallback? onPointerDownCallback; final bool musicActionButtonStyle; - final Color musicActionButtonColor; + final Color? musicActionButtonColor; const IncrementableValue({ - Key key, + Key? key, this.onIncrement, this.onDecrement, this.value, @@ -63,8 +63,8 @@ class IncrementableValue extends StatefulWidget { class _IncrementableValueState extends State { int lastTouchTimeMs = 0; - Offset incrementStartPos; - int incrementStartTimeMs; + Offset? incrementStartPos; + late int incrementStartTimeMs; static const _msDelay = 3000; // static const _delay = Duration(milliseconds: _msDelay); bool _disposed = false; @@ -92,7 +92,7 @@ class _IncrementableValueState extends State { double buttonWidth = showButtons ? 32 : 0; onPointerDown(event) { - widget.onPointerDownCallback.call(); + widget.onPointerDownCallback?.call(); incrementStartPos = event.position; incrementStartTimeMs = DateTime.now().millisecondsSinceEpoch; lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; @@ -140,12 +140,12 @@ class _IncrementableValueState extends State { incrementStartPos = event.position; incrementStartTimeMs = eventTime; // print("increment"); - widget.onIncrement(); + widget.onIncrement?.call(); } else if (isDown) { vibrate(); incrementStartPos = event.position; incrementStartTimeMs = eventTime; - widget.onDecrement(); + widget.onDecrement?.call(); } } @@ -153,7 +153,7 @@ class _IncrementableValueState extends State { onPointerUp(event) { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; incrementStartPos = null; - widget.onPointerUpCallback.call(); + widget.onPointerUpCallback?.call(); } ; @@ -225,7 +225,7 @@ class _IncrementableValueState extends State { ? () { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; - widget.onBigDecrement(); + widget.onBigDecrement?.call(); } : null, padding: EdgeInsets.zero, @@ -246,7 +246,7 @@ class _IncrementableValueState extends State { ? () { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; - widget.onDecrement(); + widget.onDecrement?.call(); } : null, padding: EdgeInsets.all(0), @@ -279,7 +279,7 @@ class _IncrementableValueState extends State { ? () { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; - widget.onIncrement(); + widget.onIncrement?.call(); } : null, padding: EdgeInsets.all(0), @@ -300,7 +300,7 @@ class _IncrementableValueState extends State { ? () { lastTouchTimeMs = DateTime.now().millisecondsSinceEpoch; - widget.onBigIncrement(); + widget.onBigIncrement?.call(); } : null, padding: EdgeInsets.all(0), diff --git a/lib/widget/keyboard.dart b/lib/widget/keyboard.dart index c3b803d5..12a09d66 100644 --- a/lib/widget/keyboard.dart +++ b/lib/widget/keyboard.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:math'; import 'dart:ui'; -import 'package:aeyrium_sensor/aeyrium_sensor.dart'; +// import 'package:aeyrium_sensor/aeyrium_sensor.dart'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; import 'package:flutter/services.dart'; import '../drawing/canvas_tone_drawer.dart'; @@ -36,20 +36,20 @@ class Keyboard extends StatefulWidget { final VoidCallback closeKeyboard; const Keyboard( - {Key key, - this.appSettings, - this.height, - this.showConfiguration, - this.hideConfiguration, - this.sectionColor, - this.part, - this.pressedNotesNotifier, - this.bluetoothControllerPressedNotes, - this.width, - this.leftMargin, - this.distanceFromBottom, - this.closed, - this.closeKeyboard}) + {Key? key, + required this.appSettings, + required this.height, + required this.showConfiguration, + required this.hideConfiguration, + required this.sectionColor, + required this.part, + required this.pressedNotesNotifier, + required this.bluetoothControllerPressedNotes, + required this.width, + required this.leftMargin, + required this.distanceFromBottom, + required this.closed, + required this.closeKeyboard}) : super(key: key); @override @@ -75,10 +75,10 @@ class KeyboardState extends State with TickerProviderStateMixin { bool useOrientation = false; List> _streamSubscriptions = >[]; - ValueNotifier scrollPositionNotifier; + late ValueNotifier scrollPositionNotifier; bool reverseScrolling = false; ScrollingMode scrollingMode = ScrollingMode.sideScroll; - ScrollingMode previousScrollingMode; + ScrollingMode? previousScrollingMode; bool showScrollHint = false; List _scaleAnimationControllers = []; @@ -99,7 +99,7 @@ class KeyboardState extends State with TickerProviderStateMixin { _scaleAnimationControllers.clear(); AnimationController scaleAnimationController = animationController(); _scaleAnimationControllers.add(scaleAnimationController); - Animation animation; + late Animation animation; animation = Tween(begin: _halfStepWidthInPx, end: value) .animate(scaleAnimationController) ..addListener(() { @@ -111,10 +111,10 @@ class KeyboardState extends State with TickerProviderStateMixin { } double get diatonicStepWidthInPx => halfStepWidthInPx * 12 / 7; - AnimationController orientationAnimationController; - Animation orientationAnimation; - AnimationController blurAnimationController; - Animation blurAnimation; + late AnimationController orientationAnimationController; + late Animation orientationAnimation; + late AnimationController blurAnimationController; + late Animation blurAnimation; int highestPitch = CanvasToneDrawer.TOP; int lowestPitch = CanvasToneDrawer.BOTTOM; @@ -124,7 +124,7 @@ class KeyboardState extends State with TickerProviderStateMixin { (scrollingMode == ScrollingMode.sideScroll) ? 30 : 0; Map _pointerIdsToTones = Map(); - double _startHalfStepWidthInPx; + late double _startHalfStepWidthInPx; @override void initState() { @@ -141,51 +141,49 @@ class KeyboardState extends State with TickerProviderStateMixin { ).animate(blurAnimationController); scrollPositionNotifier = ValueNotifier(0); if (MyPlatform.isMobile) { - try { - _streamSubscriptions.add(AeyriumSensor.sensorEvents.listen((event) { - if (scrollingMode != ScrollingMode.sideScroll) { - print("Sensor event: $event"); - double normalizedPitch; - switch (scrollingMode) { - case ScrollingMode.pitch: - var absoluteScrollPosition = event.pitch; - if (absoluteScrollPosition < 0) { - absoluteScrollPosition = -absoluteScrollPosition; - } - normalizedPitch = max( - 0.0, min(1.0, (1.58 - absoluteScrollPosition * 1.2) / 1.5)); - break; - case ScrollingMode.roll: -// var maxRoll = -1.45; // All the way to the right -// var minRoll = 1.45; // All the way to the left - normalizedPitch = (1.45 - event.roll) / 2.9; - break; - case ScrollingMode.sideScroll: - break; - } - - double newScrollPositionValue = max(0.0, min(1.0, normalizedPitch)); - if (newScrollPositionValue.isFinite && - !newScrollPositionValue.isNaN) { - Animation animation; - animation = Tween( - begin: scrollPositionNotifier.value, - end: newScrollPositionValue) - .animate(orientationAnimationController) - ..addListener(() { - scrollPositionNotifier.value = animation.value; -// setState(() {}); - }); - orientationAnimationController.forward( - from: scrollPositionNotifier.value); -// scrollPositionNotifier.value = newScrollPositionValue; - } - } - })); - } catch (MissingPluginException) { - // It's fine for this to not work on desktop - scrollingMode = ScrollingMode.sideScroll; - } +// try { +// _streamSubscriptions.add(AeyriumSensor.sensorEvents.listen((event) { +// if (scrollingMode != ScrollingMode.sideScroll) { +// print("Sensor event: $event"); +// double normalizedPitch; +// switch (scrollingMode) { +// case ScrollingMode.pitch: +// var absoluteScrollPosition = event.pitch; +// if (absoluteScrollPosition < 0) { +// absoluteScrollPosition = -absoluteScrollPosition; +// } +// normalizedPitch = max( +// 0.0, min(1.0, (1.58 - absoluteScrollPosition * 1.2) / 1.5)); +// break; +// case ScrollingMode.roll: +// // var maxRoll = -1.45; // All the way to the right +// // var minRoll = 1.45; // All the way to the left +// normalizedPitch = (1.45 - event.roll) / 2.9; +// break; +// case ScrollingMode.sideScroll: +// break; +// } + +// double newScrollPositionValue = max(0.0, min(1.0, normalizedPitch)); +// if (newScrollPositionValue.isFinite && +// !newScrollPositionValue.isNaN) { +// Animation animation; +// animation = Tween( +// begin: scrollPositionNotifier.value, +// end: newScrollPositionValue) +// .animate(orientationAnimationController) +// ..addListener(() { +// scrollPositionNotifier.value = animation.value; +// }); +// orientationAnimationController.forward( +// from: scrollPositionNotifier.value); +// } +// } +// })); +// } catch (MissingPluginException) { +// // It's fine for this to not work on desktop +// scrollingMode = ScrollingMode.sideScroll; +// } } WidgetsBinding.instance.addPostFrameCallback((_) { @@ -242,7 +240,7 @@ class KeyboardState extends State with TickerProviderStateMixin { scrollDirection: Axis.horizontal, slivers: [ CustomSliverToBoxAdapter( - setVisibleRect: (rect) { + (rect) { _visibleRect = rect; _visibleRect = Rect.fromLTRB(rect.left, rect.top, rect.right, rect.bottom - touchScrollAreaHeight); @@ -389,7 +387,7 @@ class KeyboardState extends State with TickerProviderStateMixin { event.position.dy - widget.distanceFromBottom; double maxDy = widget.height - touchScrollAreaHeight; - int oldTone = _pointerIdsToTones[event.pointer]; + int oldTone = _pointerIdsToTones[event.pointer]!; int tone; if (dy > maxDy / 2) { // Black key area press @@ -412,7 +410,7 @@ class KeyboardState extends State with TickerProviderStateMixin { } }, onPointerUp: (event) { - int tone = _pointerIdsToTones.remove(event.pointer); + int tone = _pointerIdsToTones.remove(event.pointer)!; widget.pressedNotesNotifier.value = _pointerIdsToTones.values.toSet(); try { @@ -420,7 +418,7 @@ class KeyboardState extends State with TickerProviderStateMixin { } catch (t) {} }, onPointerCancel: (event) { - int tone = _pointerIdsToTones.remove(event.pointer); + int tone = _pointerIdsToTones.remove(event.pointer)!; widget.pressedNotesNotifier.value = _pointerIdsToTones.values.toSet(); try { @@ -794,6 +792,9 @@ class KeyboardState extends State with TickerProviderStateMixin { case 6: toneOffset = 11; break; + default: + toneOffset = 0; + break; } int tone = 12 * (octave - 4) + toneOffset; // print("diatonic tone: $diatonicTone octave: $octave toneoffset: $toneOffset tone: $tone"); @@ -809,12 +810,12 @@ class _KeyboardPainter extends CustomPainter { final int highestPitch, lowestPitch; _KeyboardPainter( - {this.highestPitch, - this.lowestPitch, - this.pressedNotesNotifier, - this.scrollPositionNotifier, - this.halfStepsOnScreen, - this.visibleRect}) + {required this.highestPitch, + required this.lowestPitch, + required this.pressedNotesNotifier, + required this.scrollPositionNotifier, + required this.halfStepsOnScreen, + required this.visibleRect}) : super( repaint: Listenable.merge([ scrollPositionNotifier, @@ -876,7 +877,7 @@ class _KeyboardPainter extends CustomPainter { } class KeyboardRenderer extends CanvasToneDrawer { - Iterable pressedNotes; + Iterable pressedNotes = []; bool renderLettersAndNumbers = true; draw(Canvas canvas) { diff --git a/lib/widget/my_buttons.dart b/lib/widget/my_buttons.dart index 90eb9e99..a5b3f2e7 100644 --- a/lib/widget/my_buttons.dart +++ b/lib/widget/my_buttons.dart @@ -99,7 +99,7 @@ class MySlider extends Slider { const MySlider({ Key? key, required double value, - required ValueChanged onChanged, + ValueChanged? onChanged, ValueChanged? onChangeStart, ValueChanged? onChangeEnd, double min = 0.0, diff --git a/lib/widget/scalable_view.dart b/lib/widget/scalable_view.dart index 0d1a6c8b..1d75f9aa 100644 --- a/lib/widget/scalable_view.dart +++ b/lib/widget/scalable_view.dart @@ -6,15 +6,15 @@ import 'incrementable_value.dart'; import '../ui_models.dart'; class ScalableView extends StatefulWidget { - final VoidCallback onMicroScaleDown; - final VoidCallback onMicroScaleUp; - final VoidCallback onScaleDown; - final VoidCallback onScaleUp; - final Widget child; + final VoidCallback? onMicroScaleDown; + final VoidCallback? onMicroScaleUp; + final VoidCallback? onScaleDown; + final VoidCallback? onScaleUp; + final Widget? child; final String zoomLevelDescription; // e.g. 79%, 1x, 2x. Your choice. final bool autoScroll; - final VoidCallback toggleAutoScroll; - final VoidCallback scrollToCurrent; + final VoidCallback? toggleAutoScroll; + final VoidCallback? scrollToCurrent; final bool visible; final Color primaryColor; final bool showViewOptions; @@ -26,8 +26,8 @@ class ScalableView extends StatefulWidget { this.onScaleDown, this.onScaleUp, this.child, - this.zoomLevelDescription, - this.autoScroll, + required this.zoomLevelDescription, + this.autoScroll = true, this.toggleAutoScroll, this.scrollToCurrent, this.visible = true, @@ -44,125 +44,132 @@ class ScalableView extends StatefulWidget { } class _ScalableViewState extends State { - double lastUpdatedScale; - int directionUpOrDown; + double? lastUpdatedScale; + int? directionUpOrDown; @override Widget build(BuildContext context) { return GestureDetector( child: Stack( - children: [ - widget.child, - Row(children: [ - Expanded(child: SizedBox()), - SizedBox(width: 2), - Column(children: [ - Expanded(child: SizedBox()), - if (widget.toggleAutoScroll != null) - MusicActionButton( - visible: widget.visible && widget.showViewOptions, - onPressed: widget.toggleAutoScroll, - child: Stack(children: [ - Transform.translate( - offset: Offset(0, -6), - child: Text("Auto", - maxLines: 1, - overflow: TextOverflow.fade, - style: TextStyle( - fontSize: 10, - color: widget.autoScroll - ? widget.primaryColor - : Colors.grey))), - Transform.translate( - offset: Offset(0, 6), - child: AnimatedOpacity( - duration: animationDuration, - opacity: !widget.autoScroll ? 1 : 0, - child: - Icon(Icons.location_disabled, color: Colors.grey), - ), - ), - Transform.translate( - offset: Offset(0, 6), - child: AnimatedOpacity( - duration: animationDuration, - opacity: widget.autoScroll ? 1 : 0, - child: - Icon(Icons.my_location, color: widget.primaryColor), - ), - ), - ]), - ), - SizedBox(height: 2), - Container( - color: Colors.black12, - padding: EdgeInsets.all(0), - child: IncrementableValue( - child: Container( - width: 48, - height: 48, - child: Align( - alignment: Alignment.center, - child: Transform.translate( - offset: Offset(0, -3), - child: Stack(children: [ - Transform.translate( - offset: Offset(-5, 5), - child: Transform.scale( - scale: 1, - child: Icon(Icons.zoom_out, - color: musicForegroundColor - .withOpacity(0.54)))), - Transform.translate( - offset: Offset(5, -5), - child: Transform.scale( - scale: 1, - child: Icon(Icons.zoom_in, - color: musicForegroundColor - .withOpacity(0.54)))), - Transform.translate( - offset: Offset(2, 20), - child: Text(widget.zoomLevelDescription, - style: TextStyle( - fontWeight: FontWeight.w800, - fontSize: 12, - color: musicForegroundColor - .withOpacity(0.87))), - ), - ])), + children: + ((widget.child != null ? [widget.child!] : []) as List) + + [ + // widget.child, + Row(children: [ + Expanded(child: SizedBox()), + SizedBox(width: 2), + Column(children: [ + Expanded(child: SizedBox()), + if (widget.toggleAutoScroll != null) + MusicActionButton( + visible: widget.visible && widget.showViewOptions, + onPressed: widget.toggleAutoScroll, + child: Stack(children: [ + Transform.translate( + offset: Offset(0, -6), + child: Text("Auto", + maxLines: 1, + overflow: TextOverflow.fade, + style: TextStyle( + fontSize: 10, + color: widget.autoScroll + ? widget.primaryColor + : Colors.grey))), + Transform.translate( + offset: Offset(0, 6), + child: AnimatedOpacity( + duration: animationDuration, + opacity: !widget.autoScroll ? 1 : 0, + child: Icon(Icons.location_disabled, + color: Colors.grey), + ), + ), + Transform.translate( + offset: Offset(0, 6), + child: AnimatedOpacity( + duration: animationDuration, + opacity: widget.autoScroll ? 1 : 0, + child: Icon(Icons.my_location, + color: widget.primaryColor), + ), + ), + ]), ), - ), - valueWidth: 48, - collapsing: true, - musicActionButtonStyle: true, - musicActionButtonColor: - widget.zoomButtonColor.withOpacity(0.26), - incrementIcon: Icons.zoom_in, - decrementIcon: Icons.zoom_out, - onIncrement: widget.onScaleUp, - onDecrement: widget.onScaleDown)), - SizedBox(height: 2), - AnimatedContainer( - duration: animationDuration, - height: widget.shiftUpZoomControls ? 24 : 0) - ]), - SizedBox(width: 2), - ]) - ], + SizedBox(height: 2), + Container( + color: Colors.black12, + padding: EdgeInsets.all(0), + child: IncrementableValue( + child: Container( + width: 48, + height: 48, + child: Align( + alignment: Alignment.center, + child: Transform.translate( + offset: Offset(0, -3), + child: Stack(children: [ + Transform.translate( + offset: Offset(-5, 5), + child: Transform.scale( + scale: 1, + child: Icon(Icons.zoom_out, + color: musicForegroundColor + .withOpacity(0.54)))), + Transform.translate( + offset: Offset(5, -5), + child: Transform.scale( + scale: 1, + child: Icon(Icons.zoom_in, + color: musicForegroundColor + .withOpacity(0.54)))), + Transform.translate( + offset: Offset(2, 20), + child: Text( + widget.zoomLevelDescription, + style: TextStyle( + fontWeight: FontWeight.w800, + fontSize: 12, + color: musicForegroundColor + .withOpacity(0.87))), + ), + ])), + ), + ), + valueWidth: 48, + collapsing: true, + musicActionButtonStyle: true, + musicActionButtonColor: + widget.zoomButtonColor.withOpacity(0.26), + incrementIcon: Icons.zoom_in, + decrementIcon: Icons.zoom_out, + onIncrement: widget.onScaleUp, + onDecrement: widget.onScaleDown)), + SizedBox(height: 2), + AnimatedContainer( + duration: animationDuration, + height: widget.shiftUpZoomControls ? 24 : 0) + ]), + SizedBox(width: 2), + ]) + ], ), onScaleStart: (details) { lastUpdatedScale = 1; }, onScaleUpdate: (details) { + final lastUpdatedScale = this.lastUpdatedScale; + if (lastUpdatedScale == null) { + return; + } final scale = details.scale; // print("scale: $scale"); if (scale - lastUpdatedScale >= .01) { - widget.onMicroScaleUp(); + widget.onMicroScaleUp?.call(); } else if (scale - lastUpdatedScale <= -.01) { - widget.onMicroScaleDown(); + widget.onMicroScaleDown?.call(); } else if (scale - lastUpdatedScale >= .09) { - widget.onScaleUp(); + widget.onScaleUp?.call(); } else if (scale - lastUpdatedScale <= -.09) { - widget.onScaleDown(); + widget.onScaleDown?.call(); } }, onScaleEnd: (details) { diff --git a/pubspec.lock b/pubspec.lock index 17cafcc2..6864026d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.2" + appcheck: + dependency: "direct main" + description: + name: appcheck + sha256: "6971b1ae5833b15b1abc29f7d03d08db79577b2934ceb34fe39ab937b53c2f17" + url: "https://pub.dev" + source: hosted + version: "1.5.4+1" archive: dependency: "direct main" description: @@ -296,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.1" + material_design_icons_flutter: + dependency: "direct main" + description: + name: material_design_icons_flutter + sha256: "6f986b7a51f3ad4c00e33c5c84e8de1bdd140489bbcdc8b66fc1283dad4dea5a" + url: "https://pub.dev" + source: hosted + version: "7.0.7296" matrix4_transform: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d70644de..9e8ce007 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,6 +48,8 @@ dependencies: matrix4_transform: ^2.0.1 share_plus: ^11.0.0 collection: ^1.19.1 + appcheck: ^1.5.4+1 + material_design_icons_flutter: ^7.0.7296 dev_dependencies: flutter_test: From eadb5dd7578ec9c7d6be7f906c5123c36afcf73e Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 25 May 2025 15:21:31 -0400 Subject: [PATCH 05/11] down to 2xx errors --- lib/drawing/music/base_music_renderer.dart | 29 ++-- .../music/colorblock_music_renderer.dart | 9 +- lib/drawing/music/music_clef_renderer.dart | 2 +- .../music/music_measure_lines_renderer.dart | 2 +- .../music/music_staff_lines_renderer.dart | 4 +- .../music/notation_music_renderer.dart | 47 ++++--- lib/generated/i18n.dart | 126 ------------------ lib/layers_view/layers_part_view.dart | 66 ++++----- 8 files changed, 84 insertions(+), 201 deletions(-) delete mode 100644 lib/generated/i18n.dart diff --git a/lib/drawing/music/base_music_renderer.dart b/lib/drawing/music/base_music_renderer.dart index d7f05fb5..40972e13 100644 --- a/lib/drawing/music/base_music_renderer.dart +++ b/lib/drawing/music/base_music_renderer.dart @@ -14,14 +14,14 @@ class BaseMusicRenderer extends ColorGuide { final bool renderVertically = true; @override final double normalizedDevicePitch = 0; - Rect overallBounds; - Melody melody; - int elementPosition; - bool isCurrentlyPlayingBeat; - bool isSelectedBeatInHarmony; - Section section; - bool isUserChoosingHarmonyChord; - bool isMelodyReferenceEnabled; + late Rect overallBounds; + late Melody melody; + late int elementPosition; + late bool isCurrentlyPlayingBeat; + late bool isSelectedBeatInHarmony; + late Section section; + late bool isUserChoosingHarmonyChord; + late bool isMelodyReferenceEnabled; int beatPosition = 0; double xScale = 1; double yScale = 1; @@ -49,12 +49,12 @@ class BaseMusicRenderer extends ColorGuide { ///doesn't work for [renderVertically]=false. drawTimewiseLineRelativeToBounds( - {Canvas canvas, + {required Canvas canvas, bool leftSide = true, double alpha = 1, double strokeWidth = 1, - double startY, - double stopY, + required double startY, + required double stopY, double percentThrough = 0, Offset offset = Offset.zero}) { double oldStrokeWidth = alphaDrawerPaint.strokeWidth; @@ -72,7 +72,10 @@ class BaseMusicRenderer extends ColorGuide { } drawPitchwiseLine( - {Canvas canvas, double pointOnToneAxis, double left, double right}) { + {required Canvas canvas, + required double pointOnToneAxis, + double? left, + double? right}) { if (renderVertically) { canvas.drawLine( Offset(left ?? bounds.left, pointOnToneAxis), @@ -133,7 +136,7 @@ class BaseMusicRenderer extends ColorGuide { double centerOfTone(int tone) => startPoint - (bottomMostNote + tone - 9.5) * halfStepWidth; - double pointFor({NoteLetter letter, int octave}) { + double pointFor({required NoteLetter letter, required int octave}) { double middleC = centerOfTone(0); double result = middleC - letterStepSize * (((octave - 4) * 7) + letter.value); diff --git a/lib/drawing/music/colorblock_music_renderer.dart b/lib/drawing/music/colorblock_music_renderer.dart index 57f44f5d..34f072bc 100644 --- a/lib/drawing/music/colorblock_music_renderer.dart +++ b/lib/drawing/music/colorblock_music_renderer.dart @@ -11,7 +11,7 @@ class ColorblockMusicRenderer extends BaseMusicRenderer { double uiScale = 1; @override double get halfStepsOnScreen => (highestPitch - lowestPitch + 1).toDouble(); - double colorblockAlpha; + double colorblockAlpha = 0.5; static double stepLineScaleThreshold = 0.7; draw(Canvas canvas) { @@ -48,7 +48,7 @@ class ColorblockMusicRenderer extends BaseMusicRenderer { } } - _drawColorblockMelody({Canvas canvas, double alpha}) { + _drawColorblockMelody({required Canvas canvas, required double alpha}) { iterateSubdivisions(() { _drawColorblockNotes( canvas: canvas, elementPosition: elementPosition, alpha: alpha); @@ -61,7 +61,10 @@ class ColorblockMusicRenderer extends BaseMusicRenderer { // } } - _drawColorblockNotes({Canvas canvas, int elementPosition, double alpha}) { + _drawColorblockNotes( + {required Canvas canvas, + required int elementPosition, + required double alpha}) { alphaDrawerPaint.color = musicForegroundColor.withAlpha((alpha * 255).toInt()); diff --git a/lib/drawing/music/music_clef_renderer.dart b/lib/drawing/music/music_clef_renderer.dart index da225137..35194edd 100644 --- a/lib/drawing/music/music_clef_renderer.dart +++ b/lib/drawing/music/music_clef_renderer.dart @@ -11,7 +11,7 @@ import 'music_staff_lines_renderer.dart'; class MelodyClefRenderer extends BaseMusicRenderer { @override double get halfStepsOnScreen => (highestPitch - lowestPitch + 1).toDouble(); - List clefs; // = [Clef.treble, Clef.bass]; + List clefs = [Clef.treble, Clef.bass]; static Path _trebleClefPath = parseSvgPathData( "M 592.10873,1275.9669 C 461.75172,1268.3902 328.65904,1186.6265 249.0601,1092.783 C 156.77394,983.97782 118.72592,836.04683 128.47199,714.56357 C 157.10277,357.61288 545.27831,146.63848 688.97108,-9.280262 C 785.15294,-113.64625 805.31643,-164.52308 826.79977,-218.19949 C 868.39181,-322.09965 875.09166,-443.8341 792.63375,-452.92251 C 713.90712,-461.59988 649.13737,-337.79201 620.20973,-253.17845 C 594.19587,-177.07331 576.90507,-100.71696 592.5563,13.979673 C 599.58954,65.50958 793.18636,1503.9125 796.45179,1526.2088 C 829.05589,1749.0255 701.63092,1841.2249 571.55248,1857.6251 C 290.65671,1893.038 200.52617,1607.5843 326.4212,1499.1719 C 423.34291,1415.7001 564.35026,1487.3615 556.73245,1624.5919 C 549.98693,1746.1391 430.80546,1749.7197 400.35244,1746.9429 C 447.10065,1830.7846 799.52998,1874.5871 745.41513,1495.7923 C 737.811,1442.5634 558.91549,90.842953 554.53112,60.595454 C 521.71238,-165.84753 516.71147,-345.08557 634.69182,-554.25141 C 678.24767,-631.46637 747.0821,-681.3156 780.87362,-674.7893 C 788.29962,-673.35526 795.69824,-670.62872 801.57144,-664.56827 C 892.07191,-571.31845 919.83494,-364.53202 909.9199,-245.74332 C 899.76736,-124.11391 894.1088,1.7993735 773.16902,148.63428 C 726.36601,205.45738 583.54553,330.63538 501.65851,402.55255 C 386.60107,503.59831 303.14756,591.85179 257.99323,698.31862 C 207.24886,817.97506 198.65826,968.6006 313.27268,1102.2505 C 379.20247,1177.7619 488.59222,1231.3424 580.65459,1232.4842 C 836.63719,1235.6628 911.39048,1109.4801 913.77904,966.58197 C 917.71126,731.28351 633.64596,642.32214 516.85762,804.10953 C 449.14212,897.92109 478.90552,996.66049 524.38411,1043.6371 C 539.99424,1059.7587 557.43121,1072.0395 573.92734,1078.8855 C 579.9056,1081.3654 593.96751,1087.9054 589.97593,1097.4779 C 586.6557,1105.4428 580.20702,1105.8904 574.33381,1105.1871 C 500.68573,1096.3544 419.13667,1025.958 399.0828,904.87212 C 369.86288,728.38801 525.6035,519.0349 747.9133,553.274 C 893.45572,575.68903 1028.5853,700.92182 1016.7338,934.11946 C 1006.5722,1133.9822 840.87996,1290.4262 592.10873,1275.9669 z"); diff --git a/lib/drawing/music/music_measure_lines_renderer.dart b/lib/drawing/music/music_measure_lines_renderer.dart index cc4a9f9f..9610ebca 100644 --- a/lib/drawing/music/music_measure_lines_renderer.dart +++ b/lib/drawing/music/music_measure_lines_renderer.dart @@ -25,7 +25,7 @@ class MelodyMeasureLinesRenderer extends BaseMusicRenderer { try { // print("drawing measure line"); NoteSpecification highestDiatonicNote = - clefs.expand((clef) => clef.notes).maxBy((e) => e.diatonicValue); + clefs.expand((clef) => clef.notes).maxBy((e) => e.diatonicValue)!; NoteSpecification lowestDiatonicNote = clefs.expand((clef) => clef.notes).minBy((e) => e.diatonicValue); drawTimewiseLineRelativeToBounds( diff --git a/lib/drawing/music/music_staff_lines_renderer.dart b/lib/drawing/music/music_staff_lines_renderer.dart index 2ad8344a..109523d2 100644 --- a/lib/drawing/music/music_staff_lines_renderer.dart +++ b/lib/drawing/music/music_staff_lines_renderer.dart @@ -8,7 +8,7 @@ import 'base_music_renderer.dart'; enum Clef { treble, bass, tenor_treble, drum_treble, drum_bass } extension ClefNotes on Clef { - List get notes => clefNotes[this]; + List get notes => clefNotes[this]!; static final Map> clefNotes = { Clef.treble: [ @@ -75,7 +75,7 @@ extension ClefNotes on Clef { static Map diatonicMaxCache = Map(); int get diatonicMax => diatonicMaxCache.putIfAbsent( - this, () => notes.maxBy((it) => it.diatonicValue).diatonicValue); + this, () => notes.maxBy((it) => it.diatonicValue)!.diatonicValue); static Map diatonicMinCache = Map(); int get diatonicMin => diatonicMinCache.putIfAbsent( diff --git a/lib/drawing/music/notation_music_renderer.dart b/lib/drawing/music/notation_music_renderer.dart index b8dc34e7..e587ce37 100644 --- a/lib/drawing/music/notation_music_renderer.dart +++ b/lib/drawing/music/notation_music_renderer.dart @@ -17,25 +17,25 @@ enum Notehead { quarter, half, whole, percussion } class _NoteheadInstruction { final Notehead notehead; - final NoteSign noteSign; + final NoteSign? noteSign; final double noteheadTop; final double noteheadLeft; final bool staggered; - final bool hadStaggeredNotes; + final bool hadStaggeredNotes = false; final List ledgerLines; const _NoteheadInstruction( - {this.notehead, - this.noteSign, - this.noteheadLeft, - this.ledgerLines, - this.noteheadTop, - this.staggered}); + {required this.notehead, + required this.noteSign, + required this.noteheadLeft, + required this.ledgerLines, + required this.noteheadTop, + required this.staggered}); } class _StemInstruction { final Offset top; final Offset bottom; - const _StemInstruction({this.top, this.bottom}); + const _StemInstruction({required this.top, required this.bottom}); } class _RenderInstructions { @@ -107,7 +107,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { _renderNoteheadSignAndLedgers( Canvas canvas, _NoteheadInstruction instruction) { - NoteSign noteSign = instruction.noteSign; + NoteSign? noteSign = instruction.noteSign; bool staggered = instruction.staggered; double noteheadWidth = 18 * xScale; double noteheadHeight = noteheadWidth; @@ -222,7 +222,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { } // Draw signs - NoteSign previousSign; + NoteSign? previousSign; Iterable previousSigns = getMostRecentSignsOf( note: note, relevantMelodies: otherMelodiesOnStaff.followedBy([melody]), @@ -235,7 +235,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { forceShowNaturals = true; } // val previousSign = previousSignOf(melody, harmony, note, elementPosition) - NoteSign signToDraw; + NoteSign? signToDraw; switch (note.sign) { case NoteSign.sharp: if (previousSign != NoteSign.sharp) signToDraw = NoteSign.sharp; @@ -303,8 +303,8 @@ class NotationMusicRenderer extends BaseMusicRenderer { static Map> recentSignCache = Map(); Iterable getMostRecentSignsOf({ - NoteSpecification note, - Iterable relevantMelodies, + required NoteSpecification note, + required Iterable relevantMelodies, }) { final args = ArgumentList([ relevantMelodies.map((e) => e.id).join(), @@ -323,8 +323,8 @@ class NotationMusicRenderer extends BaseMusicRenderer { } Iterable _calculateMostRecentSignsOf({ - NoteSpecification note, - Iterable relevantMelodies, + required NoteSpecification note, + required Iterable relevantMelodies, }) { // final currentBeatPosition = elementPosition.toDouble() / melody.subdivisionsPerBeat; // final lastDownbeat = range(0,1000000).firstWhere((it) { @@ -348,7 +348,7 @@ class NotationMusicRenderer extends BaseMusicRenderer { } relevantMelodyIndex -= 1; } - NoteSign melodyResult; + NoteSign? melodyResult; while (melodyResult == null) { if (relevantMelodyIndex % relevantMelody.subdivisionsPerBeat == 0 && // Beginning of measure, stop searching @@ -390,8 +390,8 @@ class NotationMusicRenderer extends BaseMusicRenderer { return []; } double highestKey = - resultCandidates.keys.toList().maxBy((it) => (it * 1000).toInt()); - return resultCandidates[highestKey]; + resultCandidates.keys.toList().maxBy((it) => (it * 1000).toInt()) ?? -1; + return resultCandidates[highestKey] ?? []; } static Path _sharpPath = parseSvgPathData( @@ -408,12 +408,12 @@ class NotationMusicRenderer extends BaseMusicRenderer { Offset.zero); static Path _naturalPath = parseSvgPathData( "M 26.578125,106.17187 L 22.640625,107.57812 L 22.640625,75.375001 L 0,85.218751 L 0,1.6875 L 3.796875,1.4210855e-014 L 3.796875,32.765625 L 26.578125,22.359375 L 26.578125,106.17187 z M 22.640625,61.171871 L 22.640625,38.671875 L 3.796875,46.96875 L 3.796875,69.468751 L 22.640625,61.171871 z "); - _renderSign(Canvas canvas, Rect signRect, NoteSign sign) { + _renderSign(Canvas canvas, Rect signRect, NoteSign? sign) { // canvas.drawRect(signRect, Paint()..style=PaintingStyle.fill..color=Colors.black26); // print("Rendering sign: $sign"); canvas.save(); canvas.translate(signRect.topLeft.dx, signRect.topLeft.dy); - Path signPath; + Path? signPath; switch (sign) { case NoteSign.sharp: signPath = _sharpPath; @@ -445,7 +445,10 @@ class NotationMusicRenderer extends BaseMusicRenderer { default: break; } - canvas.drawPath(signPath, alphaDrawerPaint); + + if (signPath != null) { + canvas.drawPath(signPath, alphaDrawerPaint); + } canvas.restore(); } diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart deleted file mode 100644 index f4685cf7..00000000 --- a/lib/generated/i18n.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -// ignore_for_file: non_constant_identifier_names -// ignore_for_file: camel_case_types -// ignore_for_file: prefer_single_quotes - -// This file is automatically generated. DO NOT EDIT, all your changes would be lost. -class S implements WidgetsLocalizations { - const S(); - - static S current; - - static const GeneratedLocalizationsDelegate delegate = - GeneratedLocalizationsDelegate(); - - static S of(BuildContext context) => Localizations.of(context, S); - - @override - TextDirection get textDirection => TextDirection.ltr; -} - -class $en extends S { - const $en(); -} - -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { - const GeneratedLocalizationsDelegate(); - - List get supportedLocales { - return const [ - Locale("en", ""), - ]; - } - - LocaleListResolutionCallback listResolution( - {Locale fallback, bool withCountry = true}) { - return (List locales, Iterable supported) { - if (locales.isEmpty) { - return fallback ?? supported.first; - } else { - return _resolve(locales.first, fallback, supported, withCountry); - } - }; - } - - LocaleResolutionCallback resolution( - {Locale fallback, bool withCountry = true}) { - return (Locale locale, Iterable supported) { - return _resolve(locale, fallback, supported, withCountry); - }; - } - - @override - Future load(Locale locale) { - final String lang = getLang(locale); - switch (lang) { - case "en": - S.current = const $en(); - return SynchronousFuture(S.current); - default: - // NO-OP. - } - S.current = const S(); - return SynchronousFuture(S.current); - } - - @override - bool isSupported(Locale locale) => _isSupported(locale, true); - - @override - bool shouldReload(GeneratedLocalizationsDelegate old) => false; - - /// - /// Internal method to resolve a locale from a list of locales. - /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, - bool withCountry) { - if (!_isSupported(locale, withCountry)) { - return fallback ?? supported.first; - } - - final Locale languageLocale = Locale(locale.languageCode, ""); - if (supported.contains(locale)) { - return locale; - } else if (supported.contains(languageLocale)) { - return languageLocale; - } else { - final Locale fallbackLocale = fallback ?? supported.first; - return fallbackLocale; - } - } - - /// - /// Returns true if the specified locale is supported, false otherwise. - /// - bool _isSupported(Locale locale, bool withCountry) { - for (Locale supportedLocale in supportedLocales) { - // Language must always match both locales. - if (supportedLocale.languageCode != locale.languageCode) { - continue; - } - - // If country code matches, return this locale. - if (supportedLocale.countryCode == locale.countryCode) { - return true; - } - - // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && - (supportedLocale.countryCode == null || - supportedLocale.countryCode.isEmpty)) { - return true; - } - } - return false; - } -} - -String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); diff --git a/lib/layers_view/layers_part_view.dart b/lib/layers_view/layers_part_view.dart index 93e90747..0fb337a8 100644 --- a/lib/layers_view/layers_part_view.dart +++ b/lib/layers_view/layers_part_view.dart @@ -27,7 +27,7 @@ class LayersPartView extends StatefulWidget { MelodyReferenceView.columnWidthMicroIncrement; final Score score; - final Axis scrollDirection; + final Axis? scrollDirection; final Function(Melody) selectMelody; final VoidCallback toggleEditingMelody; final VoidCallback hideMelodyView; @@ -58,33 +58,33 @@ class LayersPartView extends StatefulWidget { } LayersPartView({ - this.score, + required this.score, this.scrollDirection, - this.part, - this.sectionColor, - this.currentSection, - this.selectedMelody, - this.selectMelody, - this.colorboardPart, - this.keyboardPart, - this.setKeyboardPart, - this.setColorboardPart, - this.selectPart, - this.toggleMelodyReference, - this.setReferenceVolume, - this.setPartVolume, - this.editingMelody, - this.toggleEditingMelody, - this.hideMelodyView, - this.removePart, - this.selectedPart, - this.enableColorboard, - this.showBeatCounts, - this.height, - this.showMediumDetails, - this.autoScroll, - this.showHighDetails, - this.width, + required this.part, + required this.sectionColor, + required this.currentSection, + required this.selectedMelody, + required this.selectMelody, + required this.colorboardPart, + required this.keyboardPart, + required this.setKeyboardPart, + required this.setColorboardPart, + required this.selectPart, + required this.toggleMelodyReference, + required this.setReferenceVolume, + required this.setPartVolume, + required this.editingMelody, + required this.toggleEditingMelody, + required this.hideMelodyView, + required this.removePart, + required this.selectedPart, + required this.enableColorboard, + required this.showBeatCounts, + required this.height, + required this.showMediumDetails, + required this.autoScroll, + required this.showHighDetails, + required this.width, }); @override @@ -141,7 +141,7 @@ class _LayersPartViewState extends State { get toggleEditingMelody => widget.toggleEditingMelody; get hideMelodyView => widget.hideMelodyView; - ScrollController scrollController; + late ScrollController scrollController; int _indexOfKey(Key key) { return widget._items.indexWhere((Melody melody) => Key(melody.id) == key); @@ -172,7 +172,7 @@ class _LayersPartViewState extends State { bool get scrollControllerIsNearTop => scrollController.hasClients && scrollController.offset < (widget.showMediumDetails ? 150 : 165); - DateTime _lastScrollTime; + DateTime? _lastScrollTime; setScrollToTopTimeout() { final v = DateTime.now(); Future.delayed(Duration(seconds: 3), () { @@ -265,8 +265,8 @@ class _LayersPartViewState extends State { ]; int newMelodyBeatCountIndex = 0; - String lastSelectedMelodyId; - double prevWidth; + String? lastSelectedMelodyId; + double? prevWidth; @override Widget build(BuildContext context) { @@ -592,9 +592,9 @@ class _LayersPartViewState extends State { r"^(.*?)(\d*)\s*$", ); final match = expr.allMatches(melody.name).first; - String prefix = match.group(1); + String prefix = match.group(1)!; prefix = prefix.trim(); - int number = int.tryParse(match.group(2)) ?? 1; + int number = int.tryParse(match.group(2)!) ?? 1; int newNumber = number + 1; melody.name = "$prefix $newNumber"; while (part.melodies.any((it) { From 299eca7d657deb6567e5280873dc39f9a097902a Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Mon, 26 May 2025 12:52:32 -0400 Subject: [PATCH 06/11] down to the 100s of errors now --- lib/layers_view/melody_menu_browser.dart | 45 +++--- lib/main.dart | 170 +++++++++++++---------- lib/messages/bs_message.dart | 4 +- lib/messages/messages_ui.dart | 2 +- lib/music_preview/melody_preview.dart | 22 ++- lib/music_preview/part_preview.dart | 14 +- lib/recording/recording.dart | 6 +- lib/storage/migrations.dart | 6 +- lib/storage/score_manager.dart | 46 +++--- lib/universe_view/universe_view_ui.dart | 2 +- pubspec.lock | 20 +-- pubspec.yaml | 4 +- 12 files changed, 182 insertions(+), 159 deletions(-) diff --git a/lib/layers_view/melody_menu_browser.dart b/lib/layers_view/melody_menu_browser.dart index 69adfce8..fe587b90 100644 --- a/lib/layers_view/melody_menu_browser.dart +++ b/lib/layers_view/melody_menu_browser.dart @@ -22,14 +22,14 @@ class MelodyMenuBrowser extends StatefulWidget { final Section currentSection; final Function(Melody) onMelodySelected; final Color textColor; - final Widget child; + final Widget? child; const MelodyMenuBrowser( - {Key key, + {Key? key, this.child, - this.part, - this.currentSection, - this.onMelodySelected, + required this.part, + required this.currentSection, + required this.onMelodySelected, this.textColor = Colors.white}) : super(key: key); @@ -77,10 +77,10 @@ final Map> _sampleDrumMelodies = { final _manager = ScoreManager(); class _MelodyMenuBrowserState extends State { - Score selectedScore; - Part selectedPart; - BSMethod updatedMenu; - String selectedSamples; + Score? selectedScore; + Part? selectedPart; + late BSMethod updatedMenu; + String? selectedSamples; Iterable get sampleLists => (widget.part.isDrum == true ? _sampleDrumMelodies : _sampleMelodies).keys; List get samples => @@ -121,7 +121,7 @@ class _MelodyMenuBrowserState extends State { @override Widget build(BuildContext context) { - return new MyPopupMenuButton( + return new MyPopupMenuButton( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), color: musicBackgroundColor.withOpacity(0.95), padding: EdgeInsets.zero, @@ -145,11 +145,9 @@ class _MelodyMenuBrowserState extends State { ]), updatedMenu: updatedMenu, itemBuilder: (ctx) { + late List> result; if (selectedScore == null && selectedSamples == null) { - List> result = [ - mainHeader(), - samplesSectionHeader() - ]; + result = [mainHeader(), samplesSectionHeader()]; result.addAll( sampleLists.map((listName) => sampleListMenuItem(listName))); // result.addAll(samples.map((m) => melodyMenuItem(m, isSample: true))); @@ -159,10 +157,7 @@ class _MelodyMenuBrowserState extends State { } return result; } else - List> result = [ - backMenuItem(), - sampleListHeader() - ]; + result = [backMenuItem(), sampleListHeader()]; result.addAll(menuEntriesByDuplicateStatus(samples, isSample: true)); // result.addAll(samples.map((m) => melodyMenuItem(m, isSample: true))); return result; @@ -170,7 +165,7 @@ class _MelodyMenuBrowserState extends State { onSelected: (value) { switch (value) { case "back": - if (selectedPart.isDrum) { + if (selectedPart?.isDrum ?? false) { selectedScore = null; } selectedPart = null; @@ -184,7 +179,7 @@ class _MelodyMenuBrowserState extends State { selectedScore = _scoreDataCache.firstWhere((s) => s.id == value); if (widget.part.isDrum == true) { - selectedPart = selectedScore.parts + selectedPart = selectedScore?.parts .firstWhere((p) => p.isDrum, orElse: null); } } @@ -211,7 +206,7 @@ class _MelodyMenuBrowserState extends State { child: Text( selectedSamples != null ? "Import" - : !selectedPart.isDrum + : !(selectedPart?.isDrum ?? false) ? "Parts" : "Import", style: TextStyle(color: musicForegroundColor), @@ -467,7 +462,7 @@ class _MelodyMenuBrowserState extends State { maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 10, color: musicForegroundColor)), - Text(selectedSamples, + Text(selectedSamples!, textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, @@ -482,7 +477,7 @@ class _MelodyMenuBrowserState extends State { maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 10, color: musicForegroundColor)), - Text(selectedScore.name, + Text(selectedScore?.name ?? "", textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, @@ -492,12 +487,12 @@ class _MelodyMenuBrowserState extends State { MyPopupMenuItem melodyListHeader(Part part) { return _splitListHeader( - Text(selectedScore.name, + Text(selectedScore?.name ?? "", textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 10, color: musicForegroundColor)), - Text(selectedPart.midiName, + Text(selectedPart?.midiName ?? "", textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, diff --git a/lib/main.dart b/lib/main.dart index 62a9d3a6..017173ca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,8 @@ +import 'dart:async'; import 'dart:math'; import 'package:beatscratch_flutter_redux/storage/universe_manager.dart'; +import 'package:collection/collection.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -64,17 +66,15 @@ const Map swatch = { ScoreManager _scoreManager = ScoreManager(); UniverseManager _universeManager = UniverseManager(); AppSettings _appSettings = AppSettings(); -var baseHandler = Fluro.Handler( - handlerFunc: (BuildContext context, Map params) { +var baseHandler = Fluro.Handler(handlerFunc: (context, params) { return MyHomePage(title: 'BeatScratch', initialScore: defaultScore()); // return UsersScreen(params["scoreData"][0]); }); -var scoreRouteHandler = Fluro.Handler( - handlerFunc: (BuildContext context, Map params) { - String scoreData = params["scoreData"][0]; +var scoreRouteHandler = Fluro.Handler(handlerFunc: (context, params) { + String scoreData = params["scoreData"]![0]; Score score; try { - score = scoreFromUrlHashValue(scoreData); + score = scoreFromUrlHashValue(scoreData)!; } catch (any) { score = defaultScore(); } @@ -82,9 +82,8 @@ var scoreRouteHandler = Fluro.Handler( return MyHomePage(title: 'BeatScratch', initialScore: score); // return UsersScreen(params["scoreData"][0]); }); -var pastebinRouteHandler = Fluro.Handler( - handlerFunc: (BuildContext context, Map params) { - String pastebinCode = params["pasteBinData"][0]; +var pastebinRouteHandler = Fluro.Handler(handlerFunc: (context, params) { + String pastebinCode = params["pasteBinData"]![0]; return MyHomePage( title: 'BeatScratch', initialScore: defaultScore(), @@ -108,7 +107,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // debugPaintSizeEnabled = true; - MyHomePage home; + late MyHomePage home; try { home = MyHomePage(title: 'BeatScratch', initialScore: defaultScore()); } catch (e) { @@ -142,21 +141,25 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title, this.initialScore, this.pastebinCode}) + MyHomePage( + {Key? key, + required this.title, + required this.initialScore, + this.pastebinCode}) : super(key: key); final String title; final Score initialScore; - final String pastebinCode; + final String? pastebinCode; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State with TickerProviderStateMixin { - Score score; + late Score score; InteractionMode interactionMode = InteractionMode.view; - SplitMode _splitMode; + late SplitMode _splitMode; SplitMode get splitMode => _splitMode; @@ -196,7 +199,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set recordingMelody(value) { _recordingMelody = value; if (value) { - BeatScratchPlugin.setRecordingMelody(selectedMelody); + BeatScratchPlugin.setRecordingMelody(value); _showMusicView(); } else { BeatScratchPlugin.setRecordingMelody(null); @@ -206,7 +209,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } } - Section _currentSection; // + Section _currentSection = Section(); Section get currentSection => _currentSection; @@ -216,7 +219,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { min(section.beatCount - 1, BeatScratchPlugin.currentBeat.value); _currentSection = section; if (recordingMelody && - section.referenceTo(selectedMelody).playbackType == + section.referenceTo(selectedMelody!).playbackType == MelodyReference_PlaybackType.disabled) { recordingMelody = false; } @@ -227,7 +230,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } } - int _tapInBeat; + int? _tapInBeat; bool showViewOptions = false; bool _wasKeyboardShowingWhenMidiConfigurationOpened = false; bool _wasColorboardShowingWhenMidiConfigurationOpened = false; @@ -251,7 +254,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool _showKeyboardConfiguration = false; bool _enableColorboard = false; - get enableColorboard => _enableColorboard; + bool get enableColorboard => _enableColorboard; set enableColorboard(bool value) { _enableColorboard = value; @@ -261,30 +264,30 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool showColorboard = false; bool _showColorboardConfiguration = false; - Part _keyboardPart; + Part? _keyboardPart; - Part get keyboardPart => _keyboardPart; + Part? get keyboardPart => _keyboardPart; - set keyboardPart(Part part) { + set keyboardPart(Part? part) { _keyboardPart = part; - BeatScratchPlugin.setKeyboardPart(part); + if (part != null) BeatScratchPlugin.setKeyboardPart(part); } - Part _colorboardPart; + Part? _colorboardPart; - Part get colorboardPart => _colorboardPart; + Part? get colorboardPart => _colorboardPart; - set colorboardPart(Part part) { + set colorboardPart(Part? part) { _colorboardPart = part; // BeatScratchPlugin.setColorboardPart(part); } - ValueNotifier> colorboardNotesNotifier; - ValueNotifier> keyboardNotesNotifier; - ValueNotifier>> bluetoothControllerPressedNotes; - int keyboardChordBase; - Set keyboardChordNotes = Set(); - ValueNotifier keyboardChordNotifier; + late ValueNotifier> colorboardNotesNotifier; + late ValueNotifier> keyboardNotesNotifier; + late ValueNotifier>> bluetoothControllerPressedNotes; + int? keyboardChordBase; + final Set keyboardChordNotes = Set(); + late ValueNotifier keyboardChordNotifier; bool get melodyViewVisible => _musicViewSizeFactor > 0; @@ -362,33 +365,33 @@ class _MyHomePageState extends State with TickerProviderStateMixin { }); } - Melody _selectedMelody; + Melody? _selectedMelody; - Melody get selectedMelody => _selectedMelody; + Melody? get selectedMelody => _selectedMelody; - set selectedMelody(Melody selectedMelody) { + set selectedMelody(Melody? selectedMelody) { _selectedMelody = selectedMelody; - Part part = score.parts - .firstWhere((p) => p.melodies.any((m) => m.id == selectedMelody.id)); + Part? part = score.parts.firstWhereOrNull( + (p) => p.melodies.any((m) => m.id == selectedMelody?.id)); if (part != null) { keyboardPart = part; } } - Part _selectedPart; + Part? _selectedPart; - Part get selectedPart => _selectedPart; + Part? get selectedPart => _selectedPart; - set selectedPart(Part selectedPart) { + set selectedPart(Part? selectedPart) { _selectedPart = selectedPart; keyboardPart = selectedPart; } - Part _viewingPart; + Part? _viewingPart; - Part get viewingPart => _viewingPart; + Part? get viewingPart => _viewingPart; - set viewingPart(Part viewingPart) { + set viewingPart(Part? viewingPart) { _viewingPart = viewingPart; keyboardPart = viewingPart; } @@ -397,7 +400,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { Color get sectionColor => currentSection.color.color; - _selectOrDeselectMelody(Melody melody, {bool hideMusicOnDeselect = true}) { + _selectOrDeselectMelody(Melody? melody, {bool hideMusicOnDeselect = true}) { setState(() { if (selectedMelody != melody) { selectedMelody = melody; @@ -413,7 +416,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { recordingMelody = false; if (hideMusicOnDeselect) { _hideMusicView(); - } else { + } else if (melody != null) { final part = score.parts .firstWhere((p) => p.melodies.any((m) => m.id == melody.id)); _selectOrDeselectPart(part, hideMusicOnDeselect: hideMusicOnDeselect); @@ -437,8 +440,10 @@ class _MyHomePageState extends State with TickerProviderStateMixin { _hideMusicView(); } else { if (musicViewMode == MusicViewMode.melody) { - _selectOrDeselectMelody(selectedMelody, - hideMusicOnDeselect: hideMusicOnDeselect); + if (selectedMelody != null) { + _selectOrDeselectMelody(selectedMelody!, + hideMusicOnDeselect: hideMusicOnDeselect); + } } else { selectedPart = null; _prevSelectedPart = null; @@ -457,7 +462,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } else { setState(() { ref.playbackType = MelodyReference_PlaybackType.disabled; - if (ref != null && ref.melodyId == selectedMelody.id) { + if (ref.melodyId == selectedMelody?.id) { recordingMelody = false; } }); @@ -541,8 +546,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { }); } - Part _prevSelectedPart; - Melody _prevSelectedMelody; + Part? _prevSelectedPart; + Melody? _prevSelectedMelody; _editMode() { BeatScratchPlugin.setPlaybackMode(Playback_Mode.section); @@ -651,7 +656,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool get _portraitPhoneUI => !_landscapePhoneUI && !_scalableUI; - BuildContext nativeDeviceOrientationReaderContext; + late BuildContext nativeDeviceOrientationReaderContext; NativeDeviceOrientation get _nativeOrientation { try { @@ -793,15 +798,17 @@ class _MyHomePageState extends State with TickerProviderStateMixin { double get horizontalSectionListHeight => showSections && !verticalSectionList ? 36 : 0; - ExportUI exportUI; - MessagesUI messagesUI; - UniverseViewUI universeViewUI; + late KeyboardVisibilityController keyboardVisibilityController; + late StreamSubscription keyboardVisbilitySubscription; + late ExportUI exportUI; + late MessagesUI messagesUI; + late UniverseViewUI universeViewUI; double get universeViewUIHeight => universeViewUI.height(context, keyboardHeight: _keyboardHeight, settingsHeight: _midiSettingsHeight); - BSMethod scrollToCurrentBeat; - BSMethod refreshUniverseData; - BSMethod bluetoothScan; - BSMethod duplicateCurrentScore; + late BSMethod scrollToCurrentBeat; + late BSMethod refreshUniverseData; + late BSMethod bluetoothScan; + late BSMethod duplicateCurrentScore; @override void initState() { @@ -840,16 +847,22 @@ class _MyHomePageState extends State with TickerProviderStateMixin { score = widget.initialScore; _currentSection = widget.initialScore.sections[0]; _scoreManager.doOpenScore = doOpenScore; - _scoreManager.loadPastebinScoreIntoUI(widget.pastebinCode, onFail: () { - messagesUI.sendMessage(message: "Failed to load URL!", isError: true); - }); - if (MyPlatform.isMobile) { - KeyboardVisibility.onChange.listen((bool visible) { + if (widget.pastebinCode != null) { + _scoreManager.loadPastebinScoreIntoUI(widget.pastebinCode!, onFail: () { + messagesUI.sendMessage(message: "Failed to load URL!", isError: true); + }); + } + keyboardVisibilityController = KeyboardVisibilityController(); + keyboardVisbilitySubscription = + keyboardVisibilityController.onChange.listen((bool visible) { + // print('Keyboard visibility update. Is visible: $visible'); + if (MyPlatform.isMobile) { setState(() { _softKeyboardVisible = visible; }); - }); - } + } + }); + // BeatScratchPlugin.createScore(_score); BeatScratchPlugin.onSectionSelected = (sectionId) { setState(() { @@ -899,10 +912,12 @@ class _MyHomePageState extends State with TickerProviderStateMixin { : null; RecordedSegmentQueue.updateRecordingMelody = BeatScratchPlugin.onRecordingMelodyUpdated; - keyboardPart = score.parts.firstWhere((part) => true, orElse: () => null); - colorboardPart = score.parts.firstWhere( - (part) => part.instrument.type == InstrumentType.harmonic, - orElse: () => null); + keyboardPart = score.parts.firstWhereOrNull( + (part) => true, + ); + colorboardPart = score.parts.firstWhereOrNull( + (part) => part.instrument.type == InstrumentType.harmonic, + ); colorboardNotesNotifier = ValueNotifier(Set()); keyboardNotesNotifier = ValueNotifier(Set()); @@ -1037,6 +1052,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { ), )) ?? false; + } else { + return true; } } @@ -2772,9 +2789,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { final match = RegExp( r"^(.*?)(\d*)\s*$", ).allMatches(section.name).first; - String prefix = match.group(1); + String prefix = match.group(1)!; prefix = prefix.trim(); - int number = int.tryParse(match.group(2)) ?? 1; + int number = int.tryParse(match.group(2)!) ?? 1; while (score.sections.any((s) => s.name == section.name)) { section.name = "$prefix ${++number}"; } @@ -3015,6 +3032,11 @@ class _MyHomePageState extends State with TickerProviderStateMixin { part: keyboardPart, height: _keyboardHeight, showConfiguration: _showKeyboardConfiguration, + hideConfiguration: () { + setState(() { + _showKeyboardConfiguration = false; + }); + }, sectionColor: sectionColor, pressedNotesNotifier: keyboardNotesNotifier, bluetoothControllerPressedNotes: bluetoothControllerPressedNotes, @@ -3042,6 +3064,12 @@ class _MyHomePageState extends State with TickerProviderStateMixin { part: colorboardPart, height: _colorboardHeight, showConfiguration: _showColorboardConfiguration, + hideConfiguration: () { + setState(() { + // showColorboard = false; + _showColorboardConfiguration = false; + }); + }, sectionColor: sectionColor, pressedNotesNotifier: colorboardNotesNotifier, distanceFromBottom: diff --git a/lib/messages/bs_message.dart b/lib/messages/bs_message.dart index b94511e6..a9f4f9ec 100644 --- a/lib/messages/bs_message.dart +++ b/lib/messages/bs_message.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; class BSMessage { - final String id; + final String? id; final Icon icon; final String message; final Duration timeout; bool visible = false; BSMessage({ - required this.id, + this.id, required this.message, this.timeout = const Duration(milliseconds: 500), required this.icon, diff --git a/lib/messages/messages_ui.dart b/lib/messages/messages_ui.dart index 9bdc3538..7a91b88c 100644 --- a/lib/messages/messages_ui.dart +++ b/lib/messages/messages_ui.dart @@ -23,7 +23,7 @@ class MessagesUI { color, timeout = const Duration(milliseconds: 5500), bool isError = false, - String messageId, + String? messageId, bool andSetState = false, }) { if (icon == null) { diff --git a/lib/music_preview/melody_preview.dart b/lib/music_preview/melody_preview.dart index f7f47bd8..98420282 100644 --- a/lib/music_preview/melody_preview.dart +++ b/lib/music_preview/melody_preview.dart @@ -16,10 +16,10 @@ class MelodyPreview extends StatefulWidget { final double scale; const MelodyPreview({ - Key key, - this.section, - this.melody, - this.part, + Key? key, + required this.section, + required this.melody, + required this.part, this.width = 300, this.height = 100, this.scale = 0.15, @@ -77,27 +77,25 @@ class MelodyPreview extends StatefulWidget { } class _MelodyPreviewState extends State { - String lastPreviewKey; - Score preview; - BSMethod notifyUpdate; + late String lastPreviewKey; + late Score preview; + late BSMethod notifyUpdate; String get previewKey => - "${widget.melody.id}-${widget.melody.hashCode}|${widget.part.id ?? "null"}|" + + "${widget.melody.id}-${widget.melody.hashCode}|${widget.part.id}|" + "${widget.section.id}-${widget.section.hashCode}"; @override initState() { super.initState(); - preview = melodyPreview(widget.melody ?? Melody(), widget.part ?? Part(), - widget.section ?? Section()); + preview = melodyPreview(widget.melody, widget.part, widget.section); notifyUpdate = BSMethod(); } @override Widget build(BuildContext context) { if (lastPreviewKey != previewKey) { - preview = melodyPreview(widget.melody ?? Melody(), widget.part ?? Part(), - widget.section ?? Section()); + preview = melodyPreview(widget.melody, widget.part, widget.section); lastPreviewKey = previewKey; notifyUpdate(); } diff --git a/lib/music_preview/part_preview.dart b/lib/music_preview/part_preview.dart index b58abad6..e56d18e6 100644 --- a/lib/music_preview/part_preview.dart +++ b/lib/music_preview/part_preview.dart @@ -14,10 +14,10 @@ class PartPreview extends StatefulWidget { final double scale; const PartPreview({ - Key key, - this.section, - this.score, - this.part, + Key? key, + required this.section, + required this.score, + required this.part, this.width = 300, this.height = 100, this.scale = 0.15, @@ -28,9 +28,9 @@ class PartPreview extends StatefulWidget { } class _PartPreviewState extends State { - String lastPreviewKey; - Score preview; - BSMethod notifyUpdate; + String? lastPreviewKey; + late Score preview; + late BSMethod notifyUpdate; String get previewKey => "${widget.section.id}-${widget.section.hashCode}"; diff --git a/lib/recording/recording.dart b/lib/recording/recording.dart index 25289a69..d080229a 100644 --- a/lib/recording/recording.dart +++ b/lib/recording/recording.dart @@ -12,11 +12,11 @@ import '../util/music_utils.dart'; /// are sent to this singleton queue for processing. class RecordedSegmentQueue { /// Gets the recording melody from your UI. Should be set in [State.initState] and [State.dispose]. - static Melody Function()? getRecordingMelody; + static Melody? Function()? getRecordingMelody; /// Should be set in [State.initState] and [State.dispose] for static Function(Melody)? updateRecordingMelody; - static Melody get recordingMelody => getRecordingMelody!.call(); + static Melody? get recordingMelody => getRecordingMelody?.call(); // static set recordingMelody(Melody melody) => updateRecordingMelody(melody); static final Queue segments = ListQueue(); static final BSValueMethod enabled = BSValueMethod(false) @@ -48,6 +48,8 @@ class RecordedSegmentQueue { static _processSegment(RecordedSegment segment) { if (segment.recordedData.isEmpty) return; final melody = recordingMelody; + if (melody == null) return; + RecordedSegment_RecordedBeat firstBeat = segment.beats.minBy((rb) => rb.timestamp.toInt()); RecordedSegment_RecordedBeat secondBeat = diff --git a/lib/storage/migrations.dart b/lib/storage/migrations.dart index e15bb731..c1cb5bdc 100644 --- a/lib/storage/migrations.dart +++ b/lib/storage/migrations.dart @@ -14,15 +14,15 @@ extension Migrations on Score { } _setBpmsOnSections() { - double firstSeenBpm; + double? firstSeenBpm; for (Section section in sections) { - if (section.tempo.bpm != null) { + if (section.tempo.bpm > 0) { firstSeenBpm = section.tempo.bpm; break; } } sections.forEach((section) { - if (section.tempo.bpm == null) { + if (section.tempo.bpm > 0) { section.tempo = Tempo()..bpm = firstSeenBpm ?? 123; } }); diff --git a/lib/storage/score_manager.dart b/lib/storage/score_manager.dart index 6a6bd5eb..a9fbfd31 100644 --- a/lib/storage/score_manager.dart +++ b/lib/storage/score_manager.dart @@ -26,9 +26,9 @@ class ScoreManager { static const String FROM_WEB = " (from Link)"; static const String UNIVERSE_SCORE = "Universe Score"; static const String FROM_UNIVERSE = " (from Universe)"; - Function(Score) doOpenScore; - Directory scoresDirectory; - SharedPreferences _prefs; + late Function(Score) doOpenScore; + late Directory scoresDirectory; + late SharedPreferences _prefs; String get currentScoreName => _prefs.getString('currentScoreName') ?? UNIVERSE_SCORE; @@ -41,13 +41,13 @@ class ScoreManager { List get scoreFiles { List result = scoresDirectory - ?.listSync() + .listSync() .where((f) => f.path.endsWith(".beatscratch")) .toList(); result .sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified)); return result; - return []; + // return []; } ScoreManager() { @@ -73,7 +73,7 @@ class ScoreManager { } } - createScore(String name, {Score score}) { + createScore(String name, {Score? score}) { score = score ?? defaultScore(); currentScoreName = name; saveCurrentScore(score); @@ -112,9 +112,9 @@ class ScoreManager { loadFromScoreUrl(String scoreUrl, {String newScoreDefaultFilename = PASTED_SCORE, String newScoreNameSuffix = FROM_CLIPBOARD, - Score currentScoreToSave, - VoidCallback onFail, - Function(String) onSuccess}) { + required Score currentScoreToSave, + VoidCallback? onFail, + Function(String)? onSuccess}) { print("ScoreURL=$scoreUrl"); scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#score='), ''); scoreUrl = scoreUrl.replaceFirst(new RegExp(r'http.*#/score/'), ''); @@ -123,7 +123,7 @@ class ScoreManager { if (scoreUrl.length < 10) { throw Exception("nope"); } - Score score = scoreFromUrlHashValue(scoreUrl); + Score score = scoreFromUrlHashValue(scoreUrl)!; if (score.sections.isEmpty) { throw Exception("nope"); } @@ -138,7 +138,7 @@ class ScoreManager { openScoreWithFilename( score, newScoreDefaultFilename); // side-effect: updates this.score _lastSuggestedScoreName = suggestedScoreName; - onSuccess.call(suggestedScoreName); + onSuccess?.call(suggestedScoreName); } catch (any) { loadPastebinScoreIntoUI(scoreUrl, newScoreDefaultFilename: newScoreDefaultFilename, @@ -149,8 +149,8 @@ class ScoreManager { } } - static String _lastSuggestedScoreName; - static String get lastSuggestedScoreName { + static String? _lastSuggestedScoreName; + static String? get lastSuggestedScoreName { final value = _lastSuggestedScoreName; _lastSuggestedScoreName = null; return value; @@ -161,7 +161,7 @@ class ScoreManager { } Future loadPastebinScore(String codeOrUrl, - {String titleOverride}) async { + {String? titleOverride}) async { final code = codeOrUrl.replaceFirst(new RegExp(r'http.*#/s/'), ''); http.Response response = await http.get( @@ -175,17 +175,17 @@ class ScoreManager { longUrl = longUrl.replaceFirst(new RegExp(r'http.*#score='), ''); longUrl = longUrl.replaceFirst(new RegExp(r'http.*#/score/'), ''); - Score score = scoreFromUrlHashValue(longUrl); - score.name = titleOverride; + Score score = scoreFromUrlHashValue(longUrl)!; + if (titleOverride != null) score.name = titleOverride; return score; } loadPastebinScoreIntoUI(String pastebinCode, {String newScoreDefaultFilename = PASTED_SCORE, String newScoreNameSuffix = FROM_CLIPBOARD, - Score currentScoreToSave, - VoidCallback onFail, - Function(String) onSuccess}) async { + Score? currentScoreToSave, + VoidCallback? onFail, + Function(String)? onSuccess}) async { try { Score score = await loadPastebinScore(pastebinCode); String scoreName = score.name ?? ""; @@ -196,15 +196,17 @@ class ScoreManager { suggestedScoreName += newScoreNameSuffix; } if (BeatScratchPlugin.supportsStorage) { - saveCurrentScore(currentScoreToSave); + if (currentScoreToSave != null) { + saveCurrentScore(currentScoreToSave); + } openScoreWithFilename(score, newScoreDefaultFilename); } else { doOpenScore(score); } - onSuccess.call(suggestedScoreName); + onSuccess?.call(suggestedScoreName); _lastSuggestedScoreName = suggestedScoreName; } catch (any) { - onFail.call(); + onFail?.call(); } } diff --git a/lib/universe_view/universe_view_ui.dart b/lib/universe_view/universe_view_ui.dart index f6f4001a..aa73a6a5 100644 --- a/lib/universe_view/universe_view_ui.dart +++ b/lib/universe_view/universe_view_ui.dart @@ -50,7 +50,7 @@ class UniverseViewUI { required Color sectionColor, required double keyboardHeight, required double settingsHeight, - required VoidCallback showDownloads, + VoidCallback? showDownloads, required double scorePickerWidth}) { double abbreviateAtWidth = 340; return AnimatedOpacity( diff --git a/pubspec.lock b/pubspec.lock index 6864026d..6426c2d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" base_x: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -154,10 +154,10 @@ packages: dependency: "direct main" description: name: flutter_keyboard_visibility - sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb" + sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "6.0.0" flutter_keyboard_visibility_linux: dependency: transitive description: @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -729,10 +729,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9e8ce007..42ddc74d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: flutter_reorderable_list: ^1.2.0 url_launcher: ^6.0.3 animated_list_plus: ^0.5.0 - flutter_keyboard_visibility: ^5.4.1 + flutter_keyboard_visibility: ^6.0.0 # aeyrium_sensor: ^1.0.7 sensors: ^2.0.3 # dart_midi: 1.0.1 @@ -55,13 +55,11 @@ dev_dependencies: flutter_test: sdk: flutter - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. From 39118a70c9ec98bfc034c8610723dfd316cb37d0 Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sat, 7 Jun 2025 08:50:53 -0400 Subject: [PATCH 07/11] more progress --- lib/beatscratch_plugin.dart | 6 +- lib/main.dart | 49 +++--- lib/music_preview/preview_renderer.dart | 11 +- lib/music_preview/score_preview.dart | 44 ++--- lib/music_preview/section_preview.dart | 12 +- lib/music_view/music_scroll_container.dart | 11 +- lib/music_view/music_system_painter.dart | 32 ++-- lib/music_view/music_toolbars.dart | 8 +- lib/music_view/music_view.dart | 6 +- lib/settings/tile_bluetooth.dart | 2 +- lib/settings/tile_controller.dart | 20 +-- lib/settings/tile_synth.dart | 4 +- lib/util/music_notation_theory.dart | 5 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 164 ++++++++++++++---- pubspec.yaml | 27 ++- 16 files changed, 260 insertions(+), 143 deletions(-) diff --git a/lib/beatscratch_plugin.dart b/lib/beatscratch_plugin.dart index be48ebf7..88c928e2 100644 --- a/lib/beatscratch_plugin.dart +++ b/lib/beatscratch_plugin.dart @@ -410,11 +410,11 @@ class BeatScratchPlugin { /// [Melody]. Implementation-wise: this is just done by passing the [Melody.id]. /// This applies to notes played either with a physical MIDI controller on /// the native side or from [sendMIDI] in the plugin. - static void setRecordingMelody(Melody melody) async { + static void setRecordingMelody(Melody? melody) async { if (kIsWeb) { - context.callMethod('setRecordingMelody', [melody.id]); + context.callMethod('setRecordingMelody', [melody?.id]); } else { - _channel.invokeMethod('setRecordingMelody', melody.id); + _channel.invokeMethod('setRecordingMelody', melody?.id); } } diff --git a/lib/main.dart b/lib/main.dart index 017173ca..e7637aef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1354,22 +1354,26 @@ class _MyHomePageState extends State with TickerProviderStateMixin { padding: EdgeInsets.zero, onPressed: _universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = - _universeManager.currentUniverseScoreFuture.likes; + if (scoreFuture == null) return; + bool? oldValue = scoreFuture.likes; setState(() { if (oldValue == true) { scoreFuture.likes = null; - scoreFuture.voteCount -= 1; + if (scoreFuture.voteCount != null) + scoreFuture.voteCount = + scoreFuture.voteCount! - 1; } else { scoreFuture.likes = true; - scoreFuture.voteCount += oldValue == null ? 1 : 2; + if (scoreFuture.voteCount != null) + scoreFuture.voteCount = scoreFuture.voteCount! + + (oldValue == null ? 1 : 2); } _universeManager.vote( - scoreFuture.fullName, scoreFuture.likes); + scoreFuture.fullName ?? '', scoreFuture.likes); }); } : null, - color: scoreFuture.likes == true + color: scoreFuture?.likes == true ? chromaticSteps[11] : Colors.transparent, child: Align( @@ -1379,7 +1383,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Icon(Icons.arrow_upward, color: _universeManager.isAuthenticated - ? scoreFuture.likes == true + ? scoreFuture?.likes == true ? chromaticSteps[11].textColor() : chromaticSteps[11] : musicForegroundColor.withOpacity(0.5)))), @@ -1389,7 +1393,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Align( alignment: Alignment.center, - child: Text(scoreFuture.voteCount.toString() ?? '', + child: Text(scoreFuture?.voteCount.toString() ?? '', textAlign: TextAlign.center, style: TextStyle( color: musicForegroundColor, @@ -1401,22 +1405,24 @@ class _MyHomePageState extends State with TickerProviderStateMixin { padding: EdgeInsets.zero, onPressed: _universeManager.redditUsername.isNotEmpty ? () { - bool oldValue = - _universeManager.currentUniverseScoreFuture.likes; + if (scoreFuture == null) return; + bool? oldValue = scoreFuture.likes; setState(() { if (oldValue == false) { scoreFuture.likes = null; - scoreFuture.voteCount += 1; + scoreFuture.voteCount = + scoreFuture.voteCount! + 1; } else { scoreFuture.likes = false; - scoreFuture.voteCount -= oldValue == null ? 1 : 2; + scoreFuture.voteCount = scoreFuture.voteCount! - + (oldValue == null ? 1 : 2); } _universeManager.vote( - scoreFuture.fullName, scoreFuture.likes); + scoreFuture.fullName ?? '', scoreFuture.likes); }); } : null, - color: scoreFuture.likes == false + color: scoreFuture?.likes == false ? chromaticSteps[10] : Colors.transparent, child: Align( @@ -1426,7 +1432,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { duration: animationDuration, child: Icon(Icons.arrow_downward, color: _universeManager.isAuthenticated - ? scoreFuture.likes == false + ? scoreFuture?.likes == false ? chromaticSteps[10].textColor() : chromaticSteps[10] : musicForegroundColor.withOpacity(0.5)))), @@ -1472,13 +1478,16 @@ class _MyHomePageState extends State with TickerProviderStateMixin { child: MyFlatButton( padding: EdgeInsets.zero, onPressed: () { + if (scoreFuture == null) return; + if (_appSettings.enableApollo) { launchURL( - scoreFuture.commentUrl - .replaceAll("https://", "apollo://"), + scoreFuture?.commentUrl + ?.replaceAll("https://", "apollo://") ?? + '', forceSafariVC: false); - } else { - launchURL(scoreFuture.commentUrl, forceSafariVC: false); + } else if (scoreFuture.commentUrl != null) { + launchURL(scoreFuture.commentUrl!, forceSafariVC: false); } }, child: Align( @@ -1726,7 +1735,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool bottom = false, }) { bool playing = BeatScratchPlugin.playing; - int tapInBeat = _tapInBeat; + int? tapInBeat = _tapInBeat; bool isDisplayed = (!vertical && !bottom && _tapInBarHeight != 0) || (vertical && _landscapeTapInBarWidth != 0) || (bottom && _bottomTapInBarHeight != 0); diff --git a/lib/music_preview/preview_renderer.dart b/lib/music_preview/preview_renderer.dart index a5bcc18f..09d8aaa4 100644 --- a/lib/music_preview/preview_renderer.dart +++ b/lib/music_preview/preview_renderer.dart @@ -30,7 +30,7 @@ class MusicPreviewRenderer { required this.renderSections, required this.renderPartNames, required this.musicViewMode, - this.renderColor}); + required this.renderColor}); MusicSystemPainter get painter { final parts = score.parts; @@ -51,6 +51,9 @@ class MusicPreviewRenderer { partTopOffsets: ValueNotifier(partTopOffsets), staffOffsets: ValueNotifier(staffOffsets), colorGuideOpacityNotifier: ValueNotifier(0), + tappedBeat: ValueNotifier(null), + tappedPart: ValueNotifier(null), + bluetoothControllerPressedNotes: ValueNotifier(Map()), colorblockOpacityNotifier: ValueNotifier( AppSettings.globalRenderingMode == RenderingMode.colorblock ? 1 : 0), notationOpacityNotifier: ValueNotifier( @@ -76,7 +79,7 @@ class MusicPreviewRenderer { double get maxWidth => (extraBeatsSpaceForClefs + score.beatCount) * beatWidth * scale; double get actualWidth => min(maxWidth, width); - Future get renderedScoreImage async { + Future get renderedScoreImage async { if (height < 1 || width < 1) { return null; } @@ -105,9 +108,9 @@ class MusicPreviewRenderer { return data; } - Future get renderedScoreImageData async { + Future get renderedScoreImageData async { final image = await renderedScoreImage; return Uint8List.sublistView( - await image.toByteData(format: ui.ImageByteFormat.png)); + (await image?.toByteData(format: ui.ImageByteFormat.png))!); } } diff --git a/lib/music_preview/score_preview.dart b/lib/music_preview/score_preview.dart index d03381b7..dc473727 100644 --- a/lib/music_preview/score_preview.dart +++ b/lib/music_preview/score_preview.dart @@ -23,17 +23,17 @@ class ScorePreview extends StatefulWidget { final double height; final double scale; final BSMethod notifyUpdate; - final Color renderColor; + final Color? renderColor; const ScorePreview(this.score, - {Key key, + {Key? key, this.width = 300, this.height = 100, this.scale = 0.15, this.musicViewMode = MusicViewMode.score, this.renderPartNames = true, this.renderSections = true, - this.notifyUpdate, + required this.notifyUpdate, this.renderColor}) : super(key: key); @@ -44,22 +44,22 @@ class ScorePreview extends StatefulWidget { enum _Thumbnail { a, b } class _ScorePreviewState extends State { - bool hasBuilt; - String _prevScoreId; - RenderingMode _prevRenderingMode; - double _prevScale, _prevWidth, _prevHeight; - Color _prevRenderColor; - _Thumbnail currentThumbnail; - Uint8List thumbnailA, thumbnailB; - - Uint8List get currentThumbnailData => + late bool hasBuilt; + late String _prevScoreId; + late RenderingMode _prevRenderingMode; + late double _prevScale, _prevWidth, _prevHeight; + late Color _prevRenderColor; + late _Thumbnail currentThumbnail; + Uint8List? thumbnailA, thumbnailB; + + Uint8List? get currentThumbnailData => currentThumbnail == _Thumbnail.a ? thumbnailA : thumbnailB; - set currentThumbnailData(Uint8List value) => currentThumbnail == _Thumbnail.a + set currentThumbnailData(Uint8List? value) => currentThumbnail == _Thumbnail.a ? thumbnailA = value : thumbnailB = value; - Uint8List get otherThumbnailData => + Uint8List? get otherThumbnailData => currentThumbnail == _Thumbnail.b ? thumbnailA : thumbnailB; - set otherThumbnailData(Uint8List value) => currentThumbnail == _Thumbnail.b + set otherThumbnailData(Uint8List? value) => currentThumbnail == _Thumbnail.b ? thumbnailA = value : thumbnailB = value; @@ -80,7 +80,7 @@ class _ScorePreviewState extends State { : 0 : 0; - double renderableWidth; + double renderableWidth = 1; bool disposed = false; @override initState() { @@ -126,11 +126,15 @@ class _ScorePreviewState extends State { AnimatedOpacity( opacity: thumbnailAOpacity, duration: animationDuration, - child: thumbnailA == null ? SizedBox() : Image.memory(thumbnailA)), + child: thumbnailA == null + ? SizedBox() + : Image.memory(thumbnailA ?? Uint8List(0))), AnimatedOpacity( opacity: thumbnailBOpacity, duration: animationDuration, - child: thumbnailB == null ? SizedBox() : Image.memory(thumbnailB)) + child: thumbnailB == null + ? SizedBox() + : Image.memory(thumbnailB ?? Uint8List(0))) ]), ); } @@ -142,7 +146,7 @@ class _ScorePreviewState extends State { storage: new InMemoryStorage(500)) ..loader = (key, oldValue) async => oldValue ?? - await MusicPreviewRenderer( + (await MusicPreviewRenderer( scoreData: key.arguments[0].writeToBuffer(), scale: key.arguments[1], width: key.arguments[2], @@ -151,7 +155,7 @@ class _ScorePreviewState extends State { renderPartNames: key.arguments[5], musicViewMode: key.arguments[6], renderColor: key.arguments[7], - ).renderedScoreImageData; + ).renderedScoreImageData)!; ArgumentList get renderingArguments => ArgumentList([ widget.score, diff --git a/lib/music_preview/section_preview.dart b/lib/music_preview/section_preview.dart index 783b2cc9..733fa700 100644 --- a/lib/music_preview/section_preview.dart +++ b/lib/music_preview/section_preview.dart @@ -15,9 +15,9 @@ class SectionPreview extends StatefulWidget { final double scale; const SectionPreview({ - Key key, - this.section, - this.score, + Key? key, + required this.section, + required this.score, this.width = 300, this.height = 100, this.scale = 0.15, @@ -28,9 +28,9 @@ class SectionPreview extends StatefulWidget { } class _SectionPreviewState extends State { - String lastPreviewKey; - Score preview; - BSMethod notifyUpdate; + String? lastPreviewKey; + late Score preview; + late BSMethod notifyUpdate; String get previewKey => "${widget.section.id}-${widget.section.hashCode}"; diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 6c1aa582..85628a7c 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -759,7 +759,7 @@ class _MusicScrollContainerState extends State var removedOffsets = staffOffsets.value.keys .where((id) => !widget.staves.any((staff) => staff.id == id)); removedOffsets.forEach((removedStaffId) { - Animation staffAnimation; + late Animation staffAnimation; staffAnimation = Tween( begin: staffOffsets.value[removedStaffId], end: 0) .animate( @@ -774,7 +774,7 @@ class _MusicScrollContainerState extends State double staffPosition = staffIndex * staffHeight; double initialStaffPosition = staffOffsets.value.putIfAbsent(staff.id, () => overallCanvasHeight()); - Animation staffAnimation; + late Animation staffAnimation; staffAnimation = Tween( begin: initialStaffPosition, end: staffPosition) .animate( @@ -788,7 +788,7 @@ class _MusicScrollContainerState extends State double partPosition = staffPosition; double initialPartPosition = partTopOffsets.value .putIfAbsent(part.id, () => overallCanvasHeight()); - Animation partAnimation; + late Animation partAnimation; partAnimation = Tween(begin: initialPartPosition, end: partPosition) .animate(CurvedAnimation( @@ -813,28 +813,25 @@ class _MusicScrollContainerState extends State double notationOpacityValue = (widget.renderingMode == RenderingMode.notation) ? 1 : 0; double sectionScaleValue = sectionsHeight != 0 ? 1 : 0; - Animation animation1; + late Animation animation1, animation2, animation3, animation4; animation1 = Tween( begin: colorblockOpacityNotifier.value, end: colorblockOpacityValue) .animate(animationController) ..addListener(() { colorblockOpacityNotifier.value = animation1.value; }); - Animation animation2; animation2 = Tween( begin: notationOpacityNotifier.value, end: notationOpacityValue) .animate(animationController) ..addListener(() { notationOpacityNotifier.value = animation2.value; }); - Animation animation3; animation3 = Tween(begin: sectionScaleNotifier.value, end: sectionScaleValue) .animate(animationController) ..addListener(() { sectionScaleNotifier.value = animation3.value; }); - Animation animation4; animation4 = Tween( begin: colorGuideOpacityNotifier.value, end: colorGuideOpacityValue) .animate(animationController) diff --git a/lib/music_view/music_system_painter.dart b/lib/music_view/music_system_painter.dart index 42b3d7eb..1278184c 100644 --- a/lib/music_view/music_system_painter.dart +++ b/lib/music_view/music_system_painter.dart @@ -21,7 +21,7 @@ import '../util/music_theory.dart'; class MusicSystemPainter extends CustomPainter { Paint _tickPaint = Paint()..style = PaintingStyle.fill; - final String focusedMelodyId; + final String? focusedMelodyId; final Score score; final Section section; final TransformationController transformationController; @@ -39,7 +39,7 @@ class MusicSystemPainter extends CustomPainter { final ValueNotifier> staves; final ValueNotifier> partTopOffsets, staffOffsets; final ValueNotifier sectionColor; - final ValueNotifier keyboardPart, colorboardPart, focusedPart; + final ValueNotifier keyboardPart, colorboardPart, focusedPart; final ValueNotifier tappedPart; final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; final bool isCurrentScore, isPreview, renderPartNames; @@ -87,7 +87,7 @@ class MusicSystemPainter extends CustomPainter { this.rescale = false, required this.visibleRect, required this.verticallyVisibleRect, - required this.focusedMelodyId, + this.focusedMelodyId, required this.colorblockOpacityNotifier, required this.notationOpacityNotifier, required this.isCurrentScore, @@ -232,7 +232,7 @@ class MusicSystemPainter extends CustomPainter { if (sectionIndex < score.sections.length) { candidate = score.sections[sectionIndex]; } else { - candidate = null; + // candidate = null; break; } } @@ -436,8 +436,8 @@ class MusicSystemPainter extends CustomPainter { opacity = 0; } } - _renderMelodyBeat(canvas, focusedMelody, melodyBounds, renderingSection, - renderingSectionBeat, true, opacity, renderQueue, + _renderMelodyBeat(canvas, focusedMelody ?? Melody(), melodyBounds, + renderingSection, renderingSectionBeat, true, opacity, renderQueue, renderLoopStarts: true); } @@ -473,14 +473,14 @@ class MusicSystemPainter extends CustomPainter { melodyBounds, Paint() ..style = PaintingStyle.fill - ..color = tappedPart.value.id == part.id && + ..color = tappedPart.value?.id == part.id && renderingBeat == tappedBeat.value ? sectionColor.value.withOpacity(0.12) : Colors.black12); } if (isCurrentScore && (renderingBeat == tappedBeat.value) && - tappedPart.value.id == part.id) { + tappedPart.value?.id == part.id) { canvas.drawRect( melodyBounds, Paint() @@ -540,7 +540,7 @@ class MusicSystemPainter extends CustomPainter { if (staff .getParts(score, staves.value) - .any((element) => element.id == focusedPart.value.id)) { + .any((element) => element.id == focusedPart.value?.id)) { Rect highlight = Rect.fromPoints( bounds.topLeft.translate(-bounds.width / 13, notationOpacityNotifier.value * bounds.height / 6), @@ -598,7 +598,7 @@ class MusicSystemPainter extends CustomPainter { int renderingSectionBeat, Iterable otherMelodiesOnStaff, MusicStaff staff, - {Paint backgroundPaint}) { + {Paint? backgroundPaint}) { canvas.drawRect( melodyBounds, backgroundPaint ?? Paint() @@ -606,9 +606,9 @@ class MusicSystemPainter extends CustomPainter { ..color = musicForegroundColor.withOpacity(0.26)); var staffParts = staff.getParts(score, staves.value); bool hasColorboardPart = - staffParts.any((part) => part.id == colorboardPart.value.id); + staffParts.any((part) => part.id == colorboardPart.value?.id); bool hasKeyboardPart = - staffParts.any((part) => part.id == keyboardPart.value.id); + staffParts.any((part) => part.id == keyboardPart.value?.id); if (hasColorboardPart || hasKeyboardPart) { _colorboardDummyMelody.setMidiDataFromSimpleMelody( {0: colorboardNotesNotifier.value.toList()}); @@ -629,7 +629,7 @@ class MusicSystemPainter extends CustomPainter { keyboardNotes.length.toDouble(); _keyboardDummyMelody.instrumentType = - keyboardPart.value.instrument.type ?? InstrumentType.harmonic; + keyboardPart.value?.instrument.type ?? InstrumentType.harmonic; if (hasColorboardPart) { _renderMelodyBeat( canvas, @@ -803,7 +803,7 @@ class MusicSystemPainter extends CustomPainter { final double startOffset = renderingBeat * beatWidth; double left = startOffset; double chordLeft = left; - Chord renderingChord; + Chord? renderingChord; while (left < visibleRect().right + beatWidth) { if (renderingBeat < 0) { @@ -821,7 +821,7 @@ class MusicSystemPainter extends CustomPainter { 1)) { Chord chordAtSubdivision = renderingHarmony.changeBefore(renderingSubdivision) ?? cChromatic; - if (renderingChord != chordAtSubdivision) { + if (renderingChord != null && renderingChord != chordAtSubdivision) { Rect renderingRect = Rect.fromLTRB(chordLeft, top, left, bottom); try { ColorGuide() @@ -855,7 +855,7 @@ class MusicSystemPainter extends CustomPainter { ..halfStepsOnScreen = 88 ..normalizedDevicePitch = 0 ..bounds = renderingRect - ..chord = renderingChord + ..chord = renderingChord! ..drawPadding = 0 ..nonRootPadding = 0 ..drawnColorGuideAlpha = colorGuideAlpha diff --git a/lib/music_view/music_toolbars.dart b/lib/music_view/music_toolbars.dart index b3e9b484..6df130df 100644 --- a/lib/music_view/music_toolbars.dart +++ b/lib/music_view/music_toolbars.dart @@ -508,15 +508,15 @@ class SectionToolbar extends StatefulWidget { final MusicViewMode musicViewMode; final Function(Section, String) setSectionName; final Function(Section) deleteSection; - final Function addPart; + final Function? addPart; final Function cloneCurrentSection; final bool editingSection; final Function(bool) setEditingSection; const SectionToolbar( - {Key key, - this.currentSection, - this.sectionColor, + {Key? key, + required this.currentSection, + required this.sectionColor, this.musicViewMode, this.setSectionName, this.deleteSection, diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index aea0ab33..2f7b5f44 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -61,7 +61,7 @@ class MusicView extends StatefulWidget { final Function(Part) selectOrDeselectPart; final Function(Melody) selectOrDeselectMelody; final Function(Part, Melody, bool) createMelody; - final Function addPart; + final Function? addPart; final Function cloneCurrentSection; final Color backgroundColor; final bool isCurrentScore; @@ -77,7 +77,7 @@ class MusicView extends StatefulWidget { required this.selectOrDeselectPart, required this.selectOrDeselectMelody, required this.melodyViewSizeFactor, - required this.addPart, + this.addPart, required this.cloneCurrentSection, required this.superSetState, required this.musicViewMode, @@ -1683,7 +1683,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { } double get sectionsHeight => widget.musicViewMode == MusicViewMode.score || - targetedScale < 2 * MusicScrollContainer.minScale + (targetedScale ?? 1) < 2 * MusicScrollContainer.minScale ? 30 : 0; diff --git a/lib/settings/tile_bluetooth.dart b/lib/settings/tile_bluetooth.dart index a89d5dde..7362fc8c 100644 --- a/lib/settings/tile_bluetooth.dart +++ b/lib/settings/tile_bluetooth.dart @@ -18,7 +18,7 @@ class BluetoothDeviceTile extends StatefulWidget { final ValueNotifier>> bluetoothControllerPressedNotes; const BluetoothDeviceTile( - {Key key, + {Key? key, required this.connected, required this.device, required this.sectionColor, diff --git a/lib/settings/tile_controller.dart b/lib/settings/tile_controller.dart index 070ea11c..830fd936 100644 --- a/lib/settings/tile_controller.dart +++ b/lib/settings/tile_controller.dart @@ -23,15 +23,15 @@ class MidiControllerTile extends StatelessWidget { final VoidCallback toggleColorboardConfig; const MidiControllerTile( - {Key key, - this.appSettings, - this.enableColorboard, - this.setColorboardEnabled, - this.scrollDirection, - this.midiController, - this.sectionColor, - this.toggleKeyboardConfig, - this.toggleColorboardConfig}) + {Key? key, + required this.appSettings, + required this.enableColorboard, + required this.setColorboardEnabled, + required this.scrollDirection, + required this.midiController, + required this.sectionColor, + required this.toggleKeyboardConfig, + required this.toggleColorboardConfig}) : super(key: key); @override Widget build(BuildContext context) { @@ -202,7 +202,7 @@ class MidiControllerTile extends StatelessWidget { value: appSettings.controllersReplacingKeyboard .contains(midiController.nameOrId), onChanged: (v) { - if (v) { + if (v == true) { appSettings.controllersReplacingKeyboard = appSettings.controllersReplacingKeyboard + [midiController.nameOrId]; diff --git a/lib/settings/tile_synth.dart b/lib/settings/tile_synth.dart index 3cde7312..9d299306 100644 --- a/lib/settings/tile_synth.dart +++ b/lib/settings/tile_synth.dart @@ -1,4 +1,3 @@ - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -15,7 +14,8 @@ class MidiSynthTile extends StatefulWidget { final Axis scrollDirection; final MidiSynthesizer midiSynthesizer; - const MidiSynthTile({Key key, this.scrollDirection, this.midiSynthesizer}) + const MidiSynthTile( + {Key? key, required this.scrollDirection, required this.midiSynthesizer}) : super(key: key); @override diff --git a/lib/util/music_notation_theory.dart b/lib/util/music_notation_theory.dart index 86e3a615..10772f79 100644 --- a/lib/util/music_notation_theory.dart +++ b/lib/util/music_notation_theory.dart @@ -170,7 +170,7 @@ abstract class MusicStaff { MusicStaff(); String get id; - Iterable getParts(Score score, List staffConfiguration); + Iterable getParts(Score score, Iterable staffConfiguration); @override bool operator ==(other) => other is MusicStaff && id == other.id; @@ -184,7 +184,8 @@ class PartStaff extends MusicStaff { @override String get id => "staff-part-${part.id}"; @override - Iterable getParts(Score score, List staffConfiguration) => + Iterable getParts( + Score score, Iterable staffConfiguration) => [part]; } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 977ff597..1830cc80 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,6 +10,7 @@ import package_info_plus import path_provider_foundation import share_plus import shared_preferences_foundation +import universal_ble import url_launcher_macos import webview_flutter_wkwebview @@ -19,6 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 6426c2d5..9ae643f7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,18 @@ packages: dependency: "direct main" description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.7" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" async: dependency: transitive description: @@ -41,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + bluez: + dependency: transitive + description: + name: bluez + sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" + url: "https://pub.dev" + source: hosted + version: "0.8.3" boolean_selector: dependency: transitive description: @@ -97,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" dcache: dependency: "direct main" description: @@ -202,10 +226,10 @@ packages: dependency: "direct main" description: name: flutter_midi_command - sha256: a74e9f15b397e2f9c1869629b58bbf125c52cab71189a4f393c6e0bd6f77c418 + sha256: bce9e83d3fb05aef275af83d65c53a40623735516ef1bdcefc0ba1ca5db1d89f url: "https://pub.dev" source: hosted - version: "0.4.17" + version: "0.5.3" flutter_midi_command_linux: dependency: transitive description: @@ -222,6 +246,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.3" + flutter_midi_command_windows: + dependency: transitive + description: + name: flutter_midi_command_windows + sha256: fd85c892d890f462487601e69228de261954e2cd8740f5396f5e3060d23ff097 + url: "https://pub.dev" + source: hosted + version: "0.1.1" flutter_reorderable_list: dependency: "direct main" description: @@ -235,6 +267,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_bluetooth: + dependency: transitive + description: + name: flutter_web_bluetooth + sha256: fcd03e2e5f82edcedcbc940f1b6a0635a50757374183254f447640886c53208e + url: "https://pub.dev" + source: hosted + version: "0.2.4" flutter_web_plugins: dependency: transitive description: flutter @@ -252,10 +292,10 @@ packages: dependency: "direct main" description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" http_parser: dependency: transitive description: @@ -264,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" leak_tracker: dependency: transitive description: @@ -288,6 +336,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -316,10 +372,10 @@ packages: dependency: "direct main" description: name: matrix4_transform - sha256: "6ddeaa2c0e1f5c3f3a197f552377570b3e54fa0b8bf48507728a216fc0fd78a6" + sha256: "1346e53517e3081d3e8362377be97e285e2bd348855c177eae2a18aa965cafa0" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "4.0.1" meta: dependency: transitive description: @@ -348,10 +404,10 @@ packages: dependency: "direct main" description: name: native_device_orientation - sha256: "744a03030fad5a332a54833cd34f1e2ee51ae9acf477b4ef85bacc8823af9937" + sha256: "0c330c068575e4be72cce5968ca479a3f8d5d1e5dfce7d89d5c13a1e943b338c" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "2.0.3" nested: dependency: transitive description: @@ -364,18 +420,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "8.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.2.0" path: dependency: transitive description: @@ -448,6 +504,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" platform: dependency: transitive description: @@ -464,14 +528,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" + source: hosted + version: "6.0.2" protobuf: dependency: "direct main" description: name: protobuf - sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" + sha256: "579fe5557eae58e3adca2e999e38f02441d8aa908703854a9e0a0f47fa857731" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.1.0" provider: dependency: "direct main" description: @@ -496,14 +568,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" - sensors: + sensors_plus: dependency: "direct main" description: - name: sensors - sha256: "69c10fe94a63dd7c6f5e6557366e5329a713bf6c45d885d95a56642dd8722e35" + name: sensors_plus + sha256: "905282c917c6bb731c242f928665c2ea15445aa491249dea9d98d7c79dc8fd39" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "6.1.1" + sensors_plus_platform_interface: + dependency: transitive + description: + name: sensors_plus_platform_interface + sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" + url: "https://pub.dev" + source: hosted + version: "2.0.1" share_plus: dependency: "direct main" description: @@ -589,6 +669,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" stack_trace: dependency: transitive description: @@ -645,6 +733,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + universal_ble: + dependency: transitive + description: + name: universal_ble + sha256: "50011255aa793589ccefb086ceead0f2eaddd30609a6f8b10ee4a0a548c3250e" + url: "https://pub.dev" + source: hosted + version: "0.9.11" url_launcher: dependency: "direct main" description: @@ -713,10 +809,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -745,34 +841,34 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: caf0f5a1012aa3c2d33c4215adc72dc1194bb59a2d3ed901f457965626805e66 + sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba url: "https://pub.dev" source: hosted - version: "4.11.0" + version: "4.13.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "6b0eae02b7604954b80ee9a29507ac38f5de74b712faa6fee33abc1cdedc1b21" + sha256: f6e6afef6e234801da77170f7a1847ded8450778caf2fe13979d140484be3678 url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.7.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd" + sha256: "7cb32b21825bd65569665c32bb00a34ded5779786d6201f5350979d2d529940d" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff + sha256: a3d461fe3467014e05f3ac4962e5fdde2a4bf44c561cb53e9ae5c586600fdbc3 url: "https://pub.dev" source: hosted - version: "3.20.0" + version: "3.22.0" win32: dependency: transitive description: @@ -789,6 +885,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: dart: ">=3.7.0 <4.0.0" flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 42ddc74d..9c382242 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,15 +6,14 @@ version: 1.7.5+480 environment: sdk: ">=2.17.1 <3.0.0" - # sdk: ">=2.6.0 <3.0.0" dependencies: flutter: sdk: flutter - http: ^1.1.0 - protobuf: ^3.0.0 - uuid: ^3.0.4 - package_info_plus: ^4.0.2 + http: ^1.4.0 + protobuf: ^4.1.0 + uuid: ^4.5.1 + package_info_plus: ^8.3.0 recase: ^4.1.0 # share: ^0.6.5+4 flutter_reorderable_list: ^1.2.0 @@ -22,34 +21,32 @@ dependencies: animated_list_plus: ^0.5.0 flutter_keyboard_visibility: ^6.0.0 # aeyrium_sensor: ^1.0.7 - sensors: ^2.0.3 + # sensors: ^2.0.3 # dart_midi: 1.0.1 quiver: ^3.0.1 path_drawing: 1.0.1 path_provider: ^2.0.2 shared_preferences: ^2.0.6 base_x: ^2.0.0 - archive: ^3.1.2 + archive: ^4.0.7 font_awesome_flutter: ^10.5.0 cupertino_icons: ^1.0.5 - fluro: "^2.0.3" + fluro: ^2.0.3 # flutter_appavailability: ^0.0.21 - native_device_orientation: ^1.1.4 - webview_flutter: ^4.2.2 + native_device_orientation: ^2.0.3 + webview_flutter: ^4.13.0 # flutter_icons: ^1.1.0 # flutter_blue: ^0.8.0 - # path: ../flutter_blue # flutter_reactive_ble: #^3.1.0 - # path: ../flutter_reactive_ble - flutter_midi_command: ^0.4.11 - # path: ../FlutterMidiCommand + flutter_midi_command: ^0.5.3 dcache: ^0.4.0 provider: ^6.0.2 - matrix4_transform: ^2.0.1 + matrix4_transform: ^4.0.1 share_plus: ^11.0.0 collection: ^1.19.1 appcheck: ^1.5.4+1 material_design_icons_flutter: ^7.0.7296 + sensors_plus: ^6.1.1 dev_dependencies: flutter_test: From c218df854e666f980e8df12f35f3300b5e8a6ccf Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 15 Jun 2025 18:30:54 -0400 Subject: [PATCH 08/11] down to 14 errors --- lib/edit_menu.dart | 14 +- lib/layers_view/layers_part_view.dart | 22 +-- lib/layers_view/layers_view.dart | 4 +- lib/layers_view/melody_reference_view.dart | 4 +- lib/main.dart | 23 ++-- lib/main_toolbars.dart | 29 ++-- lib/music_view/music_scroll_container.dart | 14 +- lib/music_view/music_toolbars.dart | 147 +++++++++++---------- lib/music_view/music_view.dart | 66 ++++----- pubspec.lock | 8 ++ pubspec.yaml | 2 + 11 files changed, 182 insertions(+), 151 deletions(-) diff --git a/lib/edit_menu.dart b/lib/edit_menu.dart index c61321a6..917d2f71 100644 --- a/lib/edit_menu.dart +++ b/lib/edit_menu.dart @@ -13,7 +13,7 @@ Future showEditMenu( {required BuildContext context, required RelativeRect position, required Score score, - required Part part, + required Part? part, Melody? selectedMelody, required MusicViewMode musicViewMode, required Section section, @@ -24,7 +24,8 @@ Future showEditMenu( } final melodies = - part.melodies.where((m) => section.referenceTo(m)?.isEnabled == true); + part?.melodies.where((m) => section.referenceTo(m)?.isEnabled == true) ?? + []; return showMenu( context: context, position: position, @@ -76,7 +77,7 @@ Future showEditMenu( value: null, child: Column(children: [ Row(children: [ - Text(part.midiName, + Text(part?.midiName ?? '', textAlign: TextAlign.left, // overflow: TextOverflow.ellipsis, softWrap: true, @@ -98,7 +99,7 @@ Future showEditMenu( enabled: false, ), ...melodies.map((m) => melodyMenuItem( - score, m, part, section, onSelected, m == selectedMelody)), + score, m, part!, section, onSelected, m == selectedMelody)), ]); } @@ -190,13 +191,14 @@ Material sectionPreview(Score score, Section section, ); } -PopupMenuItem partMenuItem(Score score, Part part, Section section, +PopupMenuItem partMenuItem(Score score, Part? part, Section section, Function(Object) onSelected, bool isSelected) { return PopupMenuItem( value: part, mouseCursor: SystemMouseCursors.basic, padding: EdgeInsets.zero, - child: partPreview(score, part, section, onSelected, isSelected), + child: + partPreview(score, part ?? Part(), section, onSelected, isSelected), enabled: true); } diff --git a/lib/layers_view/layers_part_view.dart b/lib/layers_view/layers_part_view.dart index 0fb337a8..44509a06 100644 --- a/lib/layers_view/layers_part_view.dart +++ b/lib/layers_view/layers_part_view.dart @@ -37,8 +37,8 @@ class LayersPartView extends StatefulWidget { final Function(Part) selectPart; final Color sectionColor; final Section currentSection; - final Melody selectedMelody; - final Part selectedPart; + final Melody? selectedMelody; + final Part? selectedPart; final Part colorboardPart; final Part keyboardPart; final Function(Part) setKeyboardPart; @@ -120,7 +120,7 @@ class _LayersPartViewState extends State { Section get currentSection => widget.currentSection; - Melody get selectedMelody => widget.selectedMelody; + Melody? get selectedMelody => widget.selectedMelody; get setReferenceVolume => widget.setReferenceVolume; @@ -287,15 +287,15 @@ class _LayersPartViewState extends State { textColor = isSelectedPart ? Colors.grey : Colors.white; } if (selectedMelody != null && - lastSelectedMelodyId != selectedMelody.id && + lastSelectedMelodyId != selectedMelody?.id && widget.autoScroll) { int indexOfMelody = - part.melodies.indexWhere((m) => m.id == selectedMelody.id); + part.melodies.indexWhere((m) => m.id == selectedMelody?.id); if (indexOfMelody >= 0) { requestScrollToTop(indexOfMelody); } } - lastSelectedMelodyId = selectedMelody.id; + lastSelectedMelodyId = selectedMelody?.id; setScrollToTopTimeout(); return frl.ReorderableList( onReorder: this._reorderCallback, @@ -442,7 +442,7 @@ class _LayersPartViewState extends State { })), ), ), - if (part.instrument.type == selectedMelody.instrumentType) + if (part.instrument.type == selectedMelody?.instrumentType) buildDuplicateButton( backgroundColor, textColor, @@ -584,7 +584,7 @@ class _LayersPartViewState extends State { expandedHeight: 50.0, flexibleSpace: MyFlatButton( onPressed: () { - final melody = widget.selectedMelody.bsCopy()..id = uuid.v4(); + final melody = widget.selectedMelody!.bsCopy()..id = uuid.v4(); bool melodyExists = melody.name.isNotEmpty && part.melodies.any((it) => it.name == melody.name); if (melodyExists && melody.name.isNotEmpty) { @@ -619,11 +619,11 @@ class _LayersPartViewState extends State { child: Transform.translate( offset: Offset(5, -1), child: Text( - selectedMelody.canonicalName, + selectedMelody?.canonicalName ?? '', maxLines: 1, overflow: TextOverflow.fade, style: TextStyle( - color: selectedMelody.name.isNotEmpty ?? false + color: selectedMelody?.name.isNotEmpty ?? false ? textColor : textColor.withOpacity(0.5), fontWeight: FontWeight.w300), @@ -635,7 +635,7 @@ class _LayersPartViewState extends State { child: Transform.translate( offset: Offset(5, 0), child: BeatsBadge( - beats: selectedMelody.beatCount, + beats: selectedMelody?.beatCount ?? 0, show: widget.showBeatCounts, ), )), diff --git a/lib/layers_view/layers_view.dart b/lib/layers_view/layers_view.dart index 23d46de3..31914ac2 100644 --- a/lib/layers_view/layers_view.dart +++ b/lib/layers_view/layers_view.dart @@ -27,7 +27,7 @@ class LayersView extends StatefulWidget { final Score score; final Color sectionColor; final Section currentSection; - final Melody selectedMelody; + final Melody? selectedMelody; final Function(Melody) selectMelody; final VoidCallback toggleEditingMelody; final VoidCallback hideMelodyView; @@ -36,7 +36,7 @@ class LayersView extends StatefulWidget { final Function(Part, double) setPartVolume; final Part colorboardPart; final Part keyboardPart; - final Part selectedPart; + final Part? selectedPart; final Function(Part) setKeyboardPart; final Function(Part) setColorboardPart; final Function(Part) selectPart; diff --git a/lib/layers_view/melody_reference_view.dart b/lib/layers_view/melody_reference_view.dart index 346ea478..7ab532e6 100644 --- a/lib/layers_view/melody_reference_view.dart +++ b/lib/layers_view/melody_reference_view.dart @@ -25,7 +25,7 @@ class MelodyReferenceView extends StatefulWidget { final Color sectionColor; final Section currentSection; final Part part; - final Melody selectedMelody; + final Melody? selectedMelody; final Function(Melody) selectMelody; final VoidCallback toggleEditingMelody; final VoidCallback hideMelodyView; @@ -72,7 +72,7 @@ class _MelodyReferenceViewState extends State MelodyReference get reference => widget.currentSection.referenceTo(widget.melody)!; - bool get isSelectedMelody => widget.melody.id == widget.selectedMelody.id; + bool get isSelectedMelody => widget.melody.id == widget.selectedMelody?.id; late AnimationController animationController; TextEditingController nameController = TextEditingController(); bool get allowEditName => widget.showMediumDetails; diff --git a/lib/main.dart b/lib/main.dart index e7637aef..55337494 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1735,13 +1735,13 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool bottom = false, }) { bool playing = BeatScratchPlugin.playing; - int? tapInBeat = _tapInBeat; + final int? tapInBeat = _tapInBeat; bool isDisplayed = (!vertical && !bottom && _tapInBarHeight != 0) || (vertical && _landscapeTapInBarWidth != 0) || (bottom && _bottomTapInBarHeight != 0); final double tapInFirstSize = !playing && (vertical) ? 42 : 0; final double tapInSecondSize = - !BeatScratchPlugin.playing && (_tapInBeat <= -2) ? 42 : 0; + !playing && (tapInBeat != null) && (tapInBeat <= -2) ? 42 : 0; final audioButtonColor = BeatScratchPlugin.metronomeEnabled ? sectionColor : Colors.grey; Widget tapInBarInstructions({bool withText = true, bool withIcon = true}) => @@ -2228,8 +2228,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { }, saveCurrentScore: saveCurrentScore, pasteScore: () async { - ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); - String scoreUrl = data.text; + ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + String scoreUrl = data?.text ?? ''; _scoreManager.loadFromScoreUrl(scoreUrl, currentScoreToSave: this.score, onFail: () { setState(() { @@ -2293,7 +2293,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } } else if (object is Section) { _selectOrDeselectMelody(selectedMelody); - _selectOrDeselectPart(selectedPart); + if (selectedPart != null) { + _selectOrDeselectPart(selectedPart!); + } musicViewMode = MusicViewMode.section; if (!interactionMode.isEdit) { _editMode(); @@ -2407,7 +2409,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { return result; } - saveCurrentScore({Duration delay}) { + saveCurrentScore({Duration? delay}) { final score = this.score; final scoreFile = _scoreManager.currentScoreFile; print("Saving score ${score.name} to ${scoreFile.path.split('/').last}..."); @@ -2426,7 +2428,10 @@ class _MyHomePageState extends State with TickerProviderStateMixin { })); } - Future.delayed(delay, doSave); + if (delay == null) { + Future.microtask(doSave); + } else + Future.delayed(delay, doSave); } double beatScratchToolbarHeight(BuildContext context) => @@ -2648,8 +2653,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { setPartVolume: _setPartVolume, setColorboardPart: _setColorboardPart, setKeyboardPart: _setKeyboardPart, - colorboardPart: colorboardPart, - keyboardPart: keyboardPart, + colorboardPart: colorboardPart ?? Part(), + keyboardPart: keyboardPart ?? Part(), editingMelody: recordingMelody, hideMelodyView: _hideMusicView, availableWidth: availableWidth, diff --git a/lib/main_toolbars.dart b/lib/main_toolbars.dart index fd5705c1..c7d51f85 100644 --- a/lib/main_toolbars.dart +++ b/lib/main_toolbars.dart @@ -31,7 +31,7 @@ class BeatScratchToolbar extends StatefulWidget { final UniverseManager universeManager; final Score score; final Section currentSection; - final Part currentPart; + final Part? currentPart; final ScoreManager scoreManager; final Function(ScorePickerMode) showScorePicker; final VoidCallback viewMode; @@ -56,10 +56,10 @@ class BeatScratchToolbar extends StatefulWidget { final bool vertical; final bool showSections; final bool verticalSections; - final Melody openMelody; - final Melody prevMelody; - final Part openPart; - final Part prevPart; + final Melody? openMelody; + final Melody? prevMelody; + final Part? openPart; + final Part? prevPart; final bool isMelodyViewOpen; final bool leftHalfOnly; final bool rightHalfOnly; @@ -133,7 +133,7 @@ class _BeatScratchToolbarState extends State bool get hasMelody => widget.openMelody != null || widget.prevMelody != null; bool get hasPart => !hasMelody || widget.prevPart != null; bool get hasDrumPart => - hasPart && (widget.openPart.isDrum ?? widget.prevPart.isDrum ?? false); + hasPart && (widget.openPart?.isDrum ?? widget.prevPart?.isDrum ?? false); @override void initState() { @@ -564,8 +564,7 @@ class _BeatScratchToolbarState extends State class _EditButton extends StatelessWidget { final Score score; final Section currentSection; - final Part currentPart; - final Part? openPart, prevPart; + final Part? openPart, prevPart, currentPart; final Melody? openMelody, prevMelody; final InteractionMode interactionMode; final MusicViewMode musicViewMode; @@ -773,12 +772,12 @@ class _EditButton extends StatelessWidget { class SecondToolbar extends StatefulWidget { final AppSettings appSettings; - final VoidCallback toggleKeyboard; - final VoidCallback toggleColorboard; - final VoidCallback toggleKeyboardConfiguration; - final VoidCallback toggleColorboardConfiguration; + final VoidCallback? toggleKeyboard; + final VoidCallback? toggleColorboard; + final VoidCallback? toggleKeyboardConfiguration; + final VoidCallback? toggleColorboardConfiguration; final VoidCallback toggleTempoConfiguration; - final VoidCallback tempoLongPress; + final VoidCallback? tempoLongPress; final VoidCallback rewind; final bool recordingMelody; final bool showKeyboard; @@ -1015,7 +1014,7 @@ class _SecondToolbarState extends State { onPressed: widget.toggleKeyboard, onLongPress: () { HapticFeedback.lightImpact(); - widget.toggleKeyboardConfiguration(); + widget.toggleKeyboardConfiguration?.call(); }, color: keyboardBackgroundColor, ))), @@ -1201,7 +1200,7 @@ class _SecondToolbarState extends State { onPressed: widget.toggleTempoConfiguration, onLongPress: () { HapticFeedback.lightImpact(); - widget.tempoLongPress(); + widget.tempoLongPress?.call(); }, )); } diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 85628a7c..0ae90de0 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -34,10 +34,10 @@ class MusicScrollContainer extends StatefulWidget { final ValueNotifier>> bluetoothControllerPressedNotes; final ValueNotifier highlightedBeat, focusedBeat, tappedBeat; final ValueNotifier tappedPart; - final ValueNotifier requestedScrollOffsetForScale; + final ValueNotifier requestedScrollOffsetForScale; final TransformationController transformationController; final ValueNotifier scaleUpdateNotifier; - final ValueNotifier targetScaleNotifier; + final ValueNotifier targetScaleNotifier; final bool showingSectionList; const MusicScrollContainer( @@ -129,7 +129,7 @@ class _MusicScrollContainerState extends State double get scaledStandardBeatWidth => beatWidth * scale; - double get targetScale => widget.targetScaleNotifier.value; + double? get targetScale => widget.targetScaleNotifier.value; double get targetBeatWidth => beatWidth; @@ -254,6 +254,14 @@ class _MusicScrollContainerState extends State } else { // interactiveController.reset(); final targetedMatrix = transformationController.value.clone(); + final targetScale = widget.targetScaleNotifier.value; + if (targetScale == + null /*|| + targetScale < minScale || + targetScale > maxScale*/ + ) { + return; + } targetedMatrix.scale( targetScale / scale, targetScale / scale, targetScale / scale); diff --git a/lib/music_view/music_toolbars.dart b/lib/music_view/music_toolbars.dart index 6df130df..f66255f0 100644 --- a/lib/music_view/music_toolbars.dart +++ b/lib/music_view/music_toolbars.dart @@ -13,7 +13,7 @@ import '../widget/my_buttons.dart'; class MelodyToolbar extends StatefulWidget { final MusicViewMode musicViewMode; final bool editingMelody; - final Melody melody; + final Melody? melody; final Section currentSection; final Color sectionColor; final Function(MelodyReference) toggleMelodyReference; @@ -23,18 +23,18 @@ class MelodyToolbar extends StatefulWidget { final Function(Melody) deleteMelody; const MelodyToolbar( - {Key key, - this.melody, - this.currentSection, - this.toggleMelodyReference, - this.setReferenceVolume, - this.editingMelody, - this.sectionColor, - this.toggleRecording, - this.backToPart, - this.setMelodyName, - this.musicViewMode, - this.deleteMelody}) + {Key? key, + required this.melody, + required this.currentSection, + required this.toggleMelodyReference, + required this.setReferenceVolume, + required this.editingMelody, + required this.sectionColor, + required this.toggleRecording, + required this.backToPart, + required this.setMelodyName, + required this.musicViewMode, + required this.deleteMelody}) : super(key: key); @override @@ -42,18 +42,19 @@ class MelodyToolbar extends StatefulWidget { } class MelodyToolbarState extends State { - bool _showVolume; - TextEditingController nameController; + late bool _showVolume; + late TextEditingController nameController; - MelodyReference get melodyReference => - widget.currentSection.referenceTo(widget.melody); + MelodyReference? get melodyReference => widget.melody != null + ? widget.currentSection.referenceTo(widget.melody!) + : null; bool get melodySelected => widget.melody != null; bool get melodyEnabled => - melodySelected && (melodyReference.isEnabled ?? false); - Melody confirmingDeleteFor; + melodySelected && (melodyReference?.isEnabled ?? false); + Melody? confirmingDeleteFor; bool get isConfirmingDelete => confirmingDeleteFor == widget.melody; bool get showVolume => - (melodyReference.isEnabled == true) && + (melodyReference?.isEnabled == true) && (/*context.isTablet ||*/ _showVolume); @override @@ -75,13 +76,13 @@ class MelodyToolbarState extends State { if (context.isTabletOrLandscapey) { width = width / 2; } - _showVolume &= (melodyReference.isEnabled == true) && !isConfirmingDelete; + _showVolume &= (melodyReference?.isEnabled == true) && !isConfirmingDelete; if (confirmingDeleteFor != widget.melody) { confirmingDeleteFor = null; } nameController.value = - nameController.value.copyWith(text: widget.melody.name ?? ""); + nameController.value.copyWith(text: widget.melody?.name ?? ""); return Container( // color: Colors.white, @@ -95,9 +96,11 @@ class MelodyToolbarState extends State { textCapitalization: TextCapitalization.words, onChanged: (melodySelected) ? (value) { - widget.melody.name = value; - widget.setMelodyName( - widget.melody, widget.melody.name); + final melody = widget.melody; + if (melody == null) return; + + melody.name = value; + widget.setMelodyName(melody, melody.name); // BeatScratchPlugin.updateMelody(widget.melody); } : null, @@ -106,7 +109,7 @@ class MelodyToolbarState extends State { // }, decoration: InputDecoration( border: InputBorder.none, - hintText: (melodySelected) ? widget.melody.idName : "", + hintText: (melodySelected) ? widget.melody?.idName : "", )) : Text(""))), // AnimatedContainer( @@ -157,13 +160,13 @@ class MelodyToolbarState extends State { height: 36, padding: EdgeInsets.zero, child: MySlider( - value: melodyReference.volume ?? 0, + value: melodyReference?.volume ?? 0, activeColor: (melodyReference != null) ? widget.sectionColor : Colors.grey, - onChanged: (melodyReference.isEnabled != true) + onChanged: (melodyReference?.isEnabled != true) ? null : (value) { - widget.setReferenceVolume(melodyReference, value); + widget.setReferenceVolume(melodyReference!, value); }), ), ), @@ -175,10 +178,10 @@ class MelodyToolbarState extends State { child: MyRaisedButton( onPressed: melodySelected ? () { - widget.toggleMelodyReference(melodyReference); + widget.toggleMelodyReference(melodyReference!); } : null, - onLongPress: (melodyReference.isEnabled == true) + onLongPress: (melodyReference?.isEnabled == true) ? () { setState(() { _showVolume = !_showVolume; @@ -211,7 +214,7 @@ class MelodyToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - widget.deleteMelody(confirmingDeleteFor); + widget.deleteMelody(confirmingDeleteFor!); confirmingDeleteFor = null; }); }, @@ -242,12 +245,14 @@ class MelodyToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - if (widget.melody.name.isEmpty != false && - (widget.melody.midiData.data.isEmpty || - widget.melody.midiData.data.values - .where((mc) => mc.data.length != 0) - .isEmpty)) { - widget.deleteMelody(widget.melody); + if (widget.melody?.name.isEmpty != false && + (widget.melody?.midiData.data.isEmpty ?? + false || + (widget.melody?.midiData.data.values + .where((mc) => mc.data.length != 0) + .isEmpty ?? + false))) { + widget.deleteMelody(widget.melody!); } else { confirmingDeleteFor = widget.melody; } @@ -266,7 +271,7 @@ class MelodyToolbarState extends State { class PartToolbar extends StatefulWidget { final Color sectionColor; - final Part part; + final Part? part; final Function(Part) setKeyboardPart; final Function(Part) setColorboardPart; final Part colorboardPart; @@ -278,19 +283,19 @@ class PartToolbar extends StatefulWidget { final bool enableColorboard; const PartToolbar( - {Key key, - this.part, - this.setKeyboardPart, - this.setColorboardPart, - this.colorboardPart, - this.keyboardPart, - this.deletePart, - this.configuringPart, - this.browsingPartMelodies, - this.toggleConfiguringPart, - this.sectionColor, - this.enableColorboard, - this.toggleBrowsingPartMelodies}) + {Key? key, + required this.part, + required this.setKeyboardPart, + required this.setColorboardPart, + required this.colorboardPart, + required this.keyboardPart, + required this.deletePart, + required this.configuringPart, + required this.browsingPartMelodies, + required this.toggleConfiguringPart, + required this.sectionColor, + required this.enableColorboard, + required this.toggleBrowsingPartMelodies}) : super(key: key); @override @@ -298,7 +303,7 @@ class PartToolbar extends StatefulWidget { } class PartToolbarState extends State { - Part confirmingDeleteFor; + Part? confirmingDeleteFor; bool get isConfirmingDelete => confirmingDeleteFor == widget.part; @@ -311,7 +316,7 @@ class PartToolbarState extends State { confirmingDeleteFor = null; } return Container( - key: Key("part-toolbar-${widget.part.id}"), + key: Key("part-toolbar-${widget.part?.id}"), child: Row(children: [ AnimatedContainer( duration: animationDuration, @@ -332,7 +337,7 @@ class PartToolbarState extends State { Expanded( child: Padding( padding: EdgeInsets.only(left: 5), - child: Text((widget.part != null) ? widget.part.midiName : "", + child: Text((widget.part != null) ? widget.part!.midiName : "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -373,9 +378,9 @@ class PartToolbarState extends State { height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( - onPressed: (widget.part.instrument.type != InstrumentType.drum) + onPressed: (widget.part!.instrument.type != InstrumentType.drum) ? () { - widget.setColorboardPart(widget.part); + widget.setColorboardPart(widget.part!); } : null, padding: EdgeInsets.zero, @@ -388,7 +393,7 @@ class PartToolbarState extends State { alignment: Alignment.bottomRight, child: AnimatedOpacity( duration: animationDuration, - opacity: (widget.part.instrument.type != + opacity: (widget.part!.instrument.type != InstrumentType.drum) ? 1 : 0.25, @@ -454,7 +459,7 @@ class PartToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - widget.deletePart(widget.part); + widget.deletePart(widget.part!); confirmingDeleteFor = null; }); }, @@ -517,14 +522,14 @@ class SectionToolbar extends StatefulWidget { {Key? key, required this.currentSection, required this.sectionColor, - this.musicViewMode, - this.setSectionName, - this.deleteSection, - this.canDeleteSection, - this.editingSection, - this.addPart, - this.cloneCurrentSection, - this.setEditingSection}) + required this.musicViewMode, + required this.setSectionName, + required this.deleteSection, + required this.canDeleteSection, + required this.editingSection, + required this.addPart, + required this.cloneCurrentSection, + required this.setEditingSection}) : super(key: key); @override @@ -532,7 +537,7 @@ class SectionToolbar extends StatefulWidget { } class SectionToolbarState extends State { - Section confirmingDeleteFor; + Section? confirmingDeleteFor; bool get isConfirmingDelete => confirmingDeleteFor == widget.currentSection; @@ -611,7 +616,7 @@ class SectionToolbarState extends State { height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( - onPressed: widget.addPart, + onPressed: widget.addPart as VoidCallback?, padding: EdgeInsets.zero, child: AnimatedOpacity( duration: animationDuration, @@ -635,7 +640,7 @@ class SectionToolbarState extends State { height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( - onPressed: widget.cloneCurrentSection, + onPressed: widget.cloneCurrentSection as VoidCallback, padding: EdgeInsets.zero, child: AnimatedOpacity( duration: animationDuration, @@ -663,7 +668,7 @@ class SectionToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - widget.deleteSection(confirmingDeleteFor); + widget.deleteSection(confirmingDeleteFor!); confirmingDeleteFor = null; }); }, diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index 2f7b5f44..7c50ff52 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -17,6 +17,8 @@ import '../ui_models.dart'; import '../util/music_notation_theory.dart'; import '../util/music_theory.dart'; import '../util/util.dart'; +import "package:flutter_feather_icons/flutter_feather_icons.dart"; + import '../widget/incrementable_value.dart'; import '../widget/my_buttons.dart'; import 'part_instrument_picker.dart'; @@ -40,7 +42,7 @@ class MusicView extends StatefulWidget { keyboardNotesNotifier; final ValueNotifier>> bluetoothControllerPressedNotes; final Melody melody; - final Part part; + final Part? part; final Color sectionColor; final VoidCallback toggleSplitMode, closeMelodyView, toggleRecording; final Function(VoidCallback) superSetState; @@ -51,7 +53,7 @@ class MusicView extends StatefulWidget { final Function(Section, String) setSectionName; final bool recordingMelody; final Function(Part) setKeyboardPart, setColorboardPart; - final Part keyboardPart, colorboardPart; + final Part? keyboardPart, colorboardPart; final Function(Part) deletePart; final Function(Melody) deleteMelody; final Function(Section) deleteSection; @@ -541,7 +543,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { : (widget.musicViewMode == MusicViewMode.melody) ? Colors.white : (widget.musicViewMode == MusicViewMode.part) - ? ((widget.part.instrument.type == + ? ((widget.part?.instrument.type == InstrumentType.drum) ? Colors.brown : Colors.grey) @@ -835,7 +837,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { duration: animationDuration, opacity: widget.musicViewMode == MusicViewMode.part ? 1 : 0, child: AnimatedContainer( - color: widget.part.instrument.type == InstrumentType.drum + color: widget.part?.instrument.type == InstrumentType.drum ? Colors.brown : Colors.grey, duration: animationDuration, @@ -846,7 +848,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { sectionColor: widget.sectionColor, score: widget.score, currentSection: widget.currentSection, - part: widget.part, + part: widget.part ?? Part(), browsingMelodies: isBrowsingPartMelodies, selectOrDeselectMelody: widget.selectOrDeselectMelody, createMelody: widget.createMelody, @@ -861,7 +863,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { : 0, child: AnimatedContainer( duration: animationDuration, - color: widget.part.instrument.type == InstrumentType.drum + color: widget.part?.instrument.type == InstrumentType.drum ? Colors.brown : Colors.grey, height: (widget.musicViewMode == MusicViewMode.part && @@ -1258,19 +1260,19 @@ class _MusicViewState extends State with TickerProviderStateMixin { handleZoomAlign() { return; - if (autoZoomAlign) { - final double x = targetedScale, - // y = targetedScale, - w = widget.width, - numberOfBeatsOnScreen = w / (x * beatWidth), - targetNumberOfBeatsOnScreen = numberOfBeatsOnScreen.roundToDouble(), - newXScale = w / (targetNumberOfBeatsOnScreen * beatWidth); - targetedScale = newXScale; - // scale = newXScale; - } + // if (autoZoomAlign) { + // final double x = targetedScale, + // // y = targetedScale, + // w = widget.width, + // numberOfBeatsOnScreen = w / (x * beatWidth), + // targetNumberOfBeatsOnScreen = numberOfBeatsOnScreen.roundToDouble(), + // newXScale = w / (targetNumberOfBeatsOnScreen * beatWidth); + // targetedScale = newXScale; + // // scale = newXScale; + // } } - Widget autoFocusButton({bool visible}) { + Widget autoFocusButton({required bool visible}) { return MusicActionButton( child: Stack(children: [ Transform.translate( @@ -1330,7 +1332,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { }); } - Widget autoZoomAlignButton({bool visible}) { + Widget autoZoomAlignButton({required bool visible}) { return MusicActionButton( child: Stack(children: [ Transform.translate( @@ -1348,7 +1350,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { duration: animationDuration, opacity: !autoZoomAlign ? 1 : 0, child: Icon( - Feather.move, + FeatherIcons.move, color: Colors.grey, ), ), @@ -1367,7 +1369,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { duration: animationDuration, opacity: autoZoomAlign ? 1 : 0, child: Icon( - Feather.move, + FeatherIcons.move, color: Colors.white, ), ), @@ -1395,11 +1397,11 @@ class _MusicViewState extends State with TickerProviderStateMixin { Widget zoomButton() { final zoomIncrement = .01; final bigDecrementIcon = - (targetedScale > alignedScale || scale > alignedScale) + (targetedScale! > alignedScale || scale > alignedScale) ? Icons.expand : FontAwesomeIcons.compressArrowsAlt; final bigDecrementAction = - (targetedScale > alignedScale || scale > alignedScale) + (targetedScale! > alignedScale || scale > alignedScale) ? () { setState(() { _aligned = true; @@ -1411,7 +1413,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { }); }); } - : (targetedScale > minScale || scale > minScale) + : (targetedScale! > minScale || scale > minScale) ? () { setState(() { minimize(); @@ -1419,11 +1421,11 @@ class _MusicViewState extends State with TickerProviderStateMixin { } : null; final bigIncrementIcon = - (targetedScale >= alignedScale || scale >= alignedScale) + (targetedScale! >= alignedScale || scale >= alignedScale) ? FontAwesomeIcons.expandArrowsAlt : Icons.expand; final bigIncrementAction = - (targetedScale < alignedScale || scale < alignedScale) + (targetedScale! < alignedScale || scale < alignedScale) ? () { setState(() { _aligned = true; @@ -1436,8 +1438,8 @@ class _MusicViewState extends State with TickerProviderStateMixin { }); }); } - : (targetedScale < partAlignedScale || scale < partAlignedScale) && - !targetedScale.roughlyEquals(partAlignedScale) && + : (targetedScale! < partAlignedScale || scale < partAlignedScale) && + !targetedScale!.roughlyEquals(partAlignedScale) && widget.musicViewMode != MusicViewMode.section ? () { setState(() { @@ -1478,7 +1480,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { musicForegroundColor.withOpacity(0.54)))), Transform.translate( offset: Offset(2, 20), - child: Text(scaleText(targetedScale), + child: Text(scaleText(targetedScale!), style: TextStyle( fontWeight: FontWeight.w800, fontSize: 12, @@ -1500,7 +1502,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { incrementIcon: Icons.zoom_in, decrementIcon: Icons.zoom_out, incrementDistance: 1, - onIncrement: (targetedScale < maxScale || scale < maxScale) + onIncrement: (targetedScale! < maxScale || scale < maxScale) ? () { _ignoreNextScale = true; _aligned = false; @@ -1508,12 +1510,12 @@ class _MusicViewState extends State with TickerProviderStateMixin { setState(() { print("zoomIn: scale=$scale, targetedScale=$targetedScale"); targetedScale = - min(maxScale, targetedScale + zoomIncrement); + min(maxScale, targetedScale! + zoomIncrement); // print("zoomIn done; targetedScale=$targetXScale, scale=$targetYScale"); }); } : null, - onDecrement: (targetedScale > minScale || scale > minScale) + onDecrement: (targetedScale! > minScale || scale > minScale) ? () { _ignoreNextScale = true; _aligned = false; @@ -1522,7 +1524,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { print( "zoomOut: scale=$scale, targetedScale=$targetedScale"); targetedScale = - max(minScale, targetedScale - zoomIncrement); + max(minScale, targetedScale! - zoomIncrement); // print("zoomOut done; targetedScale=$targetedScale, scale=$scale"); }); } diff --git a/pubspec.lock b/pubspec.lock index 9ae643f7..aa08a158 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -174,6 +174,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_feather_icons: + dependency: "direct main" + description: + name: flutter_feather_icons + sha256: b33b9c276fc8108254632da6644cf01f71af6c17fbfb26e136a86945f5ff9b67 + url: "https://pub.dev" + source: hosted + version: "2.0.0+1" flutter_keyboard_visibility: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 9c382242..e139e22d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: font_awesome_flutter: ^10.5.0 cupertino_icons: ^1.0.5 fluro: ^2.0.3 + flutter_feather_icons: ^2.0.0 + # flutter_appavailability: ^0.0.21 native_device_orientation: ^2.0.3 webview_flutter: ^4.13.0 From 7afff7c90bf016f16eeb1ef0e0958cd34ed42d68 Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sat, 28 Jun 2025 16:36:45 -0400 Subject: [PATCH 09/11] oh fuck all the things are fixed --- lib/main.dart | 49 ++++++++++++---------- lib/music_view/melody_editing_toolbar.dart | 2 +- lib/music_view/music_scroll_container.dart | 4 +- lib/music_view/music_view.dart | 11 ++--- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 55337494..b3406622 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -264,22 +264,23 @@ class _MyHomePageState extends State with TickerProviderStateMixin { bool showColorboard = false; bool _showColorboardConfiguration = false; - Part? _keyboardPart; + Part _keyboardPart = Part(); - Part? get keyboardPart => _keyboardPart; + Part get keyboardPart => _keyboardPart; - set keyboardPart(Part? part) { + set keyboardPart(Part part) { _keyboardPart = part; - if (part != null) BeatScratchPlugin.setKeyboardPart(part); + // if (part != null) + BeatScratchPlugin.setKeyboardPart(part); } - Part? _colorboardPart; + Part _colorboardPart = Part(); - Part? get colorboardPart => _colorboardPart; + Part get colorboardPart => _colorboardPart; - set colorboardPart(Part? part) { + set colorboardPart(Part part) { _colorboardPart = part; -// BeatScratchPlugin.setColorboardPart(part); + // BeatScratchPlugin.setColorboardPart(part); } late ValueNotifier> colorboardNotesNotifier; @@ -347,21 +348,21 @@ class _MyHomePageState extends State with TickerProviderStateMixin { _setKeyboardPart(Part part) { setState(() { - bool wasAssignedByPartCreation = keyboardPart == null; + // bool wasAssignedByPartCreation = keyboardPart == null; keyboardPart = part; - if (!wasAssignedByPartCreation && !hasPrioritizedMIDIController) { - showKeyboard = true; - } + // if (!wasAssignedByPartCreation && !hasPrioritizedMIDIController) { + // showKeyboard = true; + // } }); } _setColorboardPart(Part part) { setState(() { - bool wasAssignedByPartCreation = colorboardPart == null; + // bool wasAssignedByPartCreation = colorboardPart == null; colorboardPart = part; - if (!wasAssignedByPartCreation) { - showColorboard = true; - } + // if (!wasAssignedByPartCreation) { + // showColorboard = true; + // } }); } @@ -384,7 +385,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set selectedPart(Part? selectedPart) { _selectedPart = selectedPart; - keyboardPart = selectedPart; + if (selectedPart != null) keyboardPart = selectedPart; } Part? _viewingPart; @@ -393,7 +394,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { set viewingPart(Part? viewingPart) { _viewingPart = viewingPart; - keyboardPart = viewingPart; + if (viewingPart != null) keyboardPart = viewingPart; } List _sectionLists = []; @@ -913,11 +914,13 @@ class _MyHomePageState extends State with TickerProviderStateMixin { RecordedSegmentQueue.updateRecordingMelody = BeatScratchPlugin.onRecordingMelodyUpdated; keyboardPart = score.parts.firstWhereOrNull( - (part) => true, - ); + (part) => true, + ) ?? + Part(); colorboardPart = score.parts.firstWhereOrNull( - (part) => part.instrument.type == InstrumentType.harmonic, - ); + (part) => part.instrument.type == InstrumentType.harmonic, + ) ?? + Part(); colorboardNotesNotifier = ValueNotifier(Set()); keyboardNotesNotifier = ValueNotifier(Set()); @@ -2716,7 +2719,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { this.keyboardPart = score.parts.first; } if (part == this.colorboardPart) { - this.colorboardPart = null; + this.colorboardPart = score.parts.first; } score.sections.forEach((section) { section.melodies.removeWhere( diff --git a/lib/music_view/melody_editing_toolbar.dart b/lib/music_view/melody_editing_toolbar.dart index a7fa7779..c8732a0c 100644 --- a/lib/music_view/melody_editing_toolbar.dart +++ b/lib/music_view/melody_editing_toolbar.dart @@ -14,7 +14,7 @@ import '../widget/incrementable_value.dart'; import '../widget/my_buttons.dart'; class MelodyEditingToolbar extends StatefulWidget { - final String melodyId; + final String? melodyId; final Score score; final Color sectionColor; final Section currentSection; diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 0ae90de0..94b3b783 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -21,7 +21,7 @@ class MusicScrollContainer extends StatefulWidget { final Score score; final Section currentSection; final Color sectionColor; - final Melody focusedMelody; + final Melody? focusedMelody; final RenderingMode renderingMode; final List staves; final Part focusedPart, keyboardPart, colorboardPart; @@ -568,7 +568,7 @@ class _MusicScrollContainerState extends State section: widget.currentSection, musicViewMode: widget.musicViewMode, transformationController: transformationController, - focusedMelodyId: widget.focusedMelody.id, + focusedMelodyId: widget.focusedMelody?.id, staves: stavesNotifier, partTopOffsets: partTopOffsets, staffOffsets: staffOffsets, diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index 7c50ff52..26683187 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -41,8 +41,8 @@ class MusicView extends StatefulWidget { final ValueNotifier> colorboardNotesNotifier, keyboardNotesNotifier; final ValueNotifier>> bluetoothControllerPressedNotes; - final Melody melody; - final Part? part; + final Melody? melody; + final Part part; final Color sectionColor; final VoidCallback toggleSplitMode, closeMelodyView, toggleRecording; final Function(VoidCallback) superSetState; @@ -53,7 +53,7 @@ class MusicView extends StatefulWidget { final Function(Section, String) setSectionName; final bool recordingMelody; final Function(Part) setKeyboardPart, setColorboardPart; - final Part? keyboardPart, colorboardPart; + final Part keyboardPart, colorboardPart; final Function(Part) deletePart; final Function(Melody) deleteMelody; final Function(Section) deleteSection; @@ -480,7 +480,8 @@ class _MusicViewState extends State with TickerProviderStateMixin { bool get recordingMelody => widget.recordingMelody && - widget.currentSection.referenceTo(widget.melody).isEnabled; + widget.melody != null && + widget.currentSection.referenceTo(widget.melody!).isEnabled; set ignoreDragEvents(value) { _ignoreDragEvents = value; @@ -827,7 +828,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { recordingMelody: recordingMelody, sectionColor: widget.sectionColor, score: widget.score, - melodyId: widget.melody.id, + melodyId: widget.melody?.id, currentSection: widget.currentSection, highlightedBeat: highlightedBeat, setReferenceVolume: widget.setReferenceVolume, From 07ef6deb4a78f869cbf6f863b44bd19dd16f3cee Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sat, 28 Jun 2025 17:31:03 -0400 Subject: [PATCH 10/11] various stuff with macos app --- macos/Podfile.lock | 48 +++++++++++++------ macos/Runner.xcodeproj/project.pbxproj | 12 +++-- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- macos/Runner/AppDelegate.swift | 2 +- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 1080077b..6ec9d3a2 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -2,26 +2,37 @@ PODS: - flutter_midi_command (0.0.1): - FlutterMacOS - FlutterMacOS (1.0.0) - - package_info_plus_macos (0.0.1): + - package_info_plus (0.0.1): - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - SwiftProtobuf (1.13.0) + - universal_ble (0.0.1): + - Flutter + - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS + - webview_flutter_wkwebview (0.0.1): + - Flutter + - FlutterMacOS DEPENDENCIES: - flutter_midi_command (from `Flutter/ephemeral/.symlinks/plugins/flutter_midi_command/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - SwiftProtobuf + - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - webview_flutter_wkwebview (from `Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin`) SPEC REPOS: trunk: @@ -32,24 +43,33 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/flutter_midi_command/macos FlutterMacOS: :path: Flutter/ephemeral - package_info_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + universal_ble: + :path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + webview_flutter_wkwebview: + :path: Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin SPEC CHECKSUMS: - flutter_midi_command: c1a74de594e48e8fffd195a2ed5746161d507a48 + flutter_midi_command: c7517347a1acc8e4c7d4e9fa9809b3e87bbfd2b8 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c - path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 - shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 SwiftProtobuf: fd4693388a96c8c2df35d3b063272b0e7c499d00 - url_launcher_macos: c04e4fa86382d4f94f6b38f14625708be3ae52e2 + universal_ble: ff19787898040d721109c6324472e5dd4bc86adc + url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 PODFILE CHECKSUM: 2fbdd1e2587d5566bab687bc92adce54b042c807 -COCOAPODS: 1.11.3 +COCOAPODS: 1.16.2 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index fa64242d..dc497ec4 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -296,7 +296,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -394,19 +394,25 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/flutter_midi_command/flutter_midi_command.framework", - "${BUILT_PRODUCTS_DIR}/package_info_plus_macos/package_info_plus_macos.framework", + "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", + "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", + "${BUILT_PRODUCTS_DIR}/universal_ble/universal_ble.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_macos/url_launcher_macos.framework", + "${BUILT_PRODUCTS_DIR}/webview_flutter_wkwebview/webview_flutter_wkwebview.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_midi_command.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus_macos.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/universal_ble.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_macos.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/webview_flutter_wkwebview.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 814fcbbf..82757a4f 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index 11643d37..2654d6d1 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -2,7 +2,7 @@ import Cocoa import FlutterMacOS //import Firebase -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override init() { From 5f92678d3c2b51e8fe09e8a3445c08d51d67761d Mon Sep 17 00:00:00 2001 From: Jon Latane Date: Sun, 8 Feb 2026 13:20:54 -0500 Subject: [PATCH 11/11] fix macos build --- .vscode/launch.json | 7 +- ios/Podfile.lock | 80 ++++++++++--------- .../xcshareddata/xcschemes/Runner.xcscheme | 2 + lib/drawing/canvas_tone_drawer.dart | 9 ++- lib/drawing/color_guide.dart | 13 +-- lib/drawing/harmony_beat_renderer.dart | 11 +-- lib/drawing/music/base_music_renderer.dart | 4 +- .../music/colorblock_music_renderer.dart | 13 ++- .../music/notation_music_renderer.dart | 7 +- lib/drawing/rect_rendering.dart | 10 +++ lib/layers_view/layers_view.dart | 2 + lib/main.dart | 9 ++- lib/music_preview/preview_renderer.dart | 6 +- lib/music_preview/score_preview.dart | 6 +- lib/music_view/music_scroll_container.dart | 3 +- lib/music_view/music_system_painter.dart | 45 +++++++---- lib/music_view/music_toolbars.dart | 15 ++-- lib/music_view/music_view.dart | 19 ++--- lib/storage/score_manager.dart | 29 +++---- lib/storage/score_picker.dart | 6 +- lib/storage/score_picker_preview.dart | 10 +-- lib/storage/universe_manager.dart | 36 +++++---- lib/widget/colorboard.dart | 6 +- lib/widget/keyboard.dart | 8 +- lib/widget/my_popup_menu.dart | 4 +- macos/Runner.xcodeproj/project.pbxproj | 12 +-- macos/Runner/AppDelegate.swift | 4 + .../AudioSystem/AKSamplerExtensions.swift | 64 ++++++++------- pubspec.yaml | 2 +- 29 files changed, 264 insertions(+), 178 deletions(-) create mode 100644 lib/drawing/rect_rendering.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index 88bca8aa..5ba62547 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,7 +4,6 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { "name": "BeatScratch", "program": "lib/main.dart", @@ -54,6 +53,12 @@ "type": "dart", "deviceId": "77171629-E070-4F03-9FD7-0898D08E2DEA" }, + { + "name": "iPad Pro 13-inch (M4) (Simulator)", + "request": "launch", + "type": "dart", + "deviceId": "BC339840-C42C-4177-A2D9-A5BC201DD68A" + }, ], "compounds": [ { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 7f7705b3..fd60bbca 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,12 +1,10 @@ PODS: - - aeyrium_sensor (1.0.0): + - "appcheck (1.5.4+1)": - Flutter - Flutter (1.0.0) - - flutter_appavailability (0.0.1): + - flutter_keyboard_visibility (0.0.1): - Flutter - - flutter_keyboard_visibility (0.7.0): - - Flutter - - flutter_midi_command (0.3.6): + - flutter_midi_command (0.4.2): - Flutter - native_device_orientation (0.0.1): - Flutter @@ -15,46 +13,48 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - sensors (0.0.1): + - sensors_plus (0.0.1): - Flutter - - share (0.0.1): + - share_plus (0.0.1): - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - SwiftProtobuf (1.13.0) + - universal_ble (0.0.1): + - Flutter + - FlutterMacOS - url_launcher_ios (0.0.1): - Flutter - webview_flutter_wkwebview (0.0.1): - Flutter + - FlutterMacOS DEPENDENCIES: - - aeyrium_sensor (from `.symlinks/plugins/aeyrium_sensor/ios`) + - appcheck (from `.symlinks/plugins/appcheck/ios`) - Flutter (from `Flutter`) - - flutter_appavailability (from `.symlinks/plugins/flutter_appavailability/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - flutter_midi_command (from `.symlinks/plugins/flutter_midi_command/ios`) - native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - - sensors (from `.symlinks/plugins/sensors/ios`) - - share (from `.symlinks/plugins/share/ios`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - SwiftProtobuf + - universal_ble (from `.symlinks/plugins/universal_ble/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) SPEC REPOS: trunk: - SwiftProtobuf EXTERNAL SOURCES: - aeyrium_sensor: - :path: ".symlinks/plugins/aeyrium_sensor/ios" + appcheck: + :path: ".symlinks/plugins/appcheck/ios" Flutter: :path: Flutter - flutter_appavailability: - :path: ".symlinks/plugins/flutter_appavailability/ios" flutter_keyboard_visibility: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" flutter_midi_command: @@ -64,34 +64,36 @@ EXTERNAL SOURCES: package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/ios" - sensors: - :path: ".symlinks/plugins/sensors/ios" - share: - :path: ".symlinks/plugins/share/ios" + :path: ".symlinks/plugins/path_provider_foundation/darwin" + sensors_plus: + :path: ".symlinks/plugins/sensors_plus/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/ios" + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + universal_ble: + :path: ".symlinks/plugins/universal_ble/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" + :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: - aeyrium_sensor: cdaa0bdd7206824ea4fb910c627cad05275362e5 - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_appavailability: ebf8f85abea44436d1262fcde8a4e64b2534b01a - flutter_keyboard_visibility: 6195387fb6d8f46e5cd6dda4a4154e41f800f545 - flutter_midi_command: 4acc18c6391c574d21f1d3a1cc40c7fe06ff461f - native_device_orientation: 3b4cfc9565a7b879cc4fde282b3e27745e852d0d - package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 - sensors: 84eb7a30e47a649e4172b71d6e81be614c280336 - share: 0b2c3e82132f5888bccca3351c504d0003b3b410 - shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca + appcheck: 3c94d0ffc94bd639938cac7427d5b13df2795404 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619 + flutter_midi_command: 28d867d5701407d94917c4c35ca0172d362e1611 + native_device_orientation: e3580675687d5034770da198f6839ebf2122ef94 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 SwiftProtobuf: fd4693388a96c8c2df35d3b063272b0e7c499d00 - url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2 - webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f + universal_ble: ff19787898040d721109c6324472e5dd4bc86adc + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 PODFILE CHECKSUM: 79aecb95524f6b2d9ca54f898d51b01d778cce9b -COCOAPODS: 1.11.3 +COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c53e2b31..9c12df59 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> { duration: animationDuration, width: width, child: MyFlatButton( + // borderRadius: 0, color: Colors.grey, onPressed: canAddPart ? () { diff --git a/lib/main.dart b/lib/main.dart index b3406622..b3ee43ff 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -159,7 +159,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State with TickerProviderStateMixin { late Score score; InteractionMode interactionMode = InteractionMode.view; - late SplitMode _splitMode; + SplitMode _splitMode = SplitMode.full; SplitMode get splitMode => _splitMode; @@ -558,7 +558,10 @@ class _MyHomePageState extends State with TickerProviderStateMixin { if (interactionMode.isEdit) { _prevSelectedMelody = selectedMelody; _prevSelectedPart = null; - _hideMusicView(); + if (musicViewMode != MusicViewMode.none) + _hideMusicView(); + else + _showMusicView(); } else { if (_scoreManager.currentScoreName == ScoreManager.UNIVERSE_SCORE || _scoreManager.currentScoreName == ScoreManager.WEB_SCORE || @@ -1544,7 +1547,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { TextStyle( color: foregroundColor, fontSize: 10, - fontWeight: FontWeight.w100), + fontWeight: FontWeight.w400), score, _scoreManager), maxLines: 3, diff --git a/lib/music_preview/preview_renderer.dart b/lib/music_preview/preview_renderer.dart index 09d8aaa4..4b012c6b 100644 --- a/lib/music_preview/preview_renderer.dart +++ b/lib/music_preview/preview_renderer.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; +import 'package:beatscratch_flutter_redux/drawing/rect_rendering.dart'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; import 'package:flutter/material.dart'; @@ -60,9 +61,10 @@ class MusicPreviewRenderer { AppSettings.globalRenderingMode == RenderingMode.notation ? 1 : 0), colorboardNotesNotifier: ValueNotifier([]), keyboardNotesNotifier: ValueNotifier([]), - visibleRect: () => Rect.fromLTRB(0, 0, width / scale, height / scale), + visibleRect: () => + RectRendering.fromLTRB(0, 0, width / scale, height / scale), verticallyVisibleRect: () => - Rect.fromLTRB(0, 0, width / scale, height / scale), + RectRendering.fromLTRB(0, 0, width / scale, height / scale), keyboardPart: ValueNotifier(null), colorboardPart: ValueNotifier(null), focusedPart: ValueNotifier(null), diff --git a/lib/music_preview/score_preview.dart b/lib/music_preview/score_preview.dart index dc473727..2b3a5a5e 100644 --- a/lib/music_preview/score_preview.dart +++ b/lib/music_preview/score_preview.dart @@ -44,9 +44,9 @@ class ScorePreview extends StatefulWidget { enum _Thumbnail { a, b } class _ScorePreviewState extends State { - late bool hasBuilt; - late String _prevScoreId; - late RenderingMode _prevRenderingMode; + bool hasBuilt = false; + String? _prevScoreId; + RenderingMode _prevRenderingMode = RenderingMode.notation; late double _prevScale, _prevWidth, _prevHeight; late Color _prevRenderColor; late _Thumbnail currentThumbnail; diff --git a/lib/music_view/music_scroll_container.dart b/lib/music_view/music_scroll_container.dart index 94b3b783..17799740 100644 --- a/lib/music_view/music_scroll_container.dart +++ b/lib/music_view/music_scroll_container.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:beatscratch_flutter_redux/drawing/rect_rendering.dart'; import 'package:beatscratch_flutter_redux/settings/settings.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -600,7 +601,7 @@ class _MusicScrollContainerState extends State Rect get transformedRect => MatrixUtils.inverseTransformRect( transformationController.value, - Rect.fromLTRB(0, 0, widget.width, widget.height)); + RectRendering.fromLTRB(0, 0, widget.width, widget.height)); // double get secondSystemOffset => // widget.width - clefWidth; diff --git a/lib/music_view/music_system_painter.dart b/lib/music_view/music_system_painter.dart index 1278184c..bc48a3af 100644 --- a/lib/music_view/music_system_painter.dart +++ b/lib/music_view/music_system_painter.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:beatscratch_flutter_redux/drawing/rect_rendering.dart'; import 'package:beatscratch_flutter_redux/widget/my_platform.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -196,7 +197,7 @@ class MusicSystemPainter extends CustomPainter { double staffOffset = staffOffsets.value.putIfAbsent(staff.id, () => 0); double top = visibleRect().top + harmonyHeight + sectionHeight + staffOffset; - Rect staffLineBounds = Rect.fromLTRB( + Rect staffLineBounds = RectRendering.fromLTRB( max(-offsetStart, visibleRect().left), top, max(-offsetStart, visibleRect().right), @@ -204,7 +205,7 @@ class MusicSystemPainter extends CustomPainter { // canvas.drawRect(staffLineBounds, Paint()..style=PaintingStyle.stroke..strokeWidth=10); _renderStaffLines(canvas, !(staff is DrumStaff) && drawContinuousColorGuide, staffLineBounds); - Rect clefBounds = Rect.fromLTRB( + Rect clefBounds = RectRendering.fromLTRB( max(-offsetStart, visibleRect().left), top, max(-offsetStart, visibleRect().left) + standardClefWidth, @@ -254,7 +255,7 @@ class MusicSystemPainter extends CustomPainter { } // print("fontSize=$fontSize topOffset=$topOffset"); double opacityFactor = - magicOpacityFactor(Rect.fromLTRB(left, 0, left, 0)); + magicOpacityFactor(RectRendering.fromLTRB(left, 0, left, 0)); TextSpan span = TextSpan( text: renderingSection.canonicalName, style: TextStyle( @@ -282,8 +283,8 @@ class MusicSystemPainter extends CustomPainter { sectionName = renderingSection.id; } - Rect harmonyBounds = - Rect.fromLTRB(left, top, left + beatWidth, top + harmonyHeight); + Rect harmonyBounds = RectRendering.fromLTRB( + left, top, left + beatWidth, top + harmonyHeight); if (isInBounds(harmonyBounds)) { _renderHarmonyBeat( harmonyBounds, renderingSection, renderingSectionBeat, canvas); @@ -313,7 +314,7 @@ class MusicSystemPainter extends CustomPainter { } canvas.drawRect( - Rect.fromLTRB( + RectRendering.fromLTRB( left - extraWidth, translationTotal + visibleRect().top - @@ -325,8 +326,15 @@ class MusicSystemPainter extends CustomPainter { } } - doRenderMelodies(staff, renderingSection, canvas, left, right, top, - renderingSectionBeat, renderingBeat) { + doRenderMelodies( + MusicStaff staff, + Section renderingSection, + Canvas canvas, + double left, + double right, + double top, + int renderingSectionBeat, + int renderingBeat) { staff.getParts(score, staves.value).forEach((part) { double partOffset = partTopOffsets.value.putIfAbsent(part.id, () => 0); List melodiesToRender = renderingSection.melodies @@ -334,11 +342,11 @@ class MusicSystemPainter extends CustomPainter { melodyReference.playbackType != MelodyReference_PlaybackType.disabled) .where((MelodyReference ref) => - part.melodies.any((melody) => melody.id == ref.melodyId) as bool) - .map((it) => score.melodyReferencedBy(it)) + part.melodies.any((melody) => melody.id == ref.melodyId)) + .map((it) => score.melodyReferencedBy(it)!) .toList(growable: false); - Rect melodyBounds = Rect.fromLTRB( + Rect melodyBounds = RectRendering.fromLTRB( left, top + partOffset, right, top + partOffset + melodyHeight); if (isInBounds(melodyBounds)) { _renderMelodies( @@ -424,8 +432,14 @@ class MusicSystemPainter extends CustomPainter { index++; } - final part = score.parts - .firstWhere((p) => p.melodies.any((m) => m.id == focusedMelodyId)); + final part = score.parts.firstWhereOrNull( + (p) => p.melodies.any((m) => m.id == focusedMelodyId)); + + if (part == null) { + // No focused melody, so we don't render the focused melody + return; + } + final parts = staff.getParts(score, staffConfiguration); if (parts.any((p) => p.id == part.id)) { double opacity = 1; @@ -822,7 +836,8 @@ class MusicSystemPainter extends CustomPainter { Chord chordAtSubdivision = renderingHarmony.changeBefore(renderingSubdivision) ?? cChromatic; if (renderingChord != null && renderingChord != chordAtSubdivision) { - Rect renderingRect = Rect.fromLTRB(chordLeft, top, left, bottom); + Rect renderingRect = + RectRendering.fromLTRB(chordLeft, top, left, bottom); try { ColorGuide() ..renderVertically = true @@ -847,7 +862,7 @@ class MusicSystemPainter extends CustomPainter { renderingBeat += 1; } Rect renderingRect = - Rect.fromLTRB(chordLeft, top + harmonyHeight, left, bottom); + RectRendering.fromLTRB(chordLeft, top + harmonyHeight, left, bottom); try { ColorGuide() ..renderVertically = true diff --git a/lib/music_view/music_toolbars.dart b/lib/music_view/music_toolbars.dart index f66255f0..8b8d21ee 100644 --- a/lib/music_view/music_toolbars.dart +++ b/lib/music_view/music_toolbars.dart @@ -337,7 +337,8 @@ class PartToolbarState extends State { Expanded( child: Padding( padding: EdgeInsets.only(left: 5), - child: Text((widget.part != null) ? widget.part!.midiName : "", + child: Text( + (widget.part != null) ? widget.part?.midiName ?? "" : "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -378,9 +379,11 @@ class PartToolbarState extends State { height: 36, padding: EdgeInsets.only(right: 5), child: MyRaisedButton( - onPressed: (widget.part!.instrument.type != InstrumentType.drum) + onPressed: (widget.part?.instrument.type != InstrumentType.drum) ? () { - widget.setColorboardPart(widget.part!); + final part = widget.part; + if (part == null) return; + widget.setColorboardPart(part); } : null, padding: EdgeInsets.zero, @@ -393,7 +396,7 @@ class PartToolbarState extends State { alignment: Alignment.bottomRight, child: AnimatedOpacity( duration: animationDuration, - opacity: (widget.part!.instrument.type != + opacity: (widget.part?.instrument.type != InstrumentType.drum) ? 1 : 0.25, @@ -459,7 +462,9 @@ class PartToolbarState extends State { child: MyRaisedButton( onPressed: () { setState(() { - widget.deletePart(widget.part!); + final part = widget.part; + if (part == null) return; + widget.deletePart(part); confirmingDeleteFor = null; }); }, diff --git a/lib/music_view/music_view.dart b/lib/music_view/music_view.dart index 26683187..cd5bf821 100644 --- a/lib/music_view/music_view.dart +++ b/lib/music_view/music_view.dart @@ -42,7 +42,7 @@ class MusicView extends StatefulWidget { keyboardNotesNotifier; final ValueNotifier>> bluetoothControllerPressedNotes; final Melody? melody; - final Part part; + final Part? part; final Color sectionColor; final VoidCallback toggleSplitMode, closeMelodyView, toggleRecording; final Function(VoidCallback) superSetState; @@ -783,11 +783,12 @@ class _MusicViewState extends State with TickerProviderStateMixin { child: Column(children: [ Expanded(child: SizedBox()), Text( - currentSwipeTutorial! - .tutorialText( - widget.splitMode, - widget.musicViewMode, - context), + currentSwipeTutorial + ?.tutorialText( + widget.splitMode, + widget.musicViewMode, + context) ?? + "", style: TextStyle(fontSize: 11), overflow: TextOverflow.fade, maxLines: 2, @@ -872,7 +873,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { ? partConfigHeight : 0, child: PartConfiguration( - part: widget.part, + part: widget.part ?? Part(), superSetState: widget.superSetState, availableHeight: widget.height, visible: (widget.musicViewMode == MusicViewMode.part && @@ -1007,7 +1008,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { mainPart = widget.keyboardPart; break; case MusicViewMode.part: - mainPart = widget.part; + mainPart = widget.part ?? Part(); break; case MusicViewMode.melody: mainPart = widget.keyboardPart; @@ -1064,7 +1065,7 @@ class _MusicViewState extends State with TickerProviderStateMixin { bool focusedPartIsNotFirst = widget.score.parts.indexWhere((it) => it.id == mainPart.id) != 0; bool focusedMelodyIsNotFirst = widget.score.parts.indexWhere( - (p) => p.melodies.any((m) => m.id == widget.melody.id)) != + (p) => p.melodies.any((m) => m.id == widget.melody?.id)) != 0; bool showAutoFocusButton = (widget.musicViewMode == MusicViewMode.part || widget.musicViewMode == MusicViewMode.melody || diff --git a/lib/storage/score_manager.dart b/lib/storage/score_manager.dart index a9fbfd31..646da5d7 100644 --- a/lib/storage/score_manager.dart +++ b/lib/storage/score_manager.dart @@ -26,24 +26,25 @@ class ScoreManager { static const String FROM_WEB = " (from Link)"; static const String UNIVERSE_SCORE = "Universe Score"; static const String FROM_UNIVERSE = " (from Universe)"; - late Function(Score) doOpenScore; - late Directory scoresDirectory; - late SharedPreferences _prefs; + Function(Score)? doOpenScore; + Directory? scoresDirectory; + SharedPreferences? _prefs; String get currentScoreName => - _prefs.getString('currentScoreName') ?? UNIVERSE_SCORE; + _prefs?.getString('currentScoreName') ?? UNIVERSE_SCORE; set currentScoreName(String value) => - _prefs.setString("currentScoreName", value); + _prefs?.setString("currentScoreName", value); File get currentScoreFile => File( - "${scoresDirectory.path}/${Uri.encodeComponent(currentScoreName).replaceAll("%20", " ")}.beatscratch"); + "${scoresDirectory?.path}/${Uri.encodeComponent(currentScoreName).replaceAll("%20", " ")}.beatscratch"); List get scoreFiles { List result = scoresDirectory - .listSync() - .where((f) => f.path.endsWith(".beatscratch")) - .toList(); + ?.listSync() + .where((f) => f.path.endsWith(".beatscratch")) + .toList() ?? + []; result .sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified)); return result; @@ -62,7 +63,7 @@ class ScoreManager { Directory documentsDirectory = await getApplicationDocumentsDirectory(); final scoresPath = "${documentsDirectory.path}/$scoresDirectoryName"; scoresDirectory = Directory(scoresPath); - scoresDirectory.createSync(); + scoresDirectory!.createSync(); //Migrate files scoreFiles.forEach((file) { @@ -77,7 +78,7 @@ class ScoreManager { score = score ?? defaultScore(); currentScoreName = name; saveCurrentScore(score); - doOpenScore(score); + doOpenScore?.call(score); } saveCurrentScore(Score score) { @@ -106,7 +107,7 @@ class ScoreManager { } catch (e) { score = defaultScore(); } - doOpenScore.call(score); + doOpenScore?.call(score); } loadFromScoreUrl(String scoreUrl, @@ -201,7 +202,7 @@ class ScoreManager { } openScoreWithFilename(score, newScoreDefaultFilename); } else { - doOpenScore(score); + doOpenScore?.call(score); } onSuccess?.call(suggestedScoreName); _lastSuggestedScoreName = suggestedScoreName; @@ -212,7 +213,7 @@ class ScoreManager { openScoreWithFilename(Score score, String filename) async { currentScoreName = filename; - doOpenScore(score); + doOpenScore?.call(score); saveCurrentScore(score); } diff --git a/lib/storage/score_picker.dart b/lib/storage/score_picker.dart index 1461db74..7db8c3b2 100644 --- a/lib/storage/score_picker.dart +++ b/lib/storage/score_picker.dart @@ -223,7 +223,7 @@ class ScorePickerState extends State { return Column( children: [ AnimatedContainer( - height: showHeader ? 45 : 0, + height: showHeader ? 48 : 0, duration: animationDuration, child: AnimatedOpacity( duration: animationDuration, @@ -646,7 +646,7 @@ class ScorePickerState extends State { // Called, as needed, to build list item widgets. // List items are only built when they're scrolled into view. itemBuilder: (context, animation, section, index) { - late final ScoreFuture? scoreFuture; + ScoreFuture? scoreFuture; if (index < scores.length) { scoreFuture = scores[index]; } @@ -675,7 +675,7 @@ class ScorePickerState extends State { ScoreManager.UNIVERSE_SCORE; } scoreFuture?.loadScore(scoreManager).then((value) { - widget.scoreManager.doOpenScore(value); + widget.scoreManager.doOpenScore?.call(value); widget.universeManager.currentUniverseScore = scoreFuture!.identity; widget.scoreManager.saveCurrentScore(value); diff --git a/lib/storage/score_picker_preview.dart b/lib/storage/score_picker_preview.dart index 99d43491..f33d15e1 100644 --- a/lib/storage/score_picker_preview.dart +++ b/lib/storage/score_picker_preview.dart @@ -145,12 +145,12 @@ class ScorePickerPreview extends StatefulWidget { } class _ScorePickerPreviewState extends State { - late bool _confirmingDelete; - late bool _confirmingOverwrite; - late int _lastScoreKey; - late bool disposed; + bool _confirmingDelete = false; + bool _confirmingOverwrite = false; + int? _lastScoreKey; + bool disposed = false; - late Score? _previewScore; + Score? _previewScore; late ScrollController scrollController; late BSMethod notifyUpdate; diff --git a/lib/storage/universe_manager.dart b/lib/storage/universe_manager.dart index 63f6eb95..001d32bd 100644 --- a/lib/storage/universe_manager.dart +++ b/lib/storage/universe_manager.dart @@ -21,7 +21,7 @@ class UniverseManager { static final REDDIT_REDIRECT_URI = 'https://beatscratch.io/app'; late Function(Score) doOpenScore; late Directory scoresDirectory; - late SharedPreferences _prefs; + SharedPreferences? _prefs; late ScoreManager scoreManager; late MessagesUI messagesUI; late BSMethod refreshUniverseData; @@ -30,13 +30,13 @@ class UniverseManager { _initialize(); } - bool get useWebViewSignIn => _prefs.getBool('useWebViewSignIn') ?? false; - set useWebViewSignIn(bool v) => _prefs.setBool("useWebViewSignIn", v); + bool get useWebViewSignIn => _prefs?.getBool('useWebViewSignIn') ?? false; + set useWebViewSignIn(bool v) => _prefs?.setBool("useWebViewSignIn", v); String get currentUniverseScore => - _prefs.getString('currentUniverseScore') ?? ''; + _prefs?.getString('currentUniverseScore') ?? ''; set currentUniverseScore(String v) => - _prefs.setString("currentUniverseScore", v); + _prefs?.setString("currentUniverseScore", v); ScoreFuture? get currentUniverseScoreFuture => currentUniverseScore == '' ? null @@ -44,16 +44,18 @@ class UniverseManager { (d) => d.identity == currentUniverseScore, ); - String get redditRefreshToken => _prefs.getString('redditRefreshToken') ?? ""; + String get redditRefreshToken => + _prefs?.getString('redditRefreshToken') ?? ""; set redditRefreshToken(String value) => - _prefs.setString("redditRefreshToken", value); + _prefs?.setString("redditRefreshToken", value); - String get redditAccessToken => _prefs.getString('redditAccessToken') ?? ""; + String get redditAccessToken => _prefs?.getString('redditAccessToken') ?? ""; set redditAccessToken(String value) => - _prefs.setString("redditAccessToken", value); + _prefs?.setString("redditAccessToken", value); - String get redditUsername => _prefs.getString('redditUsername') ?? ""; - set redditUsername(String value) => _prefs.setString("redditUsername", value); + String get redditUsername => _prefs?.getString('redditUsername') ?? ""; + set redditUsername(String value) => + _prefs?.setString("redditUsername", value); static const String DEFAULT_UNIVERSE_DATA_STRING = '[{"filePath":null,"title":"Tropico-Pastoral","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/n5f1s1/tropicopastoral/","voteCount":1,"likes":true,"fullName":"t3_n5f1s1","scoreUrl":"https://beatscratch.io/app/#/s/CZZX0"},{"filePath":null,"title":"A cheesy educational intro","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/myliqr/a_cheesy_educational_intro/","voteCount":1,"likes":true,"fullName":"t3_myliqr","scoreUrl":"https://beatscratch.io/app/#/s/ORXsf"},{"filePath":null,"title":"A longer, original demo using 5 instruments","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/my7ajg/a_longer_original_demo_using_5_instruments/","voteCount":1,"likes":true,"fullName":"t3_my7ajg","scoreUrl":"https://beatscratch.io/app/#/s/Z4hZh"},{"filePath":null,"title":"2021, From Jacob Collier’s Insta","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/mwyv7m/2021_from_jacob_colliers_insta/","voteCount":1,"likes":null,"fullName":"t3_mwyv7m","scoreUrl":"https://beatscratch.io/app/#/s/5dVNM"},{"filePath":null,"title":"Tee Time 2.6","author":"pseudocomposer","commentUrl":"https://reddit.com/r/BeatScratch/comments/lnmxyh/tee_time_26/","voteCount":1,"likes":null,"fullName":"t3_lnmxyh","scoreUrl":"https://beatscratch.io/app/#/s/rx0w0"}]'; @@ -64,7 +66,7 @@ class UniverseManager { ..putIfAbsent("likes", () => null)))) .toList(); List get __cachedUniverseData => - (_prefs.getStringList('cachedUniverseData') ?? DEFAULT_UNIVERSE_DATA) + (_prefs?.getStringList('cachedUniverseData') ?? DEFAULT_UNIVERSE_DATA) .map((it) => ScoreFuture.fromJson(jsonDecode(it))) .toList(); List _cachedUniverseData = []; @@ -72,8 +74,10 @@ class UniverseManager { List get cachedUniverseData => _cachedUniverseData; set cachedUniverseData(List value) { _cachedUniverseData = value; - Future.microtask(() => _prefs.setStringList("cachedUniverseData", - value.map((it) => jsonEncode(it.toJson())).toList())); + Future.microtask(() => { + _prefs?.setStringList("cachedUniverseData", + value.map((it) => jsonEncode(it.toJson())).toList()) + }); } bool get isAuthenticated => @@ -85,8 +89,8 @@ class UniverseManager { refreshAccessToken(andPoll: true); } - String get _authState => _prefs.getString('redditAuthState') ?? ""; - set _authState(String value) => _prefs.setString("redditAuthState", value); + String get _authState => _prefs?.getString('redditAuthState') ?? ""; + set _authState(String value) => _prefs?.setString("redditAuthState", value); initiateSignIn() { _authState = uuid.v4(); diff --git a/lib/widget/colorboard.dart b/lib/widget/colorboard.dart index e93adc6d..290155eb 100644 --- a/lib/widget/colorboard.dart +++ b/lib/widget/colorboard.dart @@ -1,3 +1,5 @@ +import 'package:beatscratch_flutter_redux/drawing/rect_rendering.dart'; + import '../drawing/canvas_tone_drawer.dart'; import '../drawing/color_guide.dart'; import 'package:flutter/material.dart'; @@ -184,8 +186,8 @@ class _ColorboardState extends State with TickerProviderStateMixin { CustomSliverToBoxAdapter( (rect) { _visibleRect = rect; - _visibleRect = Rect.fromLTRB(rect.left, rect.top, rect.right, - rect.bottom - touchScrollAreaHeight); + _visibleRect = RectRendering.fromLTRB(rect.left, rect.top, + rect.right, rect.bottom - touchScrollAreaHeight); double newScrollPositionValue = rect.left / (physicalWidth - rect.width); if (newScrollPositionValue.isFinite && diff --git a/lib/widget/keyboard.dart b/lib/widget/keyboard.dart index 12a09d66..31bf76bd 100644 --- a/lib/widget/keyboard.dart +++ b/lib/widget/keyboard.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'dart:ui'; // import 'package:aeyrium_sensor/aeyrium_sensor.dart'; +import 'package:beatscratch_flutter_redux/drawing/rect_rendering.dart'; import 'package:beatscratch_flutter_redux/settings/app_settings.dart'; import 'package:flutter/services.dart'; import '../drawing/canvas_tone_drawer.dart'; @@ -242,7 +243,7 @@ class KeyboardState extends State with TickerProviderStateMixin { CustomSliverToBoxAdapter( (rect) { _visibleRect = rect; - _visibleRect = Rect.fromLTRB(rect.left, rect.top, + _visibleRect = RectRendering.fromLTRB(rect.left, rect.top, rect.right, rect.bottom - touchScrollAreaHeight); double newScrollPositionValue = rect.left / (physicalWidth - rect.width); @@ -952,7 +953,10 @@ class KeyboardRenderer extends CanvasToneDrawer { chromaticSteps[(tone - chord.rootNote.tone).mod12]; } canvas.drawRect( - Rect.fromLTRB(toneBounds.left, toneBounds.top, toneBounds.right, + RectRendering.fromLTRB( + toneBounds.left, + toneBounds.top, + toneBounds.right, toneBounds.top + (toneBounds.top + toneBounds.bottom) / 2), alphaDrawerPaint); break; diff --git a/lib/widget/my_popup_menu.dart b/lib/widget/my_popup_menu.dart index 22ab8f41..4713d625 100644 --- a/lib/widget/my_popup_menu.dart +++ b/lib/widget/my_popup_menu.dart @@ -1018,8 +1018,8 @@ class MyPopupMenuButton extends StatefulWidget { this.captureInheritedThemes = true, this.updatedMenu, }) : assert(offset != null), - assert( - !(icon != null), 'You can only pass [child] or [icon], not both.'), + // assert( + // !(icon != null), 'You can only pass [child] or [icon], not both.'), super(key: key); /// Called when the button is pressed to create the items to show in the menu. diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index dc497ec4..edd92b7d 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -575,9 +575,9 @@ "-framework", "\"SwiftProtobuf\"", "-framework", - "\"path_provider_macos\"", + "\"path_provider_foundation\"", "-framework", - "\"shared_preferences_macos\"", + "\"shared_preferences_foundation\"", "-framework", "\"url_launcher_macos\"", "-lc++", @@ -734,9 +734,9 @@ "-framework", "\"SwiftProtobuf\"", "-framework", - "\"path_provider_macos\"", + "\"path_provider_foundation\"", "-framework", - "\"shared_preferences_macos\"", + "\"shared_preferences_foundation\"", "-framework", "\"url_launcher_macos\"", "-lc++", @@ -778,9 +778,9 @@ "-framework", "\"SwiftProtobuf\"", "-framework", - "\"path_provider_macos\"", + "\"path_provider_foundation\"", "-framework", - "\"shared_preferences_macos\"", + "\"shared_preferences_foundation\"", "-framework", "\"url_launcher_macos\"", "-lc++", diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index 2654d6d1..21a09241 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -13,6 +13,10 @@ class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } override func application(_ application: NSApplication, continue userActivity: NSUserActivity, diff --git a/macos/Runner/AudioSystem/AKSamplerExtensions.swift b/macos/Runner/AudioSystem/AKSamplerExtensions.swift index 2fab9ca5..19a6aee3 100644 --- a/macos/Runner/AudioSystem/AKSamplerExtensions.swift +++ b/macos/Runner/AudioSystem/AKSamplerExtensions.swift @@ -6,18 +6,18 @@ // Copyright © 2020 The Flutter Authors. All rights reserved. // -import Foundation import AudioKit +import Foundation extension AKSampler { - open func loadSfzWithEmbeddedSpacesInSampleNames(folderPath: String, sfzFileName: String) { + public func loadSfzWithEmbeddedSpacesInSampleNames(folderPath: String, sfzFileName: String) { stopAllVoices() do { try unloadAllSamples() - } catch { + } catch { AKLog("Failed to unload samples") } - + var lastPrefix: String = "" var lokey: Int32 = 0 var hikey: Int32 = 127 @@ -28,7 +28,7 @@ extension AKSampler { var loopmode: String = "" var loopstart: Float32 = 0 var loopend: Float32 = 0 - + func resetVars() { lokey = 0 hikey = 127 @@ -39,7 +39,7 @@ extension AKSampler { loopstart = 0 loopend = 0 } - + let baseURL = URL(fileURLWithPath: folderPath) let sfzURL = baseURL.appendingPathComponent(sfzFileName) do { @@ -52,9 +52,14 @@ extension AKSampler { continue } for token in trimmed.components(separatedBy: .whitespaces) { - if token.hasPrefix("") || token.hasPrefix("") || token.hasPrefix("") { + if token.hasPrefix("") || token.hasPrefix("") + || token.hasPrefix("") + { if lastPrefix == "region" { - try buildSample(baseURL: baseURL, lokey: lokey, hikey: hikey, pitch: pitch, lovel: lovel, hivel: hivel, sample: sample, loopmode: loopmode, loopstart: loopstart, loopend: loopend) + try buildSample( + baseURL: baseURL, lokey: lokey, hikey: hikey, pitch: pitch, lovel: lovel, + hivel: hivel, sample: sample, loopmode: loopmode, loopstart: loopstart, + loopend: loopend) } resetVars() } else if token.hasPrefix("key=") { @@ -78,9 +83,10 @@ extension AKSampler { } else if token.hasPrefix("loop_end") { loopend = Float32(token.components(separatedBy: "=")[1])! } else if token.hasPrefix("sample") { - sample = trimmed.components(separatedBy: "sample=")[1].replacingOccurrences(of: "\\", with: "/") + sample = trimmed.components(separatedBy: "sample=")[1].replacingOccurrences( + of: "\\", with: "/") } - + if token.hasPrefix("") { lastPrefix = "global" } @@ -91,19 +97,21 @@ extension AKSampler { lastPrefix = "region" } } - + // if sample != "" { // buildSample(baseURL: baseURL, lokey: lokey, hikey: hikey, pitch: pitch, lovel: lovel, hivel: hivel, sample: sample, loopmode: loopmode, loopstart: loopstart, loopend: loopend) // sample = "" // } } - if(lastPrefix == "region") { - try buildSample(baseURL: baseURL, lokey: lokey, hikey: hikey, pitch: pitch, lovel: lovel, hivel: hivel, sample: sample, loopmode: loopmode, loopstart: loopstart, loopend: loopend) + if lastPrefix == "region" { + try buildSample( + baseURL: baseURL, lokey: lokey, hikey: hikey, pitch: pitch, lovel: lovel, hivel: hivel, + sample: sample, loopmode: loopmode, loopstart: loopstart, loopend: loopend) } } catch { AKLog(error) } - + buildKeyMap() restartVoices() } @@ -120,20 +128,22 @@ extension AKSampler { loopstart: Float32, loopend: Float32 ) throws { - let noteFreq = Float(AKPolyphonicNode.tuningTable.frequency(forNoteNumber: MIDINoteNumber(pitch))) + let noteFreq = Float( + AKPolyphonicNode.tuningTable.frequency(forNoteNumber: MIDINoteNumber(pitch))) AKLog("load \(pitch) \(noteFreq) Hz range \(lokey)-\(hikey) vel \(lovel)-\(hivel) \(sample)") - - let sd = AKSampleDescriptor(noteNumber: pitch, - noteFrequency: noteFreq, - minimumNoteNumber: lokey, - maximumNoteNumber: hikey, - minimumVelocity: lovel, - maximumVelocity: hivel, - isLooping: loopmode != "" && loopmode != "no_loop", - loopStartPoint: loopstart, - loopEndPoint: loopend, - startPoint: 0.0, - endPoint: 0.0) + + let sd = AKSampleDescriptor( + noteNumber: pitch, + noteFrequency: noteFreq, + minimumNoteNumber: lokey, + maximumNoteNumber: hikey, + minimumVelocity: lovel, + maximumVelocity: hivel, + isLooping: loopmode != "" && loopmode != "no_loop", + loopStartPoint: loopstart, + loopEndPoint: loopend, + startPoint: 0.0, + endPoint: 0.0) let sampleFileURL = baseURL.appendingPathComponent(sample) if sample.hasSuffix(".wv") { let string = (sampleFileURL.path as NSString).utf8String diff --git a/pubspec.yaml b/pubspec.yaml index e139e22d..84c88d23 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: # dart_midi: 1.0.1 quiver: ^3.0.1 path_drawing: 1.0.1 - path_provider: ^2.0.2 + path_provider: ^2.1.5 shared_preferences: ^2.0.6 base_x: ^2.0.0 archive: ^4.0.7