├── android ├── settings_aar.gradle ├── Gemfile ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable-hdpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── drawable-ldpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── drawable-mdpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ └── launch_screen.png │ │ │ │ ├── values │ │ │ │ │ ├── colors.xml │ │ │ │ │ └── styles.xml │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── kaya │ │ │ │ │ └── musicapp │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── fastlane │ ├── Appfile │ └── Fastfile ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── build.gradle └── Gemfile.lock ├── ios ├── Gemfile ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── 20.png │ │ │ ├── 29.png │ │ │ ├── 40.png │ │ │ ├── 58.png │ │ │ ├── 60.png │ │ │ ├── 76.png │ │ │ ├── 80.png │ │ │ ├── 87.png │ │ │ ├── 1024.png │ │ │ ├── 120.png │ │ │ ├── 152.png │ │ │ ├── 167.png │ │ │ ├── 180.png │ │ │ ├── 40-1.png │ │ │ ├── 40-2.png │ │ │ ├── 58-1.png │ │ │ ├── 80-1.png │ │ │ ├── 120-1.png │ │ │ └── Contents.json │ │ └── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── fastlane │ ├── Appfile │ └── Fastfile ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore ├── Podfile ├── Gemfile.lock └── Podfile.lock ├── screenshots ├── 0.png ├── 1.png └── 2.png ├── assets ├── imgs │ ├── guitar.png │ ├── key1.png │ ├── key10.png │ ├── key11.png │ ├── key12.png │ ├── key2.png │ ├── key3.png │ ├── key4.png │ ├── key5.png │ ├── key6.png │ ├── key7.png │ ├── key8.png │ ├── key9.png │ ├── logo.jpg │ ├── piano.png │ ├── piano2.gif │ ├── scale.png │ ├── appicon.png │ ├── applogo.png │ ├── applogo2.png │ ├── keyboard.gif │ ├── pianoimg.png │ ├── appsplash.png │ ├── rockmusic.png │ ├── seperator.png │ ├── appiconsplash.png │ ├── classicmusic.png │ ├── musicalnotes.png │ ├── musicnotation.png │ ├── internationalmusic.png │ ├── international_music.svg │ ├── music_notes.svg │ ├── piano.svg │ ├── x.svg │ ├── guitar.svg │ ├── prog.svg │ ├── quiz.svg │ ├── the-scale.svg │ └── metronome.svg ├── metronome │ ├── hat1.mp3 │ ├── hat2.mp3 │ ├── kick1.mp3 │ ├── kick2.mp3 │ ├── snare1.mp3 │ └── snare2.mp3 ├── notes │ ├── guitar │ │ ├── a4.mp3 │ │ ├── a5.mp3 │ │ ├── a6.mp3 │ │ ├── as4.mp3 │ │ ├── as5.mp3 │ │ ├── as6.mp3 │ │ ├── b4.mp3 │ │ ├── b5.mp3 │ │ ├── b6.mp3 │ │ ├── c4.mp3 │ │ ├── c5.mp3 │ │ ├── c6.mp3 │ │ ├── cs4.mp3 │ │ ├── cs5.mp3 │ │ ├── cs6.mp3 │ │ ├── d4.mp3 │ │ ├── d5.mp3 │ │ ├── d6.mp3 │ │ ├── ds4.mp3 │ │ ├── ds5.mp3 │ │ ├── ds6.mp3 │ │ ├── e4.mp3 │ │ ├── e5.mp3 │ │ ├── e6.mp3 │ │ ├── f4.mp3 │ │ ├── f5.mp3 │ │ ├── f6.mp3 │ │ ├── fs4.mp3 │ │ ├── fs5.mp3 │ │ ├── fs6.mp3 │ │ ├── g4.mp3 │ │ ├── g5.mp3 │ │ ├── g6.mp3 │ │ ├── gs4.mp3 │ │ ├── gs5.mp3 │ │ └── gs6.mp3 │ └── piano │ │ ├── a4.mp3 │ │ ├── a5.mp3 │ │ ├── a6.mp3 │ │ ├── as4.mp3 │ │ ├── as5.mp3 │ │ ├── as6.mp3 │ │ ├── b4.mp3 │ │ ├── b5.mp3 │ │ ├── b6.mp3 │ │ ├── c4.mp3 │ │ ├── c5.mp3 │ │ ├── c6.mp3 │ │ ├── cs4.mp3 │ │ ├── cs5.mp3 │ │ ├── cs6.mp3 │ │ ├── d4.mp3 │ │ ├── d5.mp3 │ │ ├── d6.mp3 │ │ ├── ds4.mp3 │ │ ├── ds5.mp3 │ │ ├── ds6.mp3 │ │ ├── e4.mp3 │ │ ├── e5.mp3 │ │ ├── e6.mp3 │ │ ├── f4.mp3 │ │ ├── f5.mp3 │ │ ├── f6.mp3 │ │ ├── fs4.mp3 │ │ ├── fs5.mp3 │ │ ├── fs6.mp3 │ │ ├── g4.mp3 │ │ ├── g5.mp3 │ │ ├── g6.mp3 │ │ ├── gs4.mp3 │ │ ├── gs5.mp3 │ │ └── gs6.mp3 └── fonts │ └── MyFlutterApp.ttf ├── lib ├── presentation │ ├── core │ │ ├── const.dart │ │ ├── my_app.dart │ │ └── drawer │ │ │ └── drawer.dart │ ├── icons │ │ └── my_flutter_app_icons.dart │ ├── chords │ │ ├── widgets │ │ │ └── note_cell.dart │ │ ├── chord_page.dart │ │ └── search_chord.dart │ ├── scale │ │ ├── widgets │ │ │ └── note_cell.dart │ │ ├── scale_page.dart │ │ ├── utils │ │ │ └── utils.dart │ │ └── random_progression_page.dart │ ├── widgets │ │ └── card │ │ │ └── card.dart │ ├── utils_pages │ │ └── utils_page.dart │ └── settings │ │ └── settings.dart ├── infrastructure │ └── ads │ │ ├── const.dart │ │ └── utils.dart ├── application │ ├── actions │ │ └── settings_action.dart │ ├── store │ │ └── store.dart │ └── reducers │ │ └── settings_reducer.dart ├── domain │ ├── core │ │ └── const.dart │ ├── probability_post │ │ └── probability_post.dart │ ├── settings │ │ └── settings.dart │ ├── notes │ │ └── notes.dart │ ├── scales │ │ └── scales.dart │ └── chords │ │ └── chords.dart └── main.dart ├── test_driver └── main_test.dart ├── .metadata ├── .vscode └── launch.json ├── .gitignore ├── test └── widget_test.dart ├── README.md ├── integration_test ├── app_test.dart ├── chord_test.dart └── scale_test.dart └── pubspec.yaml /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /android/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /screenshots/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/screenshots/0.png -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/screenshots/2.png -------------------------------------------------------------------------------- /assets/imgs/guitar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/guitar.png -------------------------------------------------------------------------------- /assets/imgs/key1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key1.png -------------------------------------------------------------------------------- /assets/imgs/key10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key10.png -------------------------------------------------------------------------------- /assets/imgs/key11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key11.png -------------------------------------------------------------------------------- /assets/imgs/key12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key12.png -------------------------------------------------------------------------------- /assets/imgs/key2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key2.png -------------------------------------------------------------------------------- /assets/imgs/key3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key3.png -------------------------------------------------------------------------------- /assets/imgs/key4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key4.png -------------------------------------------------------------------------------- /assets/imgs/key5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key5.png -------------------------------------------------------------------------------- /assets/imgs/key6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key6.png -------------------------------------------------------------------------------- /assets/imgs/key7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key7.png -------------------------------------------------------------------------------- /assets/imgs/key8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key8.png -------------------------------------------------------------------------------- /assets/imgs/key9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/key9.png -------------------------------------------------------------------------------- /assets/imgs/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/logo.jpg -------------------------------------------------------------------------------- /assets/imgs/piano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/piano.png -------------------------------------------------------------------------------- /assets/imgs/piano2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/piano2.gif -------------------------------------------------------------------------------- /assets/imgs/scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/scale.png -------------------------------------------------------------------------------- /lib/presentation/core/const.dart: -------------------------------------------------------------------------------- 1 | const String bearerToken = "6eed7f57c99b5ea87b4ec3941a3585d5"; 2 | -------------------------------------------------------------------------------- /assets/imgs/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/appicon.png -------------------------------------------------------------------------------- /assets/imgs/applogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/applogo.png -------------------------------------------------------------------------------- /assets/imgs/applogo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/applogo2.png -------------------------------------------------------------------------------- /assets/imgs/keyboard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/keyboard.gif -------------------------------------------------------------------------------- /assets/imgs/pianoimg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/pianoimg.png -------------------------------------------------------------------------------- /assets/imgs/appsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/appsplash.png -------------------------------------------------------------------------------- /assets/imgs/rockmusic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/rockmusic.png -------------------------------------------------------------------------------- /assets/imgs/seperator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/seperator.png -------------------------------------------------------------------------------- /assets/metronome/hat1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/hat1.mp3 -------------------------------------------------------------------------------- /assets/metronome/hat2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/hat2.mp3 -------------------------------------------------------------------------------- /assets/metronome/kick1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/kick1.mp3 -------------------------------------------------------------------------------- /assets/metronome/kick2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/kick2.mp3 -------------------------------------------------------------------------------- /assets/metronome/snare1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/snare1.mp3 -------------------------------------------------------------------------------- /assets/metronome/snare2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/metronome/snare2.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/a4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/a4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/a5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/a5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/a6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/a6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/as4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/as4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/as5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/as5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/as6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/as6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/b4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/b4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/b5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/b5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/b6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/b6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/c4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/c4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/c5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/c5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/c6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/c6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/cs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/cs4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/cs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/cs5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/cs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/cs6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/d4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/d4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/d5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/d5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/d6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/d6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/ds4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/ds4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/ds5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/ds5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/ds6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/ds6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/e4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/e4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/e5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/e5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/e6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/e6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/f4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/f4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/f5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/f5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/f6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/f6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/fs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/fs4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/fs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/fs5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/fs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/fs6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/g4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/g4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/g5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/g5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/g6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/g6.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/gs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/gs4.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/gs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/gs5.mp3 -------------------------------------------------------------------------------- /assets/notes/guitar/gs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/guitar/gs6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/a4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/a4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/a5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/a5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/a6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/a6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/as4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/as4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/as5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/as5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/as6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/as6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/b4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/b4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/b5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/b5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/b6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/b6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/c4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/c4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/c5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/c5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/c6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/c6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/cs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/cs4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/cs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/cs5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/cs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/cs6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/d4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/d4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/d5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/d5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/d6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/d6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/ds4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/ds4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/ds5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/ds5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/ds6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/ds6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/e4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/e4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/e5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/e5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/e6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/e6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/f4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/f4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/f5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/f5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/f6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/f6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/fs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/fs4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/fs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/fs5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/fs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/fs6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/g4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/g4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/g5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/g5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/g6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/g6.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/gs4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/gs4.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/gs5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/gs5.mp3 -------------------------------------------------------------------------------- /assets/notes/piano/gs6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/notes/piano/gs6.mp3 -------------------------------------------------------------------------------- /lib/infrastructure/ads/const.dart: -------------------------------------------------------------------------------- 1 | final bool enableInterstitialAds = false; 2 | final bool testing = true; 3 | -------------------------------------------------------------------------------- /assets/fonts/MyFlutterApp.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/fonts/MyFlutterApp.ttf -------------------------------------------------------------------------------- /assets/imgs/appiconsplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/appiconsplash.png -------------------------------------------------------------------------------- /assets/imgs/classicmusic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/classicmusic.png -------------------------------------------------------------------------------- /assets/imgs/musicalnotes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/musicalnotes.png -------------------------------------------------------------------------------- /assets/imgs/musicnotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/musicnotation.png -------------------------------------------------------------------------------- /assets/imgs/internationalmusic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/assets/imgs/internationalmusic.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /test_driver/main_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:integration_test/integration_test_driver.dart'; 2 | 3 | Future main() => integrationDriver(); 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/40-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/40-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/40-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/40-2.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/58-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/80-1.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-hdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-ldpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-ldpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-mdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-xhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/120-1.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-xxhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/android/app/src/main/res/drawable-xxxhdpi/launch_screen.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iberatkaya/music-scales/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/kaya/musicapp/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kaya.musicapp 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | #dda930 5 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | json_key_file("./fastlane/play-console.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one 2 | package_name("com.kaya.musicapp") # e.g. com.krausefx.app 3 | -------------------------------------------------------------------------------- /ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("com.kaya.musicapp") # The bundle identifier of your app 2 | apple_id("ibkstelapps@gmail.com") # Your Apple email address 3 | 4 | itc_team_id("121028482") # App Store Connect Team ID 5 | team_id("QH78WN2XWN") # Developer Portal Team ID -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/application/actions/settings_action.dart: -------------------------------------------------------------------------------- 1 | enum SettingsActionType { 2 | setInstrument, 3 | setFastChordAudioSpeed, 4 | setShowFlatsInScales, 5 | setSettings, 6 | } 7 | 8 | class SettingsAction { 9 | SettingsActionType settingsActionType; 10 | dynamic payload; 11 | SettingsAction({ 12 | required this.settingsActionType, 13 | required this.payload, 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/application/store/store.dart: -------------------------------------------------------------------------------- 1 | import 'package:music_scales/application/reducers/settings_reducer.dart'; 2 | import 'package:music_scales/domain/settings/settings.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | final Store store = Store(settingsReducer, 6 | initialState: Settings( 7 | fastChordAudioSpeed: true, 8 | instrument: "Piano", 9 | showFlatsInScales: false)); 10 | -------------------------------------------------------------------------------- /ios/fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | default_platform(:ios) 2 | 3 | platform :ios do 4 | desc "Push a new release build to the App Store" 5 | lane :release do 6 | increment_build_number(xcodeproj: "Runner.xcodeproj") 7 | build_app(workspace: "Runner.xcworkspace", scheme: "Runner") 8 | upload_to_app_store( 9 | skip_metadata: true, 10 | skip_screenshots: true, 11 | submit_for_review: false 12 | ) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "new_music_scales", 9 | "request": "launch", 10 | "type": "dart", 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /android/fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | default_platform(:android) 2 | 3 | platform :android do 4 | desc "Deploy a new version to the Google Play" 5 | lane :deploy do 6 | gradle( 7 | task: "clean bundle", 8 | build_type: "Release" 9 | ) 10 | 11 | upload_to_play_store( 12 | package_name: "com.kaya.musicapp", 13 | release_status: "draft", 14 | aab: "../build/app/outputs/bundle/release/app-release.aab" 15 | ) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/domain/core/const.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const double textSize = 28.0; 4 | MaterialColor myColor = MaterialColor(0xffffaf00, { 5 | 50: Color(0xffffaf00), 6 | 100: Color(0xffffaf00), 7 | 200: Color(0xffffaf00), 8 | 300: Color(0xffffaf00), 9 | 400: Color(0xffffaf00), 10 | 500: Color(0xffffaf00), 11 | 600: Color(0xffffaf00), 12 | 700: Color(0xffffaf00), 13 | 800: Color(0xffffaf00), 14 | 900: Color(0xffffaf00), 15 | }); 16 | 17 | const int adFreq = 3; 18 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // @dart=2.9 2 | 3 | import 'package:firebase_admob/firebase_admob.dart'; 4 | import 'package:firebase_core/firebase_core.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:music_scales/presentation/core/my_app.dart'; 7 | 8 | import 'infrastructure/ads/ads.dart'; 9 | 10 | Future main() async { 11 | WidgetsFlutterBinding.ensureInitialized(); 12 | await Firebase.initializeApp(); 13 | await FirebaseAdMob.instance.initialize(appId: appid); 14 | runApp(MyApp()); 15 | } 16 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/domain/probability_post/probability_post.dart: -------------------------------------------------------------------------------- 1 | class ProbabilityPost { 2 | final String chord_ID; 3 | final String chord_HTML; 4 | final double probability; 5 | final String child_path; 6 | 7 | ProbabilityPost( 8 | {required this.chord_ID, 9 | required this.chord_HTML, 10 | required this.probability, 11 | required this.child_path}); 12 | 13 | factory ProbabilityPost.fromJson(Map json) { 14 | return ProbabilityPost( 15 | chord_ID: json['chord_ID'], 16 | chord_HTML: json['chord_HTML'], 17 | probability: json['probability'], 18 | child_path: json['child_path'], 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.3' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | } 26 | subprojects { 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /lib/application/reducers/settings_reducer.dart: -------------------------------------------------------------------------------- 1 | import 'package:music_scales/application/actions/settings_action.dart'; 2 | import 'package:music_scales/domain/settings/settings.dart'; 3 | 4 | Settings settingsReducer(Settings state, dynamic action) { 5 | if (action.settingsActionType == SettingsActionType.setInstrument) { 6 | return state.copyWith(instrument: action.payload); 7 | } 8 | if (action.settingsActionType == SettingsActionType.setFastChordAudioSpeed) { 9 | return state.copyWith(fastChordAudioSpeed: action.payload); 10 | } 11 | if (action.settingsActionType == SettingsActionType.setShowFlatsInScales) { 12 | return state.copyWith(showFlatsInScales: action.payload); 13 | } 14 | if (action.settingsActionType == SettingsActionType.setSettings) { 15 | return action.payload; 16 | } 17 | 18 | return state; 19 | } 20 | -------------------------------------------------------------------------------- /lib/domain/settings/settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class Settings { 4 | String instrument; 5 | bool showFlatsInScales; 6 | bool fastChordAudioSpeed; 7 | Settings({ 8 | required this.instrument, 9 | required this.showFlatsInScales, 10 | required this.fastChordAudioSpeed, 11 | }); 12 | 13 | Settings copyWith({ 14 | String? instrument, 15 | bool? showFlatsInScales, 16 | bool? fastChordAudioSpeed, 17 | }) { 18 | return Settings( 19 | instrument: instrument ?? this.instrument, 20 | showFlatsInScales: showFlatsInScales ?? this.showFlatsInScales, 21 | fastChordAudioSpeed: fastChordAudioSpeed ?? this.fastChordAudioSpeed, 22 | ); 23 | } 24 | 25 | @override 26 | String toString() => 27 | 'Settings(instrument: $instrument, showFlatsInScales: $showFlatsInScales, fastChordAudioSpeed: $fastChordAudioSpeed)'; 28 | } 29 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /lib/infrastructure/ads/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_admob/firebase_admob.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | import 'ads.dart'; 5 | import 'const.dart'; 6 | 7 | InterstitialAd? interstitialAd() => enableInterstitialAds 8 | ? InterstitialAd( 9 | adUnitId: interstitialid, 10 | targetingInfo: MobileAdTargetingInfo( 11 | testDevices: [deviceTestId], 12 | keywords: [ 13 | "Music", 14 | "Scales", 15 | "Guitar", 16 | "Piano", 17 | "Instrument", 18 | "Songs", 19 | "Chords" 20 | ], 21 | ), 22 | listener: (MobileAdEvent event) { 23 | print(event); 24 | if (event == MobileAdEvent.closed) { 25 | SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values); 26 | } 27 | if (event == MobileAdEvent.clicked) { 28 | SystemChrome.setEnabledSystemUIOverlays([]); 29 | } 30 | }, 31 | ) 32 | : null; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | lib/infrastructure/ads/ads.dart 13 | android/app/google-services.json 14 | ios/Runner/GoogleService-Info.plist 15 | *.keystore 16 | 17 | # fastlane 18 | android/fastlane/play-console.json 19 | android/fastlane/README.md 20 | android/fastlane/report.xml 21 | ios/fastlane/Preview.html 22 | ios/fastlane/README.md 23 | ios/fastlane/report.xml 24 | ios/*.zip 25 | ios/Runner.ipa 26 | 27 | # IntelliJ related 28 | *.iml 29 | *.ipr 30 | *.iws 31 | .idea/ 32 | 33 | # The .vscode folder contains launch configuration and tasks you configure in 34 | # VS Code which you may wish to be included in version control, so this line 35 | # is commented out by default. 36 | #.vscode/ 37 | 38 | # Flutter/Dart/Pub related 39 | **/doc/api/ 40 | **/ios/Flutter/.last_build_id 41 | .dart_tool/ 42 | .flutter-plugins 43 | .flutter-plugins-dependencies 44 | .packages 45 | .pub-cache/ 46 | .pub/ 47 | /build/ 48 | 49 | # Web related 50 | lib/generated_plugin_registrant.dart 51 | 52 | # Symbolication related 53 | app.*.symbols 54 | 55 | # Obfuscation related 56 | app.*.map.json 57 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:music_scales/presentation/core/my_app.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(MyApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /assets/imgs/international_music.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Welcome to Music Scales 👋

2 | 3 | Music Scales is a music theory mobile application that shows scales and chords for the piano and guitar. Check out the Android app and the iOS app. 4 | 5 |

6 | Screenshot 7 | Screenshot 8 | Screenshot 9 |

10 | 11 | ## Authors 12 | 13 | 👤 **Ibrahim Berat Kaya** 14 | 15 | - Github: [@iberatkaya](https://github.com/iberatkaya) 16 | - LinkedIn: [@linkedin.com/in/ibrahim-berat-kaya/](https://linkedin.com/in/ibrahim-berat-kaya/) 17 | 18 | ## 🤝 Contributing 19 | 20 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/iberatkaya/music-scales/issues). 21 | -------------------------------------------------------------------------------- /assets/imgs/music_notes.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/domain/notes/notes.dart: -------------------------------------------------------------------------------- 1 | class Note { 2 | String note; 3 | int index; 4 | Note(this.note, this.index); 5 | 6 | @override 7 | String toString() => 'Note(note: $note, index: $index)'; 8 | } 9 | 10 | List notes = [ 11 | Note("A", 0), 12 | Note("A#", 1), 13 | Note("B", 2), 14 | Note("C", 3), 15 | Note("C#", 4), 16 | Note("D", 5), 17 | Note("D#", 6), 18 | Note("E", 7), 19 | Note("F", 8), 20 | Note("F#", 9), 21 | Note("G", 10), 22 | Note("G#", 11), 23 | ]; 24 | 25 | class SNote extends Note { 26 | String note; 27 | String bemolle; 28 | int index; 29 | int audioindex; 30 | bool isBemolle = false; 31 | SNote(this.note, this.index, this.audioindex, this.bemolle) 32 | : super(note, index); 33 | 34 | @override 35 | String toString() { 36 | return 'SNote(note: $note, bemolle: $bemolle, index: $index, audioindex: $audioindex, isBemolle: $isBemolle)'; 37 | } 38 | } 39 | 40 | List sNotes = [ 41 | SNote("A", 0, 0, ""), 42 | SNote("A#", 1, 0, "Bb"), 43 | SNote("B", 2, 0, "Cb"), 44 | SNote("C", 3, 0, "B#"), 45 | SNote("C#", 4, 0, "Db"), 46 | SNote("D", 5, 0, ""), 47 | SNote("D#", 6, 0, "Eb"), 48 | SNote("E", 7, 0, "Fb"), 49 | SNote("F", 8, 0, "E#"), 50 | SNote("F#", 9, 0, "Gb"), 51 | SNote("G", 10, 0, ""), 52 | SNote("G#", 11, 0, "Ab"), 53 | ]; 54 | -------------------------------------------------------------------------------- /assets/imgs/piano.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/presentation/icons/my_flutter_app_icons.dart: -------------------------------------------------------------------------------- 1 | /// Flutter icons MyFlutterApp 2 | /// Copyright (C) 2019 by original authors @ fluttericon.com, fontello.com 3 | /// This font was generated by FlutterIcon.com, which is derived from Fontello. 4 | /// 5 | /// To use this font, place it in your fonts/ directory and include the 6 | /// following in your pubspec.yaml 7 | /// 8 | /// flutter: 9 | /// fonts: 10 | /// - family: MyFlutterApp 11 | /// fonts: 12 | /// - asset: fonts/MyFlutterApp.ttf 13 | /// 14 | /// 15 | /// 16 | import 'package:flutter/widgets.dart'; 17 | 18 | class MyFlutterApp { 19 | MyFlutterApp._(); 20 | 21 | static const _kFontFam = 'MyFlutterApp'; 22 | 23 | static const IconData quiz = const IconData(0xe800, fontFamily: _kFontFam); 24 | static const IconData guitar = const IconData(0xe801, fontFamily: _kFontFam); 25 | static const IconData piano = const IconData(0xe802, fontFamily: _kFontFam); 26 | static const IconData international_music = const IconData(0xe803, fontFamily: _kFontFam); 27 | static const IconData music_notation = const IconData(0xe804, fontFamily: _kFontFam); 28 | static const IconData music_notes = const IconData(0xe805, fontFamily: _kFontFam); 29 | static const IconData prog = const IconData(0xe806, fontFamily: _kFontFam); 30 | static const IconData x = const IconData(0xe807, fontFamily: _kFontFam); 31 | static const IconData metronome = const IconData(0xe808, fontFamily: _kFontFam); 32 | } 33 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/presentation/chords/widgets/note_cell.dart: -------------------------------------------------------------------------------- 1 | import 'package:audioplayers/audio_cache.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:music_scales/domain/core/const.dart'; 4 | 5 | class NoteCell extends StatelessWidget { 6 | final String instrument; 7 | final String note; 8 | final int noteIndex; 9 | 10 | NoteCell({ 11 | Key? key, 12 | required this.instrument, 13 | required this.note, 14 | required this.noteIndex, 15 | }) : super(key: key); 16 | 17 | final AudioCache audioc = new AudioCache(); 18 | 19 | Future playCache(String note, int index) async { 20 | //print("notes/${instrument.toLowerCase()}/${note.replaceAll("#", "s").toLowerCase()}$index.mp3"); 21 | await audioc.play( 22 | "notes/${instrument.toLowerCase()}/${note.replaceAll("#", "s").toLowerCase()}$index.mp3"); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return TableCell( 28 | child: FlatButton( 29 | color: Color.fromRGBO(230, 80, 80, 0.12), 30 | onPressed: () { 31 | playCache("$note", noteIndex); 32 | }, 33 | child: Container( 34 | child: Padding( 35 | padding: EdgeInsets.fromLTRB(0, textSize * 0.7, 0, textSize * 0.75), 36 | child: Center( 37 | child: Text( 38 | "$note", 39 | style: TextStyle( 40 | fontSize: textSize, 41 | color: Colors.red, 42 | fontWeight: FontWeight.w400), 43 | ), 44 | ), 45 | ), 46 | ), 47 | ), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /integration_test/app_test.dart: -------------------------------------------------------------------------------- 1 | // @dart=2.9 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:integration_test/integration_test.dart'; 6 | import 'package:music_scales/main.dart' as app; 7 | 8 | void main() { 9 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | testWidgets("Scale Page should launch", (WidgetTester tester) async { 12 | await app.main(); 13 | await tester.pumpAndSettle(); 14 | 15 | final Finder scalesPage = find.byKey(ValueKey("scale_page")); 16 | expect(scalesPage, findsOneWidget); 17 | }); 18 | 19 | testWidgets("Chord Page should launch", (WidgetTester tester) async { 20 | await app.main(); 21 | await tester.pumpAndSettle(); 22 | 23 | final Finder bottomNavbarChordPage = 24 | find.byKey(ValueKey("bottom_navbar_chord_page")); 25 | expect(bottomNavbarChordPage, findsOneWidget); 26 | 27 | await tester.tap(bottomNavbarChordPage); 28 | await tester.pumpAndSettle(); 29 | 30 | final Finder chordPage = find.byKey(ValueKey("chord_page")); 31 | expect(chordPage, findsOneWidget); 32 | }); 33 | 34 | testWidgets("Progression Page should launch", (WidgetTester tester) async { 35 | await app.main(); 36 | await tester.pumpAndSettle(); 37 | 38 | final Finder bottomNavbarUtilsPage = 39 | find.byKey(ValueKey("bottom_navbar_utils_page")); 40 | expect(bottomNavbarUtilsPage, findsOneWidget); 41 | 42 | await tester.tap(bottomNavbarUtilsPage); 43 | await tester.pumpAndSettle(); 44 | 45 | final Finder progressionPage = find.byKey(ValueKey("utils_page")); 46 | expect(progressionPage, findsOneWidget); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /assets/imgs/x.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 19 | 22 | 25 | 28 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Music Scales 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | music_scales 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 9 25 | GADApplicationIdentifier 26 | ca-app-pub-5374812845622263~5912676540 27 | LSApplicationQueriesSchemes 28 | 29 | itms 30 | 31 | LSRequiresIPhoneOS 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /lib/presentation/scale/widgets/note_cell.dart: -------------------------------------------------------------------------------- 1 | import 'package:audioplayers/audio_cache.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:music_scales/domain/core/const.dart'; 4 | 5 | class NoteCell extends StatelessWidget { 6 | final String note; 7 | final int audioIndex; 8 | final String instrument; 9 | final AudioCache audio = new AudioCache(); 10 | 11 | NoteCell({ 12 | Key? key, 13 | required this.note, 14 | required this.audioIndex, 15 | required this.instrument, 16 | }) : super(key: key); 17 | 18 | Future play(String note, int audioIndex) async { 19 | await audio.play( 20 | "notes/${instrument.toLowerCase()}/${note.replaceAll("#", "s").toLowerCase()}$audioIndex.mp3"); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return TableCell( 26 | child: FlatButton( 27 | color: Color.fromRGBO(230, 80, 80, 0.12), 28 | onPressed: () { 29 | String tempNote = note; 30 | if (note.length > 1) { 31 | if (note[1] == "b") { 32 | int tempint; 33 | tempint = note.codeUnitAt(0); 34 | tempint--; 35 | if (tempint < 65) tempint += 7; 36 | if (note.length == 3) 37 | tempNote = String.fromCharCode(tempint); 38 | else 39 | tempNote = String.fromCharCode(tempint) + "#"; 40 | } 41 | } 42 | //print("note is $note"); 43 | play("$tempNote", audioIndex); 44 | }, 45 | child: Container( 46 | child: Padding( 47 | padding: 48 | EdgeInsets.fromLTRB(0, textSize * 0.7, 0, textSize * 0.75), 49 | child: Text( 50 | "$note", 51 | maxLines: 1, 52 | style: TextStyle( 53 | fontSize: textSize, 54 | color: Colors.red, 55 | fontWeight: FontWeight.w400), 56 | )), 57 | ), 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/presentation/widgets/card/card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ButtonCard extends StatelessWidget { 4 | final Key? key; 5 | final void Function() onPressed; 6 | final Widget icon; 7 | final String title; 8 | final String subtitle; 9 | final Color color; 10 | final int titleSize; 11 | final int subtitleSize; 12 | const ButtonCard({ 13 | this.key, 14 | required this.onPressed, 15 | required this.icon, 16 | required this.title, 17 | required this.subtitle, 18 | required this.color, 19 | required this.titleSize, 20 | required this.subtitleSize, 21 | }); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return FlatButton( 26 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), 27 | onPressed: onPressed, 28 | color: color, 29 | padding: EdgeInsets.symmetric(vertical: 36), 30 | child: Column( 31 | children: [ 32 | Row( 33 | mainAxisAlignment: MainAxisAlignment.center, 34 | children: [ 35 | Text( 36 | title, 37 | style: TextStyle( 38 | color: Colors.white, 39 | fontSize: titleSize.toDouble(), 40 | fontWeight: FontWeight.w300), 41 | ), 42 | Padding( 43 | padding: EdgeInsets.only(left: 8), 44 | child: icon, 45 | ), 46 | ], 47 | ), 48 | Row( 49 | mainAxisAlignment: MainAxisAlignment.center, 50 | children: [ 51 | Expanded( 52 | child: Padding( 53 | padding: EdgeInsets.only(top: 16), 54 | child: Text( 55 | subtitle, 56 | style: TextStyle( 57 | color: Colors.white, 58 | fontSize: subtitleSize.toDouble(), 59 | fontWeight: FontWeight.w300), 60 | textAlign: TextAlign.center, 61 | )), 62 | ), 63 | ], 64 | ), 65 | ], 66 | ), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /assets/imgs/guitar.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 32 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/domain/scales/scales.dart: -------------------------------------------------------------------------------- 1 | class Scale { 2 | String name; 3 | int index; 4 | List formula; 5 | Scale(this.name, this.index, this.formula); 6 | 7 | @override 8 | String toString() => 'Scale(name: $name, index: $index, formula: $formula)'; 9 | } 10 | 11 | List scales = [ 12 | //A A# B C C# D D# E F F# G G# 13 | Scale("Major", 0, [2, 2, 1, 2, 2, 2]), 14 | Scale("Minor", 1, [2, 1, 2, 2, 1, 2]), 15 | Scale("Major Pentatonic", 12, [2, 2, 3, 2]), 16 | Scale("Minor Pentatonic", 13, [3, 2, 2, 3]), 17 | Scale("Blues", 2, [3, 2, 1, 1, 3]), 18 | Scale("Harmonic Minor", 3, [2, 1, 2, 2, 1, 3]), 19 | Scale("Melodic Minor", 4, [2, 1, 2, 2, 2, 2]), 20 | Scale("Ionian", 5, [2, 2, 1, 2, 2, 2]), 21 | Scale("Dorian", 6, [2, 1, 2, 2, 2, 1]), 22 | Scale("Mixolydian", 7, [2, 2, 1, 2, 2, 1]), 23 | Scale("Lydian", 8, [2, 2, 2, 1, 2, 2]), 24 | Scale("Phrygian", 9, [1, 2, 2, 2, 1, 2]), 25 | Scale("Aeolian", 10, [2, 1, 2, 2, 1, 2]), 26 | Scale("Locrian", 11, [1, 2, 2, 1, 2, 2]), 27 | Scale("Augmented", 14, [3, 1, 3, 1, 3]), 28 | Scale("Double Harmonic", 15, [1, 3, 1, 2, 1, 3]), 29 | Scale("Altered", 16, [1, 2, 1, 2, 2, 2]), 30 | Scale("Altered bb7", 39, [1, 2, 1, 2, 2, 1]), 31 | Scale("Dorian b2", 17, [1, 2, 2, 2, 2, 1]), 32 | Scale("Augmented Lydian", 18, [2, 2, 2, 2, 1, 2]), 33 | Scale("Lydian b7", 19, [2, 2, 2, 1, 2, 1]), 34 | Scale("Mixolydian b6", 20, [2, 2, 1, 2, 1, 2]), 35 | Scale("Locrian 6", 21, [1, 2, 2, 1, 3, 1]), 36 | Scale("Locrian 2", 40, [2, 1, 2, 1, 2, 2]), 37 | Scale("Augmented Ionian", 22, [2, 2, 1, 3, 1, 2]), 38 | Scale("Dorian #4", 23, [2, 1, 3, 1, 2, 1]), 39 | Scale("Major Phrygian", 24, [1, 3, 1, 2, 1, 2]), 40 | Scale("Lydian #9", 25, [3, 1, 2, 1, 2, 2]), 41 | Scale("Diminished Lydian", 26, [2, 1, 3, 1, 2, 2]), 42 | Scale("Minor Lydian", 27, [2, 2, 2, 1, 1, 2]), 43 | Scale("Arabian", 28, [2, 2, 1, 1, 2, 2]), 44 | Scale("Balinese", 29, [1, 2, 3, 2]), 45 | Scale("Byzantine", 30, [1, 3, 1, 2, 1, 3]), 46 | Scale("Chinese", 31, [4, 2, 1, 4]), 47 | Scale("Egyptian", 32, [2, 3, 2, 3]), 48 | Scale("Mongolian", 33, [2, 2, 3, 2]), 49 | Scale("Hindu", 34, [2, 2, 1, 2, 1, 2]), 50 | Scale("Neopolitan", 35, [1, 2, 2, 2, 1, 3]), 51 | Scale("Neopolitan Major", 36, [1, 2, 2, 2, 2, 2]), 52 | Scale("Neopolitan Minor", 37, [1, 2, 2, 2, 1, 2]), 53 | Scale("Persian", 38, [1, 3, 1, 1, 2, 3]) //Continue from 41 54 | ]; 55 | 56 | class ScaleandKey { 57 | String note; 58 | String scale; 59 | int index; 60 | ScaleandKey(this.note, this.scale, this.index); 61 | 62 | @override 63 | String toString() => 'ScaleandKey(note: $note, scale: $scale, index: $index)'; 64 | } 65 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | 25 | def keystoreProperties = new Properties() 26 | def keystorePropertiesFile = rootProject.file('key.properties') 27 | if (keystorePropertiesFile.exists()) { 28 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 29 | } 30 | 31 | apply plugin: 'com.android.application' 32 | apply plugin: 'kotlin-android' 33 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 34 | 35 | android { 36 | compileSdkVersion 29 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | lintOptions { 43 | disable 'InvalidPackage' 44 | } 45 | 46 | defaultConfig { 47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 48 | applicationId "com.kaya.musicapp" 49 | minSdkVersion 16 50 | targetSdkVersion 29 51 | multiDexEnabled true 52 | versionCode flutterVersionCode.toInteger() 53 | versionName flutterVersionName 54 | } 55 | 56 | signingConfigs { 57 | release { 58 | keyAlias keystoreProperties['keyAlias'] 59 | keyPassword keystoreProperties['keyPassword'] 60 | storeFile file(keystoreProperties['storeFile']) 61 | storePassword keystoreProperties['storePassword'] 62 | } 63 | } 64 | 65 | buildTypes { 66 | release { 67 | // TODO: Add your own signing config for the release build. 68 | // Signing with the debug keys for now, so `flutter run --release` works. 69 | signingConfig signingConfigs.release 70 | } 71 | } 72 | } 73 | 74 | flutter { 75 | source '../..' 76 | } 77 | 78 | dependencies { 79 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 80 | } 81 | 82 | apply plugin: 'com.google.gms.google-services' 83 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "40.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "60.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "58.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "87.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "80.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "120.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "120-1.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "180.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "20.png", 53 | "idiom" : "ipad", 54 | "scale" : "1x", 55 | "size" : "20x20" 56 | }, 57 | { 58 | "filename" : "40-1.png", 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "20x20" 62 | }, 63 | { 64 | "filename" : "29.png", 65 | "idiom" : "ipad", 66 | "scale" : "1x", 67 | "size" : "29x29" 68 | }, 69 | { 70 | "filename" : "58-1.png", 71 | "idiom" : "ipad", 72 | "scale" : "2x", 73 | "size" : "29x29" 74 | }, 75 | { 76 | "filename" : "40-2.png", 77 | "idiom" : "ipad", 78 | "scale" : "1x", 79 | "size" : "40x40" 80 | }, 81 | { 82 | "filename" : "80-1.png", 83 | "idiom" : "ipad", 84 | "scale" : "2x", 85 | "size" : "40x40" 86 | }, 87 | { 88 | "filename" : "76.png", 89 | "idiom" : "ipad", 90 | "scale" : "1x", 91 | "size" : "76x76" 92 | }, 93 | { 94 | "filename" : "152.png", 95 | "idiom" : "ipad", 96 | "scale" : "2x", 97 | "size" : "76x76" 98 | }, 99 | { 100 | "filename" : "167.png", 101 | "idiom" : "ipad", 102 | "scale" : "2x", 103 | "size" : "83.5x83.5" 104 | }, 105 | { 106 | "filename" : "1024.png", 107 | "idiom" : "ios-marketing", 108 | "scale" : "1x", 109 | "size" : "1024x1024" 110 | } 111 | ], 112 | "info" : { 113 | "author" : "xcode", 114 | "version" : 1 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /assets/imgs/prog.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 25 | 32 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: music_scales 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: "none" # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 2.0.3+60 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | cached_network_image: ^2.5.1 27 | audioplayers: ^0.17.0 28 | cupertino_icons: ^1.0.0 29 | firebase_admob: ^0.10.2 30 | firebase_analytics: ^6.2.0 31 | firebase_core: ^0.5.2+1 32 | flutter_redux: ^0.7.0 33 | flutter_swiper: ^1.1.6 34 | font_awesome_flutter: ^8.10.0 35 | launch_review: ^2.0.0 36 | redux: ^4.0.0+3 37 | share: ^0.6.5+4 38 | shared_preferences: ^0.5.12+4 39 | url_launcher: ^5.7.10 40 | 41 | dev_dependencies: 42 | integration_test: 43 | sdk: flutter 44 | flutter_test: 45 | sdk: flutter 46 | flutter_driver: 47 | sdk: flutter 48 | 49 | # For information on the generic Dart part of this file, see the 50 | # following page: https://dart.dev/tools/pub/pubspec 51 | # The following section is specific to Flutter. 52 | flutter: 53 | # The following line ensures that the Material Icons font is 54 | # included with your application, so that you can use the icons in 55 | # the material Icons class. 56 | uses-material-design: true 57 | fonts: 58 | - family: MyFlutterApp 59 | fonts: 60 | - asset: assets/fonts/MyFlutterApp.ttf 61 | # To add assets to your application, add an assets section, like this: 62 | assets: 63 | - assets/imgs/ 64 | - assets/notes/guitar/ 65 | - assets/notes/piano/ 66 | # To add assets to your application, add an assets section, like this: 67 | # assets: 68 | # - images/a_dot_burr.jpeg 69 | # - images/a_dot_ham.jpeg 70 | # An image asset can refer to one or more resolution-specific "variants", see 71 | # https://flutter.dev/assets-and-images/#resolution-aware. 72 | # For details regarding adding assets from package dependencies, see 73 | # https://flutter.dev/assets-and-images/#from-packages 74 | # To add custom fonts to your application, add a fonts section here, 75 | # in this "flutter" section. Each entry in this list should have a 76 | # "family" key with the font family name, and a "fonts" key with a 77 | # list giving the asset and other descriptors for the font. For 78 | # example: 79 | # fonts: 80 | # - family: Schyler 81 | # fonts: 82 | # - asset: fonts/Schyler-Regular.ttf 83 | # - asset: fonts/Schyler-Italic.ttf 84 | # style: italic 85 | # - family: Trajan Pro 86 | # fonts: 87 | # - asset: fonts/TrajanPro.ttf 88 | # - asset: fonts/TrajanPro_Bold.ttf 89 | # weight: 700 90 | # 91 | # For details regarding fonts from package dependencies, 92 | # see https://flutter.dev/custom-fonts/#from-packages 93 | -------------------------------------------------------------------------------- /integration_test/chord_test.dart: -------------------------------------------------------------------------------- 1 | // @dart=2.9 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:integration_test/integration_test.dart'; 6 | import 'package:music_scales/main.dart' as app; 7 | 8 | void main() { 9 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | Future launchChordPage(WidgetTester tester) async { 12 | await app.main(); 13 | await tester.pumpAndSettle(); 14 | 15 | final Finder bottomNavbarChordPage = 16 | find.byKey(ValueKey("bottom_navbar_chord_page")); 17 | expect(bottomNavbarChordPage, findsOneWidget); 18 | 19 | await tester.tap(bottomNavbarChordPage); 20 | await tester.pumpAndSettle(); 21 | 22 | final Finder chordPage = find.byKey(ValueKey("chord_page")); 23 | expect(chordPage, findsOneWidget); 24 | 25 | final Finder chordDetailButton = 26 | find.byKey(ValueKey("chord_detail_button")); 27 | expect(chordDetailButton, findsOneWidget); 28 | 29 | await tester.tap(chordDetailButton); 30 | await tester.pumpAndSettle(); 31 | } 32 | 33 | testWidgets("Chord Detail Page should launch", (WidgetTester tester) async { 34 | await launchChordPage(tester); 35 | }); 36 | 37 | testWidgets( 38 | "Chord Detail Page should display images with different keys, modes, and instruments", 39 | (WidgetTester tester) async { 40 | await launchChordPage(tester); 41 | 42 | Finder chordImage = find.byKey(ValueKey("A_Major_Piano_image")); 43 | expect(chordImage, findsOneWidget); 44 | 45 | final Finder chordKeyDropdownButton = 46 | find.byKey(ValueKey("chord_key_dropdown_button")); 47 | expect(chordKeyDropdownButton, findsOneWidget); 48 | 49 | final Finder chordNameDropdownButton = 50 | find.byKey(ValueKey("chord_name_dropdown_button")); 51 | expect(chordNameDropdownButton, findsOneWidget); 52 | 53 | await tester.tap(chordKeyDropdownButton); 54 | await tester.pumpAndSettle(); 55 | 56 | final Finder chordKeyDropdownButtonItem = 57 | find.byKey(ValueKey("dropdown_note_B")).last; 58 | expect(chordKeyDropdownButtonItem, findsOneWidget); 59 | 60 | await tester.tap(chordKeyDropdownButtonItem); 61 | await tester.pumpAndSettle(); 62 | 63 | chordImage = find.byKey(ValueKey("B_Major_Piano_image")); 64 | expect(chordImage, findsOneWidget); 65 | 66 | await tester.tap(chordNameDropdownButton); 67 | await tester.pumpAndSettle(); 68 | 69 | final Finder chordNameDropdownButtonItem = 70 | find.byKey(ValueKey("dropdown_chord_Minor")).last; 71 | 72 | await tester.tap(chordNameDropdownButtonItem); 73 | await tester.pumpAndSettle(); 74 | 75 | chordImage = find.byKey(ValueKey("B_Minor_Piano_image")); 76 | expect(chordImage, findsOneWidget); 77 | 78 | final Finder instrumentButton = find.byKey(ValueKey("instrument_button")); 79 | 80 | await tester.tap(instrumentButton); 81 | await tester.pumpAndSettle(); 82 | 83 | chordImage = find.byKey(ValueKey("B_Minor_Guitar_image")); 84 | expect(chordImage, findsOneWidget); 85 | }); 86 | 87 | testWidgets("Chord Detail Page should display helper dialog", 88 | (WidgetTester tester) async { 89 | await launchChordPage(tester); 90 | 91 | final Finder helpButton = find.byKey(ValueKey("help_button")); 92 | expect(helpButton, findsOneWidget); 93 | 94 | await tester.tap(helpButton); 95 | await tester.pumpAndSettle(); 96 | 97 | final Finder helpDialog = find.byKey(ValueKey("help_dialog")); 98 | expect(helpDialog, findsOneWidget); 99 | 100 | await tester.tapAt(Offset(10, 10)); 101 | await tester.pumpAndSettle(); 102 | 103 | expect(helpDialog, findsNothing); 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /assets/imgs/quiz.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 16 | 22 | 25 | 30 | 33 | 35 | 42 | 45 | 50 | 54 | 59 | 61 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /lib/presentation/core/my_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_analytics/firebase_analytics.dart'; 2 | import 'package:firebase_analytics/observer.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:music_scales/application/actions/settings_action.dart'; 5 | import 'package:music_scales/application/store/store.dart'; 6 | import 'package:music_scales/domain/core/const.dart'; 7 | import 'package:music_scales/domain/settings/settings.dart'; 8 | import 'package:music_scales/presentation/chords/chord_page.dart'; 9 | import 'package:music_scales/presentation/scale/scale_page.dart'; 10 | import 'package:music_scales/presentation/utils_pages/utils_page.dart'; 11 | import 'package:shared_preferences/shared_preferences.dart'; 12 | import '../icons/my_flutter_app_icons.dart' as CustomIcons; 13 | import 'drawer/drawer.dart'; 14 | 15 | class MyApp extends StatefulWidget { 16 | static FirebaseAnalytics analytics = FirebaseAnalytics(); 17 | static FirebaseAnalyticsObserver observer = 18 | FirebaseAnalyticsObserver(analytics: analytics); 19 | 20 | @override 21 | _MyAppState createState() => _MyAppState(); 22 | } 23 | 24 | class _MyAppState extends State { 25 | int index = 0; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | _loadSettings(); 31 | } 32 | 33 | Future _loadSettings() async { 34 | SharedPreferences prefs = await SharedPreferences.getInstance(); 35 | String defaultinstrument = (prefs.getString('instrument') ?? "Piano"); 36 | bool fastChordAudioSpeed = (prefs.getBool('fastChordAudioSpeed') ?? true); 37 | bool showFlatsInScales = (prefs.getBool('showFlatsInScales') ?? false); 38 | Settings settings = Settings( 39 | showFlatsInScales: showFlatsInScales, 40 | fastChordAudioSpeed: fastChordAudioSpeed, 41 | instrument: defaultinstrument, 42 | ); 43 | store.dispatch(SettingsAction( 44 | settingsActionType: SettingsActionType.setSettings, payload: settings)); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return MaterialApp( 50 | debugShowCheckedModeBanner: false, 51 | title: 'Music Scales', 52 | theme: ThemeData( 53 | primarySwatch: myColor, 54 | iconTheme: IconThemeData( 55 | size: 25, 56 | opacity: 1, 57 | ), 58 | ), 59 | navigatorObservers: [MyApp.observer], 60 | home: Scaffold( 61 | appBar: AppBar( 62 | title: Text("Music Scales", 63 | style: TextStyle( 64 | color: Color.fromRGBO(20, 20, 20, 1), 65 | )), 66 | elevation: 1, 67 | ), 68 | drawer: MyDrawer(), 69 | backgroundColor: Colors.white, 70 | body: IndexedStack( 71 | index: index, 72 | children: [ 73 | ScalePage(), 74 | ChordPage(), 75 | UtilsPage(), 76 | ], 77 | ), 78 | bottomNavigationBar: BottomNavigationBar( 79 | onTap: (newIndex) { 80 | setState(() { 81 | index = newIndex; 82 | }); 83 | }, 84 | currentIndex: index, 85 | showSelectedLabels: false, 86 | showUnselectedLabels: false, 87 | backgroundColor: myColor, 88 | selectedItemColor: Colors.white70, 89 | unselectedItemColor: Colors.black, 90 | items: [ 91 | BottomNavigationBarItem( 92 | icon: Icon( 93 | CustomIcons.MyFlutterApp.music_notes, 94 | key: ValueKey("bottom_navbar_scale_page"), 95 | ), 96 | label: "", 97 | ), 98 | BottomNavigationBarItem( 99 | icon: Icon( 100 | CustomIcons.MyFlutterApp.prog, 101 | key: ValueKey("bottom_navbar_chord_page"), 102 | ), 103 | label: "", 104 | ), 105 | BottomNavigationBarItem( 106 | icon: Icon( 107 | CustomIcons.MyFlutterApp.international_music, 108 | key: ValueKey("bottom_navbar_utils_page"), 109 | ), 110 | label: "", 111 | ), 112 | ], 113 | ), 114 | ), 115 | ); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lib/presentation/chords/chord_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:music_scales/domain/core/const.dart'; 3 | import 'package:music_scales/infrastructure/ads/utils.dart'; 4 | import 'package:music_scales/presentation/chords/search_chord.dart'; 5 | import 'package:music_scales/presentation/quiz/quiz.dart'; 6 | import 'package:music_scales/presentation/widgets/card/card.dart'; 7 | import '../icons/my_flutter_app_icons.dart' as CustomIcons; 8 | import 'chord_detail.dart'; 9 | 10 | class ChordPage extends StatefulWidget { 11 | @override 12 | _ChordPageState createState() => _ChordPageState(); 13 | } 14 | 15 | class _ChordPageState extends State { 16 | int showad = 0; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | key: ValueKey("chord_page"), 22 | body: SafeArea( 23 | child: ListView( 24 | physics: AlwaysScrollableScrollPhysics(), 25 | children: [ 26 | Padding( 27 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 28 | child: ButtonCard( 29 | key: ValueKey("chord_detail_button"), 30 | icon: Icon( 31 | CustomIcons.MyFlutterApp.prog, 32 | size: 48, 33 | color: Colors.green, 34 | ), 35 | onPressed: () async { 36 | showad++; 37 | if (showad % adFreq == 1) { 38 | final myInterstitialAd = interstitialAd(); 39 | await myInterstitialAd?.load(); 40 | await myInterstitialAd?.show(); 41 | } 42 | Navigator.push( 43 | context, 44 | MaterialPageRoute( 45 | builder: (context) => ChordDetailScreen())); 46 | }, 47 | subtitle: "Learn about chord progressions!", 48 | title: "Chords", 49 | color: Color.fromRGBO(130, 155, 240, 0.75), 50 | titleSize: 32, 51 | subtitleSize: 20, 52 | ), 53 | ), 54 | Padding( 55 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 56 | child: ButtonCard( 57 | icon: Padding( 58 | padding: EdgeInsets.only(left: 4), 59 | child: Icon( 60 | CustomIcons.MyFlutterApp.quiz, 61 | size: 48, 62 | color: Colors.blue, 63 | ), 64 | ), 65 | onPressed: () async { 66 | showad++; 67 | if (showad % adFreq == 1) { 68 | final myInterstitialAd = interstitialAd(); 69 | await myInterstitialAd?.load(); 70 | await myInterstitialAd?.show(); 71 | } 72 | Navigator.push(context, 73 | MaterialPageRoute(builder: (context) => QuizScreen())); 74 | }, 75 | subtitle: "Play a quiz about scales!", 76 | title: "Quiz", 77 | color: Color.fromRGBO(80, 190, 105, 0.6), 78 | titleSize: 32, 79 | subtitleSize: 20, 80 | ), 81 | ), 82 | Padding( 83 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 84 | child: ButtonCard( 85 | icon: Icon( 86 | Icons.search, 87 | size: 48, 88 | color: Colors.pink[600], 89 | ), 90 | onPressed: () async { 91 | showad++; 92 | if (showad % adFreq == 1) { 93 | final myInterstitialAd = interstitialAd(); 94 | await myInterstitialAd?.load(); 95 | await myInterstitialAd?.show(); 96 | } 97 | Navigator.push( 98 | context, 99 | MaterialPageRoute( 100 | builder: (context) => SearchChordScreen())); 101 | }, 102 | subtitle: "Search for a chord with a note!", 103 | title: "Chord Finder", 104 | color: Color.fromRGBO(120, 155, 210, 0.55), 105 | titleSize: 28, 106 | subtitleSize: 20, 107 | ), 108 | ), 109 | ], 110 | ), 111 | ), 112 | ); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /assets/imgs/the-scale.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /lib/presentation/scale/scale_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:music_scales/domain/core/const.dart'; 3 | import 'package:music_scales/infrastructure/ads/utils.dart'; 4 | import 'package:music_scales/presentation/scale/progression_detail.dart'; 5 | import 'package:music_scales/presentation/scale/scales_detail.dart'; 6 | import 'package:music_scales/presentation/scale/search.dart'; 7 | import 'package:music_scales/presentation/widgets/card/card.dart'; 8 | import '../icons/my_flutter_app_icons.dart' as CustomIcons; 9 | 10 | class ScalePage extends StatefulWidget { 11 | @override 12 | _ScalePageState createState() => _ScalePageState(); 13 | } 14 | 15 | class _ScalePageState extends State { 16 | int showad = 0; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | key: ValueKey("scale_page"), 22 | body: SafeArea( 23 | child: ListView( 24 | physics: AlwaysScrollableScrollPhysics(), 25 | children: [ 26 | Padding( 27 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 28 | child: ButtonCard( 29 | key: ValueKey("scale_page_button"), 30 | icon: Icon( 31 | CustomIcons.MyFlutterApp.music_notes, 32 | size: 48, 33 | color: Color.fromRGBO(200, 0, 0, 1), 34 | ), 35 | onPressed: () async { 36 | showad++; 37 | if (showad % adFreq == 1) { 38 | final myInterstitialAd = interstitialAd(); 39 | await myInterstitialAd?.load(); 40 | await myInterstitialAd?.show(); 41 | } 42 | Navigator.push( 43 | context, 44 | MaterialPageRoute( 45 | builder: (context) => ScalePrintScreen())); 46 | }, 47 | subtitle: "Learn about scales!", 48 | title: "Scales", 49 | color: Color.fromRGBO(30, 195, 195, 0.6), 50 | titleSize: 34, 51 | subtitleSize: 22, 52 | ), 53 | ), 54 | Padding( 55 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 56 | child: ButtonCard( 57 | icon: Icon( 58 | Icons.search, 59 | size: 48, 60 | color: Colors.deepPurple[600], 61 | ), 62 | onPressed: () async { 63 | showad++; 64 | if (showad % adFreq == 1) { 65 | final myInterstitialAd = interstitialAd(); 66 | await myInterstitialAd?.load(); 67 | await myInterstitialAd?.show(); 68 | } 69 | Navigator.push(context, 70 | MaterialPageRoute(builder: (context) => SearchScreen())); 71 | }, 72 | subtitle: "Search for a scale with a chord!", 73 | title: "Scale Finder", 74 | color: Color.fromRGBO(120, 155, 210, 0.55), 75 | titleSize: 32, 76 | subtitleSize: 20, 77 | ), 78 | ), 79 | Padding( 80 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 81 | child: ButtonCard( 82 | key: ValueKey("progression_page_button"), 83 | icon: Icon( 84 | CustomIcons.MyFlutterApp.prog, 85 | size: 48, 86 | color: Colors.green, 87 | ), 88 | onPressed: () async { 89 | showad++; 90 | if (showad % adFreq == 1) { 91 | final myInterstitialAd = interstitialAd(); 92 | await myInterstitialAd?.load(); 93 | await myInterstitialAd?.show(); 94 | } 95 | Navigator.push( 96 | context, 97 | MaterialPageRoute( 98 | builder: (context) => ProgPrintScreen())); 99 | }, 100 | subtitle: "Learn about chord progressions!", 101 | title: "Progressions", 102 | color: Color.fromRGBO(130, 155, 240, 0.75), 103 | titleSize: 30, 104 | subtitleSize: 20, 105 | ), 106 | ), 107 | ], 108 | ), 109 | ), 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/presentation/utils_pages/utils_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:music_scales/domain/core/const.dart'; 4 | import 'package:music_scales/infrastructure/ads/utils.dart'; 5 | import 'package:music_scales/presentation/utils_pages/chord_probability.dart'; 6 | import 'package:music_scales/presentation/utils_pages/example_songs.dart'; 7 | import 'package:music_scales/presentation/utils_pages/piano.dart'; 8 | import 'package:music_scales/presentation/widgets/card/card.dart'; 9 | import '../icons/my_flutter_app_icons.dart' as CustomIcons; 10 | 11 | class UtilsPage extends StatefulWidget { 12 | @override 13 | _UtilsPageState createState() => _UtilsPageState(); 14 | } 15 | 16 | class _UtilsPageState extends State { 17 | int showad = 0; 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | key: ValueKey("utils_page"), 22 | body: SafeArea( 23 | child: ListView( 24 | physics: AlwaysScrollableScrollPhysics(), 25 | children: [ 26 | Padding( 27 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 28 | child: ButtonCard( 29 | icon: Padding( 30 | padding: EdgeInsets.only(left: 4), 31 | child: Icon( 32 | FontAwesomeIcons.dice, 33 | size: 48, 34 | color: Colors.blueGrey, 35 | ), 36 | ), 37 | onPressed: () async { 38 | showad++; 39 | if (showad % adFreq == 1) { 40 | final myInterstitialAd = interstitialAd(); 41 | await myInterstitialAd?.load(); 42 | await myInterstitialAd?.show(); 43 | } 44 | Navigator.push( 45 | context, 46 | MaterialPageRoute( 47 | builder: (context) => ChordProbScreen())); 48 | }, 49 | subtitle: "View possibilites about popular chord progressions!", 50 | title: "Chord Possibility", 51 | color: Color.fromRGBO(220, 70, 70, 0.75), 52 | titleSize: 24, 53 | subtitleSize: 16, 54 | ), 55 | ), 56 | Padding( 57 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 58 | child: ButtonCard( 59 | icon: Icon( 60 | CustomIcons.MyFlutterApp.piano, 61 | size: 48, 62 | color: Colors.black, 63 | ), 64 | onPressed: () async { 65 | showad++; 66 | if (showad % adFreq == 1) { 67 | final myInterstitialAd = interstitialAd(); 68 | await myInterstitialAd?.load(); 69 | await myInterstitialAd?.show(); 70 | } 71 | Navigator.push(context, 72 | MaterialPageRoute(builder: (context) => PianoScreen())); 73 | }, 74 | subtitle: "Play notes on a piano!", 75 | title: "Piano", 76 | color: Color.fromRGBO(180, 105, 10, 0.55), 77 | titleSize: 32, 78 | subtitleSize: 20, 79 | ), 80 | ), 81 | Padding( 82 | padding: EdgeInsets.fromLTRB(16, 16, 16, 4), 83 | child: ButtonCard( 84 | icon: Icon( 85 | FontAwesomeIcons.headphones, 86 | size: 48, 87 | color: Colors.brown[400], 88 | ), 89 | onPressed: () async { 90 | showad++; 91 | if (showad % adFreq == 1) { 92 | final myInterstitialAd = interstitialAd(); 93 | await myInterstitialAd?.load(); 94 | await myInterstitialAd?.show(); 95 | } 96 | Navigator.push( 97 | context, 98 | MaterialPageRoute( 99 | builder: (context) => SongsListScreen())); 100 | }, 101 | subtitle: "View example songs with a progression!", 102 | title: "Example Songs", 103 | color: Color.fromRGBO(180, 95, 180, 0.55), 104 | titleSize: 26, 105 | subtitleSize: 16, 106 | ), 107 | ), 108 | ], 109 | ), 110 | ), 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/presentation/core/drawer/drawer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:launch_review/launch_review.dart'; 5 | import 'package:music_scales/presentation/settings/settings.dart'; 6 | import 'package:share/share.dart'; 7 | import 'package:url_launcher/url_launcher.dart'; 8 | 9 | class MyDrawer extends StatelessWidget { 10 | Future _launchPrivPol() async { 11 | const url = "https://kayaib17.github.io/MusicScalesPrivacyPolicy/"; 12 | if (await canLaunch(url)) { 13 | await launch(url); 14 | } else { 15 | throw 'Could not launch $url'; 16 | } 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Drawer( 22 | child: ListView( 23 | physics: AlwaysScrollableScrollPhysics(), 24 | padding: EdgeInsets.zero, 25 | children: [ 26 | Container( 27 | //height: 110, 28 | color: Colors.orangeAccent, 29 | child: DrawerHeader( 30 | margin: EdgeInsets.zero, 31 | padding: EdgeInsets.zero, 32 | child: Image( 33 | fit: BoxFit.fill, image: AssetImage('assets/imgs/logo.jpg')), 34 | ), 35 | ), 36 | ListTile( 37 | contentPadding: EdgeInsets.fromLTRB(14, 0, 0, 0), 38 | title: Text('Settings', style: TextStyle(fontSize: 15)), 39 | leading: Icon(Icons.settings, size: 24, color: Colors.grey[600]), 40 | onTap: () { 41 | Navigator.pop(context); 42 | Navigator.push(context, 43 | MaterialPageRoute(builder: (context) => SettingsScreen())); 44 | }, 45 | ), 46 | Divider( 47 | height: 0, 48 | color: Colors.black26, 49 | ), 50 | ListTile( 51 | contentPadding: EdgeInsets.fromLTRB(14, 0, 0, 0), 52 | title: Text('Rate App', style: TextStyle(fontSize: 15)), 53 | leading: Icon(Icons.star, size: 24, color: Colors.grey[600]), 54 | onTap: () { 55 | LaunchReview.launch( 56 | androidAppId: "com.kaya.musicapp", iOSAppId: "1498463498"); 57 | }, 58 | ), 59 | Divider( 60 | height: 0, 61 | color: Colors.black26, 62 | ), 63 | ListTile( 64 | contentPadding: EdgeInsets.fromLTRB(14, 0, 0, 0), 65 | title: Text('Share App', style: TextStyle(fontSize: 15)), 66 | leading: Icon(Icons.share, size: 24, color: Colors.grey[600]), 67 | onTap: () { 68 | if (Platform.isAndroid) { 69 | Share.share( 70 | 'Music Scales: https://play.google.com/store/apps/details?id=com.kaya.musicapp'); 71 | } else { 72 | Share.share( 73 | 'Music Scales: https://apps.apple.com/us/app/music-scales/id1498463498'); 74 | } 75 | }, 76 | ), 77 | Divider( 78 | height: 0, 79 | color: Colors.black26, 80 | ), 81 | ListTile( 82 | contentPadding: EdgeInsets.fromLTRB(14, 0, 0, 0), 83 | title: Text('About', 84 | style: TextStyle(fontSize: 15, color: Colors.black87)), 85 | leading: 86 | Icon(Icons.help_outline, size: 24, color: Colors.grey[600]), 87 | onTap: () { 88 | showAboutDialog( 89 | applicationIcon: Tab( 90 | icon: Image.asset("assets/imgs/appicon.png"), 91 | ), 92 | applicationName: "Music Scales", 93 | context: context, 94 | children: [ 95 | Text( 96 | "Music Scales is an app that shows the user the notes of a scale or a chord in a selected key, and shows chord progressions for free. The simple design lets the user quickly learn the chords, scales, and progressions on a piano and on a guitar."), 97 | Padding( 98 | padding: EdgeInsets.fromLTRB(10, 16, 14, 0), 99 | child: FlatButton( 100 | color: Color.fromRGBO(250, 240, 240, 0.6), 101 | child: Text("Privacy Policy", 102 | style: TextStyle( 103 | color: Colors.grey[800], fontSize: 11)), 104 | onPressed: () { 105 | _launchPrivPol(); 106 | })), 107 | ], 108 | ); 109 | }, 110 | ), 111 | ], 112 | ), 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /assets/imgs/metronome.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.15, written by Peter Selinger 2001-2017 9 | 10 | 12 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /lib/domain/chords/chords.dart: -------------------------------------------------------------------------------- 1 | class Chord { 2 | String note; 3 | int index; 4 | List formula; 5 | Chord(this.note, this.index, this.formula); 6 | 7 | @override 8 | String toString() => 'Chord(note: $note, index: $index, formula: $formula)'; 9 | } 10 | 11 | class SmallChord { 12 | String name; 13 | String mode; 14 | int index; 15 | SmallChord(this.name, this.mode, this.index); 16 | 17 | @override 18 | String toString() => 'SmallChord(name: $name, mode: $mode, index: $index)'; 19 | } 20 | 21 | List chords = [ 22 | //A A# B C C# D D# E F F# G G# 23 | Chord("Major", 0, [4, 3]), 24 | Chord("Minor", 1, [3, 4]), 25 | Chord("Sus2", 3, [2, 5]), 26 | Chord("Sus4", 4, [5, 2]), 27 | Chord("Diminished", 7, [3, 3]), 28 | Chord("Augmented", 8, [4, 4]), 29 | Chord("7th", 6, [4, 3, 3]), 30 | Chord("Major 7th", 2, [4, 3, 4]), 31 | Chord("Minor 7th", 5, [3, 4, 3]), 32 | Chord("m(maj7)", 27, [3, 4, 4]), 33 | Chord("m7b5", 13, [3, 3, 4]), 34 | Chord("m7#5", 21, [3, 5, 2]), 35 | Chord("7b5", 15, [4, 2, 4]), 36 | Chord("7#5", 16, [4, 4, 2]), 37 | Chord("Diminished 7th", 14, [3, 3, 3]), 38 | Chord("Add2", 30, [2, 2, 3]), 39 | Chord("Add4", 31, [4, 1, 2]), 40 | Chord("6th", 10, [4, 3, 2]), 41 | Chord("Minor 6th", 11, [3, 4, 2]), 42 | Chord("6th/9th", 12, [4, 3, 2, 5]), 43 | Chord("9th", 9, [4, 3, 3, 4]), 44 | Chord("Major 9th", 18, [4, 3, 4, 3]), //A A# B C C# D D# E F F# G G# 45 | Chord("Minor 9th", 17, [3, 4, 3, 4]), 46 | Chord("m(maj9)", 28, [3, 4, 4, 3]), 47 | Chord("9b5", 20, [4, 2, 4, 4]), 48 | Chord("9#5", 19, [4, 4, 2, 4]), 49 | Chord("11th", 22, [4, 3, 3, 4, 3]), 50 | Chord("Major 11th", 23, [4, 3, 4, 3, 3]), 51 | Chord("Minor 11th", 24, [3, 4, 3, 4, 3]), 52 | Chord("m(maj11)", 29, [3, 4, 4, 3, 3]), 53 | Chord("11b5", 25, [4, 2, 4, 4, 3]), 54 | Chord("11#5", 26, [4, 4, 2, 4, 3]) //Continue from 32 55 | ]; 56 | 57 | class ChordNote { 58 | String note; 59 | int index; 60 | int audioindex; 61 | ChordNote(this.note, this.index, this.audioindex); 62 | } 63 | 64 | List chordNotes = [ 65 | ChordNote("A", 0, 0), 66 | ChordNote("A#", 1, 0), 67 | ChordNote("B", 2, 0), 68 | ChordNote("C", 3, 0), 69 | ChordNote("C#", 4, 0), 70 | ChordNote("D", 5, 0), 71 | ChordNote("D#", 6, 0), 72 | ChordNote("E", 7, 0), 73 | ChordNote("F", 8, 0), 74 | ChordNote("F#", 9, 0), 75 | ChordNote("G", 10, 0), 76 | ChordNote("G#", 11, 0), 77 | ]; 78 | 79 | List majorChords = [ 80 | SmallChord("A", "M", 0), 81 | SmallChord("A#", "M", 1), 82 | SmallChord("B", "M", 2), 83 | SmallChord("C", "M", 3), 84 | SmallChord("C#", "M", 4), 85 | SmallChord("D", "M", 5), 86 | SmallChord("D#", "M", 6), 87 | SmallChord("E", "M", 7), 88 | SmallChord("F", "M", 8), 89 | SmallChord("F#", "M", 9), 90 | SmallChord("G", "M", 10), 91 | SmallChord("G#", "M", 11), 92 | ]; 93 | List minorChords = [ 94 | SmallChord("Am", "m", 0), 95 | SmallChord("A#m", "m", 1), 96 | SmallChord("Bm", "m", 2), 97 | SmallChord("Cm", "m", 3), 98 | SmallChord("C#m", "m", 4), 99 | SmallChord("Dm", "m", 5), 100 | SmallChord("D#m", "m", 6), 101 | SmallChord("Em", "m", 7), 102 | SmallChord("Fm", "m", 8), 103 | SmallChord("F#m", "m", 9), 104 | SmallChord("Gm", "m", 10), 105 | SmallChord("G#m", "m", 11), 106 | ]; 107 | List dimChords = [ 108 | SmallChord("Adim", "dim", 0), 109 | SmallChord("A#dim", "dim", 1), 110 | SmallChord("Bdim", "dim", 2), 111 | SmallChord("Cdim", "dim", 3), 112 | SmallChord("C#dim", "dim", 4), 113 | SmallChord("Ddim", "dim", 5), 114 | SmallChord("D#dim", "dim", 6), 115 | SmallChord("Edim", "dim", 7), 116 | SmallChord("Fdim", "dim", 8), 117 | SmallChord("F#dim", "dim", 9), 118 | SmallChord("Gdim", "dim", 10), 119 | SmallChord("G#dim", "dim", 11), 120 | ]; 121 | 122 | List searchChords = [ 123 | //A A# B C C# D D# E F F# G G# 124 | Chord("Major", 0, [4, 3]), 125 | Chord("Minor", 1, [3, 4]), 126 | Chord("Sus2", 3, [2, 5]), 127 | Chord("Sus4", 4, [5, 2]), 128 | Chord("Diminished", 7, [3, 3]), 129 | Chord("Augmented", 8, [4, 4]), 130 | Chord("7th", 6, [4, 3, 3]), 131 | Chord("Major 7th", 2, [4, 3, 4]), 132 | Chord("Minor 7th", 5, [3, 4, 3]), 133 | Chord("m(maj7)", 27, [3, 4, 4]), 134 | Chord("m7b5", 13, [3, 3, 4]), 135 | Chord("m7#5", 21, [3, 5, 2]), 136 | Chord("7b5", 15, [4, 2, 4]), 137 | Chord("7#5", 16, [4, 4, 2]), 138 | Chord("Diminished 7th", 14, [3, 3, 3]), 139 | Chord("Add2", 30, [2, 2, 3]), 140 | Chord("Add4", 31, [4, 1, 2]), 141 | Chord("6th", 10, [4, 3, 2]), 142 | Chord("Minor 6th", 11, [3, 4, 2]), 143 | Chord("6th/9th", 12, [4, 3, 2, 5]), 144 | Chord("9th", 9, [4, 3, 3, 4]), 145 | Chord("Major 9th", 18, [4, 3, 4, 3]), //A A# B C C# D D# E F F# G G# 146 | Chord("Minor 9th", 17, [3, 4, 3, 4]), 147 | Chord("m(maj9)", 28, [3, 4, 4, 3]), 148 | Chord("9b5", 20, [4, 2, 4, 4]), 149 | Chord("9#5", 19, [4, 4, 2, 4]), 150 | Chord("11th", 22, [4, 3, 3, 4, 3]), 151 | Chord("Major 11th", 23, [4, 3, 4, 3, 3]), 152 | Chord("Minor 11th", 24, [3, 4, 3, 4, 3]), 153 | Chord("m(maj11)", 29, [3, 4, 4, 3, 3]), 154 | Chord("11b5", 25, [4, 2, 4, 4, 3]), 155 | Chord("11#5", 26, [4, 4, 2, 4, 3]) //Continue from 32 156 | ]; 157 | -------------------------------------------------------------------------------- /integration_test/scale_test.dart: -------------------------------------------------------------------------------- 1 | // @dart=2.9 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:integration_test/integration_test.dart'; 6 | import 'package:music_scales/main.dart' as app; 7 | 8 | void main() { 9 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | Future launchScalePage(WidgetTester tester) async { 12 | await app.main(); 13 | await tester.pumpAndSettle(); 14 | 15 | final Finder scalesPageButton = find.byKey(ValueKey("scale_page_button")); 16 | expect(scalesPageButton, findsOneWidget); 17 | 18 | await tester.tap(scalesPageButton); 19 | await tester.pumpAndSettle(); 20 | 21 | final Finder scaleDetailPage = find.byKey(ValueKey("scale_detail_page")); 22 | expect(scaleDetailPage, findsOneWidget); 23 | } 24 | 25 | Future launchProgressionPage(WidgetTester tester) async { 26 | await app.main(); 27 | await tester.pumpAndSettle(); 28 | 29 | final Finder progressionDetailPage = 30 | find.byKey(ValueKey("progression_page_button")); 31 | expect(progressionDetailPage, findsOneWidget); 32 | 33 | await tester.tap(progressionDetailPage); 34 | await tester.pumpAndSettle(); 35 | } 36 | 37 | testWidgets("Scale Detail Page should launch", (WidgetTester tester) async { 38 | await launchScalePage(tester); 39 | }); 40 | 41 | testWidgets( 42 | "Scale Detail Page should display images with different keys, modes, and instruments", 43 | (WidgetTester tester) async { 44 | await launchScalePage(tester); 45 | 46 | Finder scaleImage = find.byKey(ValueKey("A_Major_Piano_image")); 47 | expect(scaleImage, findsOneWidget); 48 | 49 | final Finder scaleKeyDropdownButton = 50 | find.byKey(ValueKey("scale_key_dropdown_button")); 51 | expect(scaleKeyDropdownButton, findsOneWidget); 52 | 53 | final Finder scaleNameDropdownButton = 54 | find.byKey(ValueKey("scale_name_dropdown_button")); 55 | expect(scaleNameDropdownButton, findsOneWidget); 56 | 57 | await tester.tap(scaleKeyDropdownButton); 58 | await tester.pumpAndSettle(); 59 | 60 | final Finder scaleKeyDropdownButtonItem = 61 | find.byKey(ValueKey("dropdown_note_B")).last; 62 | expect(scaleKeyDropdownButtonItem, findsOneWidget); 63 | 64 | await tester.tap(scaleKeyDropdownButtonItem); 65 | await tester.pumpAndSettle(); 66 | 67 | scaleImage = find.byKey(ValueKey("B_Major_Piano_image")); 68 | expect(scaleImage, findsOneWidget); 69 | 70 | await tester.tap(scaleNameDropdownButton); 71 | await tester.pumpAndSettle(); 72 | 73 | final Finder scaleNameDropdownButtonItem = 74 | find.byKey(ValueKey("dropdown_scale_Minor")).last; 75 | 76 | await tester.tap(scaleNameDropdownButtonItem); 77 | await tester.pumpAndSettle(); 78 | 79 | scaleImage = find.byKey(ValueKey("B_Minor_Piano_image")); 80 | expect(scaleImage, findsOneWidget); 81 | 82 | final Finder instrumentButton = find.byKey(ValueKey("instrument_button")); 83 | 84 | await tester.tap(instrumentButton); 85 | await tester.pumpAndSettle(); 86 | 87 | scaleImage = find.byKey(ValueKey("B_Minor_Guitar_image")); 88 | expect(scaleImage, findsOneWidget); 89 | }); 90 | 91 | testWidgets("Scale Detail Page should display helper dialog", 92 | (WidgetTester tester) async { 93 | await launchScalePage(tester); 94 | 95 | final Finder helpButton = find.byKey(ValueKey("help_button")); 96 | expect(helpButton, findsOneWidget); 97 | 98 | await tester.tap(helpButton); 99 | await tester.pumpAndSettle(); 100 | 101 | final Finder helpDialog = find.byKey(ValueKey("help_dialog")); 102 | expect(helpDialog, findsOneWidget); 103 | 104 | await tester.tapAt(Offset(10, 10)); 105 | await tester.pumpAndSettle(); 106 | 107 | expect(helpDialog, findsNothing); 108 | }); 109 | 110 | testWidgets( 111 | "Progression Detail Page should display progressions with different keys and modes", 112 | (WidgetTester tester) async { 113 | await launchProgressionPage(tester); 114 | 115 | final Finder progressionKeyDropdownButton = 116 | find.byKey(ValueKey("progression_key_dropdown_button")); 117 | expect(progressionKeyDropdownButton, findsOneWidget); 118 | 119 | await tester.tap(progressionKeyDropdownButton); 120 | await tester.pumpAndSettle(); 121 | 122 | final Finder progressionKeyB = 123 | find.byKey(ValueKey("progression_key_B")).last; 124 | expect(progressionKeyB, findsOneWidget); 125 | 126 | await tester.tap(progressionKeyB); 127 | await tester.pumpAndSettle(); 128 | 129 | final Finder progressionChordDropdownButton = 130 | find.byKey(ValueKey("progression_chord_dropdown_button")); 131 | expect(progressionChordDropdownButton, findsOneWidget); 132 | 133 | await tester.tap(progressionChordDropdownButton); 134 | await tester.pumpAndSettle(); 135 | 136 | final Finder progressionChordMinor = 137 | find.byKey(ValueKey("progression_chord_Minor")).last; 138 | expect(progressionChordMinor, findsOneWidget); 139 | 140 | await tester.tap(progressionChordMinor); 141 | await tester.pumpAndSettle(); 142 | 143 | final Finder cSharpDimChord = find.text("C#dim"); 144 | expect(cSharpDimChord, findsOneWidget); 145 | }); 146 | } 147 | -------------------------------------------------------------------------------- /lib/presentation/scale/utils/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:music_scales/domain/notes/notes.dart'; 2 | 3 | ///Set the table number headers based on the [mode]. 4 | List updateTableNums(String mode) { 5 | List nums = ["1", "2", "3", "4", "5", "6", "7"]; 6 | if (mode == "Minor") { 7 | nums[2] = "b3"; 8 | nums[5] = "b6"; 9 | nums[6] = "b7"; 10 | } else if (mode == "Blues") { 11 | nums[1] = "b3"; 12 | nums[2] = "4"; 13 | nums[3] = "#4"; 14 | nums[4] = "5"; 15 | nums[5] = "b7"; 16 | } else if (mode == "Melodic Minor") 17 | nums[2] = "b3"; 18 | else if (mode == "Harmonic Minor") { 19 | nums[2] = "b3"; 20 | nums[5] = "b6"; 21 | } else if (mode == "Dorian") { 22 | nums[2] = "b3"; 23 | nums[6] = "b7"; 24 | } else if (mode == "Mixolydian") 25 | nums[6] = "b7"; 26 | else if (mode == "Lydian") 27 | nums[3] = "#4"; 28 | else if (mode == "Phrygian") { 29 | nums[1] = "b2"; 30 | nums[2] = "b3"; 31 | nums[5] = "b6"; 32 | nums[6] = "b7"; 33 | } else if (mode == "Aeolian") { 34 | nums[2] = "b3"; 35 | nums[5] = "b6"; 36 | nums[6] = "b7"; 37 | } else if (mode == "Locrian") { 38 | nums[1] = "b2"; 39 | nums[2] = "b3"; 40 | nums[4] = "b5"; 41 | nums[5] = "b6"; 42 | nums[6] = "b7"; 43 | } else if (mode == "Locrian 2") { 44 | nums[2] = "b3"; 45 | nums[4] = "b5"; 46 | nums[5] = "b6"; 47 | nums[6] = "b7"; 48 | } else if (mode == "Major Pentatonic") { 49 | nums[3] = "5"; 50 | nums[4] = "6"; 51 | } else if (mode == "Minor Pentatonic") { 52 | nums[1] = "b3"; 53 | nums[2] = "4"; 54 | nums[3] = "5"; 55 | nums[4] = "b7"; 56 | } else if (mode == "Augmented") { 57 | nums[1] = "b3"; 58 | nums[3] = "5"; 59 | nums[4] = "#5"; 60 | nums[5] = "7"; 61 | } else if (mode == "Double Harmonic") { 62 | nums[1] = "b2"; 63 | nums[5] = "b6"; 64 | } else if (mode == "Altered") { 65 | nums[1] = "b2"; 66 | nums[2] = "b3"; 67 | nums[3] = "b4"; 68 | nums[4] = "b5"; 69 | nums[5] = "b6"; 70 | nums[6] = "b7"; 71 | } else if (mode == "Altered bb7") { 72 | nums[1] = "b2"; 73 | nums[2] = "b3"; 74 | nums[3] = "b4"; 75 | nums[4] = "b5"; 76 | nums[5] = "b6"; 77 | nums[6] = "bb7"; 78 | } else if (mode == "Dorian b2") { 79 | nums[1] = "b2"; 80 | nums[2] = "b3"; 81 | nums[6] = "b7"; 82 | } else if (mode == "Augmented Lydian") { 83 | nums[3] = "#4"; 84 | nums[4] = "#5"; 85 | } else if (mode == "Lydian b7") { 86 | nums[3] = "#4"; 87 | nums[6] = "b7"; 88 | } else if (mode == "Mixolydian b6") { 89 | nums[5] = "b6"; 90 | nums[6] = "b7"; 91 | } else if (mode == "Locrian 6") { 92 | nums[1] = "b2"; 93 | nums[2] = "b3"; 94 | nums[4] = "b5"; 95 | nums[6] = "b7"; 96 | } else if (mode == "Augmented Ionian") 97 | nums[4] = "#5"; 98 | else if (mode == "Dorian #4") { 99 | nums[2] = "b3"; 100 | nums[3] = "#4"; 101 | nums[6] = "b7"; 102 | } else if (mode == "Major Phrygian") { 103 | nums[1] = "b2"; 104 | nums[5] = "b6"; 105 | nums[6] = "b7"; 106 | } else if (mode == "Lydian #9") { 107 | nums[1] = "#2"; 108 | nums[3] = "#4"; 109 | } else if (mode == "Diminished Lydian") { 110 | nums[2] = "b3"; 111 | nums[3] = "#4"; 112 | } else if (mode == "Minor Lydian") { 113 | nums[3] = "#4"; 114 | nums[5] = "b6"; 115 | nums[6] = "b7"; 116 | } else if (mode == "Arabian") { 117 | nums[4] = "#4"; 118 | nums[5] = "#5"; 119 | nums[6] = "b7"; 120 | } else if (mode == "Balinese") { 121 | nums[1] = "b2"; 122 | nums[2] = "b3"; 123 | nums[3] = "5"; 124 | nums[4] = "b6"; 125 | } else if (mode == "Byzantine") { 126 | nums[1] = "b2"; 127 | nums[5] = "b6"; 128 | } else if (mode == "Chinese") { 129 | nums[1] = "3"; 130 | nums[2] = "#4"; 131 | nums[3] = "5"; 132 | nums[4] = "7"; 133 | } else if (mode == "Egyptian") { 134 | nums[2] = "4"; 135 | nums[3] = "5"; 136 | nums[4] = "b7"; 137 | } else if (mode == "Mongolian") { 138 | nums[3] = "5"; 139 | nums[4] = "6"; 140 | } else if (mode == "Hindu") { 141 | nums[5] = "b6"; 142 | nums[6] = "b7"; 143 | } else if (mode == "Neopolitan") { 144 | nums[1] = "b2"; 145 | nums[2] = "b3"; 146 | nums[5] = "b6"; 147 | } else if (mode == "Neopolitan Major") { 148 | nums[1] = "b2"; 149 | nums[2] = "b3"; 150 | } else if (mode == "Neopolitan Minor") { 151 | nums[1] = "b2"; 152 | nums[2] = "b3"; 153 | nums[5] = "b6"; 154 | nums[6] = "b7"; 155 | } else if (mode == "Persian") { 156 | nums[1] = "b2"; 157 | nums[4] = "b5"; 158 | nums[5] = "b6"; 159 | } 160 | return nums; 161 | } 162 | 163 | ///Create the url for the scale based on the [mode], [notes], and [instrument]. 164 | String urlScale(String mode, List notes, String instrument) { 165 | String url; 166 | String n_or_sharp; 167 | if (!notes[0].note.contains("#")) 168 | n_or_sharp = "n"; 169 | else 170 | n_or_sharp = "sharp"; 171 | if (mode == "Minor") 172 | url = "$instrument-natural_minor-${notes[0].note[0]}-$n_or_sharp"; 173 | else if (mode.contains(" ")) { 174 | url = 175 | "$instrument-${mode.toLowerCase().replaceFirst(" ", "_").replaceFirst("#", "s")}-${notes[0].note[0]}-$n_or_sharp"; 176 | } else 177 | url = "$instrument-${mode.toLowerCase()}-${notes[0].note[0]}-$n_or_sharp"; 178 | //print(url); 179 | return url; 180 | } 181 | -------------------------------------------------------------------------------- /ios/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.3) 5 | addressable (2.7.0) 6 | public_suffix (>= 2.0.2, < 5.0) 7 | artifactory (3.0.15) 8 | atomos (0.1.3) 9 | aws-eventstream (1.1.1) 10 | aws-partitions (1.443.0) 11 | aws-sdk-core (3.113.1) 12 | aws-eventstream (~> 1, >= 1.0.2) 13 | aws-partitions (~> 1, >= 1.239.0) 14 | aws-sigv4 (~> 1.1) 15 | jmespath (~> 1.0) 16 | aws-sdk-kms (1.43.0) 17 | aws-sdk-core (~> 3, >= 3.112.0) 18 | aws-sigv4 (~> 1.1) 19 | aws-sdk-s3 (1.93.0) 20 | aws-sdk-core (~> 3, >= 3.112.0) 21 | aws-sdk-kms (~> 1) 22 | aws-sigv4 (~> 1.1) 23 | aws-sigv4 (1.2.3) 24 | aws-eventstream (~> 1, >= 1.0.2) 25 | babosa (1.0.4) 26 | claide (1.0.3) 27 | colored (1.2) 28 | colored2 (3.1.2) 29 | commander-fastlane (4.4.6) 30 | highline (~> 1.7.2) 31 | declarative (0.0.20) 32 | declarative-option (0.1.0) 33 | digest-crc (0.6.3) 34 | rake (>= 12.0.0, < 14.0.0) 35 | domain_name (0.5.20190701) 36 | unf (>= 0.0.5, < 1.0.0) 37 | dotenv (2.7.6) 38 | emoji_regex (3.2.2) 39 | excon (0.79.0) 40 | faraday (1.3.0) 41 | faraday-net_http (~> 1.0) 42 | multipart-post (>= 1.2, < 3) 43 | ruby2_keywords 44 | faraday-cookie_jar (0.0.7) 45 | faraday (>= 0.8.0) 46 | http-cookie (~> 1.0.0) 47 | faraday-net_http (1.0.1) 48 | faraday_middleware (1.0.0) 49 | faraday (~> 1.0) 50 | fastimage (2.2.3) 51 | fastlane (2.180.1) 52 | CFPropertyList (>= 2.3, < 4.0.0) 53 | addressable (>= 2.3, < 3.0.0) 54 | artifactory (~> 3.0) 55 | aws-sdk-s3 (~> 1.0) 56 | babosa (>= 1.0.3, < 2.0.0) 57 | bundler (>= 1.12.0, < 3.0.0) 58 | colored 59 | commander-fastlane (>= 4.4.6, < 5.0.0) 60 | dotenv (>= 2.1.1, < 3.0.0) 61 | emoji_regex (>= 0.1, < 4.0) 62 | excon (>= 0.71.0, < 1.0.0) 63 | faraday (~> 1.0) 64 | faraday-cookie_jar (~> 0.0.6) 65 | faraday_middleware (~> 1.0) 66 | fastimage (>= 2.1.0, < 3.0.0) 67 | gh_inspector (>= 1.1.2, < 2.0.0) 68 | google-api-client (>= 0.37.0, < 0.39.0) 69 | google-cloud-storage (>= 1.15.0, < 2.0.0) 70 | highline (>= 1.7.2, < 2.0.0) 71 | json (< 3.0.0) 72 | jwt (>= 2.1.0, < 3) 73 | mini_magick (>= 4.9.4, < 5.0.0) 74 | multipart-post (~> 2.0.0) 75 | naturally (~> 2.2) 76 | plist (>= 3.1.0, < 4.0.0) 77 | rubyzip (>= 2.0.0, < 3.0.0) 78 | security (= 0.1.3) 79 | simctl (~> 1.6.3) 80 | slack-notifier (>= 2.0.0, < 3.0.0) 81 | terminal-notifier (>= 2.0.0, < 3.0.0) 82 | terminal-table (>= 1.4.5, < 2.0.0) 83 | tty-screen (>= 0.6.3, < 1.0.0) 84 | tty-spinner (>= 0.8.0, < 1.0.0) 85 | word_wrap (~> 1.0.0) 86 | xcodeproj (>= 1.13.0, < 2.0.0) 87 | xcpretty (~> 0.3.0) 88 | xcpretty-travis-formatter (>= 0.0.3) 89 | gh_inspector (1.1.3) 90 | google-api-client (0.38.0) 91 | addressable (~> 2.5, >= 2.5.1) 92 | googleauth (~> 0.9) 93 | httpclient (>= 2.8.1, < 3.0) 94 | mini_mime (~> 1.0) 95 | representable (~> 3.0) 96 | retriable (>= 2.0, < 4.0) 97 | signet (~> 0.12) 98 | google-apis-core (0.3.0) 99 | addressable (~> 2.5, >= 2.5.1) 100 | googleauth (~> 0.14) 101 | httpclient (>= 2.8.1, < 3.0) 102 | mini_mime (~> 1.0) 103 | representable (~> 3.0) 104 | retriable (>= 2.0, < 4.0) 105 | rexml 106 | signet (~> 0.14) 107 | webrick 108 | google-apis-iamcredentials_v1 (0.3.0) 109 | google-apis-core (~> 0.1) 110 | google-apis-storage_v1 (0.3.0) 111 | google-apis-core (~> 0.1) 112 | google-cloud-core (1.6.0) 113 | google-cloud-env (~> 1.0) 114 | google-cloud-errors (~> 1.0) 115 | google-cloud-env (1.5.0) 116 | faraday (>= 0.17.3, < 2.0) 117 | google-cloud-errors (1.1.0) 118 | google-cloud-storage (1.31.0) 119 | addressable (~> 2.5) 120 | digest-crc (~> 0.4) 121 | google-apis-iamcredentials_v1 (~> 0.1) 122 | google-apis-storage_v1 (~> 0.1) 123 | google-cloud-core (~> 1.2) 124 | googleauth (~> 0.9) 125 | mini_mime (~> 1.0) 126 | googleauth (0.16.1) 127 | faraday (>= 0.17.3, < 2.0) 128 | jwt (>= 1.4, < 3.0) 129 | memoist (~> 0.16) 130 | multi_json (~> 1.11) 131 | os (>= 0.9, < 2.0) 132 | signet (~> 0.14) 133 | highline (1.7.10) 134 | http-cookie (1.0.3) 135 | domain_name (~> 0.5) 136 | httpclient (2.8.3) 137 | jmespath (1.4.0) 138 | json (2.5.1) 139 | jwt (2.2.2) 140 | memoist (0.16.2) 141 | mini_magick (4.11.0) 142 | mini_mime (1.1.0) 143 | multi_json (1.15.0) 144 | multipart-post (2.0.0) 145 | nanaimo (0.3.0) 146 | naturally (2.2.1) 147 | os (1.1.1) 148 | plist (3.6.0) 149 | public_suffix (4.0.6) 150 | rake (13.0.3) 151 | representable (3.0.4) 152 | declarative (< 0.1.0) 153 | declarative-option (< 0.2.0) 154 | uber (< 0.2.0) 155 | retriable (3.1.2) 156 | rexml (3.2.5) 157 | rouge (2.0.7) 158 | ruby2_keywords (0.0.4) 159 | rubyzip (2.3.0) 160 | security (0.1.3) 161 | signet (0.15.0) 162 | addressable (~> 2.3) 163 | faraday (>= 0.17.3, < 2.0) 164 | jwt (>= 1.5, < 3.0) 165 | multi_json (~> 1.10) 166 | simctl (1.6.8) 167 | CFPropertyList 168 | naturally 169 | slack-notifier (2.3.2) 170 | terminal-notifier (2.0.0) 171 | terminal-table (1.8.0) 172 | unicode-display_width (~> 1.1, >= 1.1.1) 173 | tty-cursor (0.7.1) 174 | tty-screen (0.8.1) 175 | tty-spinner (0.9.3) 176 | tty-cursor (~> 0.7) 177 | uber (0.1.0) 178 | unf (0.1.4) 179 | unf_ext 180 | unf_ext (0.0.7.7) 181 | unicode-display_width (1.7.0) 182 | webrick (1.7.0) 183 | word_wrap (1.0.0) 184 | xcodeproj (1.19.0) 185 | CFPropertyList (>= 2.3.3, < 4.0) 186 | atomos (~> 0.1.3) 187 | claide (>= 1.0.2, < 2.0) 188 | colored2 (~> 3.1) 189 | nanaimo (~> 0.3.0) 190 | xcpretty (0.3.0) 191 | rouge (~> 2.0.7) 192 | xcpretty-travis-formatter (1.0.1) 193 | xcpretty (~> 0.2, >= 0.0.7) 194 | 195 | PLATFORMS 196 | ruby 197 | 198 | DEPENDENCIES 199 | fastlane 200 | 201 | BUNDLED WITH 202 | 2.1.4 203 | -------------------------------------------------------------------------------- /android/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.3) 5 | addressable (2.7.0) 6 | public_suffix (>= 2.0.2, < 5.0) 7 | artifactory (3.0.15) 8 | atomos (0.1.3) 9 | aws-eventstream (1.1.1) 10 | aws-partitions (1.443.0) 11 | aws-sdk-core (3.113.1) 12 | aws-eventstream (~> 1, >= 1.0.2) 13 | aws-partitions (~> 1, >= 1.239.0) 14 | aws-sigv4 (~> 1.1) 15 | jmespath (~> 1.0) 16 | aws-sdk-kms (1.43.0) 17 | aws-sdk-core (~> 3, >= 3.112.0) 18 | aws-sigv4 (~> 1.1) 19 | aws-sdk-s3 (1.93.0) 20 | aws-sdk-core (~> 3, >= 3.112.0) 21 | aws-sdk-kms (~> 1) 22 | aws-sigv4 (~> 1.1) 23 | aws-sigv4 (1.2.3) 24 | aws-eventstream (~> 1, >= 1.0.2) 25 | babosa (1.0.4) 26 | claide (1.0.3) 27 | colored (1.2) 28 | colored2 (3.1.2) 29 | commander-fastlane (4.4.6) 30 | highline (~> 1.7.2) 31 | declarative (0.0.20) 32 | declarative-option (0.1.0) 33 | digest-crc (0.6.3) 34 | rake (>= 12.0.0, < 14.0.0) 35 | domain_name (0.5.20190701) 36 | unf (>= 0.0.5, < 1.0.0) 37 | dotenv (2.7.6) 38 | emoji_regex (3.2.2) 39 | excon (0.79.0) 40 | faraday (1.3.0) 41 | faraday-net_http (~> 1.0) 42 | multipart-post (>= 1.2, < 3) 43 | ruby2_keywords 44 | faraday-cookie_jar (0.0.7) 45 | faraday (>= 0.8.0) 46 | http-cookie (~> 1.0.0) 47 | faraday-net_http (1.0.1) 48 | faraday_middleware (1.0.0) 49 | faraday (~> 1.0) 50 | fastimage (2.2.3) 51 | fastlane (2.180.1) 52 | CFPropertyList (>= 2.3, < 4.0.0) 53 | addressable (>= 2.3, < 3.0.0) 54 | artifactory (~> 3.0) 55 | aws-sdk-s3 (~> 1.0) 56 | babosa (>= 1.0.3, < 2.0.0) 57 | bundler (>= 1.12.0, < 3.0.0) 58 | colored 59 | commander-fastlane (>= 4.4.6, < 5.0.0) 60 | dotenv (>= 2.1.1, < 3.0.0) 61 | emoji_regex (>= 0.1, < 4.0) 62 | excon (>= 0.71.0, < 1.0.0) 63 | faraday (~> 1.0) 64 | faraday-cookie_jar (~> 0.0.6) 65 | faraday_middleware (~> 1.0) 66 | fastimage (>= 2.1.0, < 3.0.0) 67 | gh_inspector (>= 1.1.2, < 2.0.0) 68 | google-api-client (>= 0.37.0, < 0.39.0) 69 | google-cloud-storage (>= 1.15.0, < 2.0.0) 70 | highline (>= 1.7.2, < 2.0.0) 71 | json (< 3.0.0) 72 | jwt (>= 2.1.0, < 3) 73 | mini_magick (>= 4.9.4, < 5.0.0) 74 | multipart-post (~> 2.0.0) 75 | naturally (~> 2.2) 76 | plist (>= 3.1.0, < 4.0.0) 77 | rubyzip (>= 2.0.0, < 3.0.0) 78 | security (= 0.1.3) 79 | simctl (~> 1.6.3) 80 | slack-notifier (>= 2.0.0, < 3.0.0) 81 | terminal-notifier (>= 2.0.0, < 3.0.0) 82 | terminal-table (>= 1.4.5, < 2.0.0) 83 | tty-screen (>= 0.6.3, < 1.0.0) 84 | tty-spinner (>= 0.8.0, < 1.0.0) 85 | word_wrap (~> 1.0.0) 86 | xcodeproj (>= 1.13.0, < 2.0.0) 87 | xcpretty (~> 0.3.0) 88 | xcpretty-travis-formatter (>= 0.0.3) 89 | gh_inspector (1.1.3) 90 | google-api-client (0.38.0) 91 | addressable (~> 2.5, >= 2.5.1) 92 | googleauth (~> 0.9) 93 | httpclient (>= 2.8.1, < 3.0) 94 | mini_mime (~> 1.0) 95 | representable (~> 3.0) 96 | retriable (>= 2.0, < 4.0) 97 | signet (~> 0.12) 98 | google-apis-core (0.3.0) 99 | addressable (~> 2.5, >= 2.5.1) 100 | googleauth (~> 0.14) 101 | httpclient (>= 2.8.1, < 3.0) 102 | mini_mime (~> 1.0) 103 | representable (~> 3.0) 104 | retriable (>= 2.0, < 4.0) 105 | rexml 106 | signet (~> 0.14) 107 | webrick 108 | google-apis-iamcredentials_v1 (0.3.0) 109 | google-apis-core (~> 0.1) 110 | google-apis-storage_v1 (0.3.0) 111 | google-apis-core (~> 0.1) 112 | google-cloud-core (1.6.0) 113 | google-cloud-env (~> 1.0) 114 | google-cloud-errors (~> 1.0) 115 | google-cloud-env (1.5.0) 116 | faraday (>= 0.17.3, < 2.0) 117 | google-cloud-errors (1.1.0) 118 | google-cloud-storage (1.31.0) 119 | addressable (~> 2.5) 120 | digest-crc (~> 0.4) 121 | google-apis-iamcredentials_v1 (~> 0.1) 122 | google-apis-storage_v1 (~> 0.1) 123 | google-cloud-core (~> 1.2) 124 | googleauth (~> 0.9) 125 | mini_mime (~> 1.0) 126 | googleauth (0.16.1) 127 | faraday (>= 0.17.3, < 2.0) 128 | jwt (>= 1.4, < 3.0) 129 | memoist (~> 0.16) 130 | multi_json (~> 1.11) 131 | os (>= 0.9, < 2.0) 132 | signet (~> 0.14) 133 | highline (1.7.10) 134 | http-cookie (1.0.3) 135 | domain_name (~> 0.5) 136 | httpclient (2.8.3) 137 | jmespath (1.4.0) 138 | json (2.5.1) 139 | jwt (2.2.2) 140 | memoist (0.16.2) 141 | mini_magick (4.11.0) 142 | mini_mime (1.1.0) 143 | multi_json (1.15.0) 144 | multipart-post (2.0.0) 145 | nanaimo (0.3.0) 146 | naturally (2.2.1) 147 | os (1.1.1) 148 | plist (3.6.0) 149 | public_suffix (4.0.6) 150 | rake (13.0.3) 151 | representable (3.0.4) 152 | declarative (< 0.1.0) 153 | declarative-option (< 0.2.0) 154 | uber (< 0.2.0) 155 | retriable (3.1.2) 156 | rexml (3.2.5) 157 | rouge (2.0.7) 158 | ruby2_keywords (0.0.4) 159 | rubyzip (2.3.0) 160 | security (0.1.3) 161 | signet (0.15.0) 162 | addressable (~> 2.3) 163 | faraday (>= 0.17.3, < 2.0) 164 | jwt (>= 1.5, < 3.0) 165 | multi_json (~> 1.10) 166 | simctl (1.6.8) 167 | CFPropertyList 168 | naturally 169 | slack-notifier (2.3.2) 170 | terminal-notifier (2.0.0) 171 | terminal-table (1.8.0) 172 | unicode-display_width (~> 1.1, >= 1.1.1) 173 | tty-cursor (0.7.1) 174 | tty-screen (0.8.1) 175 | tty-spinner (0.9.3) 176 | tty-cursor (~> 0.7) 177 | uber (0.1.0) 178 | unf (0.1.4) 179 | unf_ext 180 | unf_ext (0.0.7.7) 181 | unicode-display_width (1.7.0) 182 | webrick (1.7.0) 183 | word_wrap (1.0.0) 184 | xcodeproj (1.19.0) 185 | CFPropertyList (>= 2.3.3, < 4.0) 186 | atomos (~> 0.1.3) 187 | claide (>= 1.0.2, < 2.0) 188 | colored2 (~> 3.1) 189 | nanaimo (~> 0.3.0) 190 | xcpretty (0.3.0) 191 | rouge (~> 2.0.7) 192 | xcpretty-travis-formatter (1.0.1) 193 | xcpretty (~> 0.2, >= 0.0.7) 194 | 195 | PLATFORMS 196 | ruby 197 | 198 | DEPENDENCIES 199 | fastlane 200 | 201 | BUNDLED WITH 202 | 2.1.4 203 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - audioplayers (0.0.1): 3 | - Flutter 4 | - Firebase/Analytics (6.33.0): 5 | - Firebase/Core 6 | - Firebase/Core (6.33.0): 7 | - Firebase/CoreOnly 8 | - FirebaseAnalytics (= 6.8.3) 9 | - Firebase/CoreOnly (6.33.0): 10 | - FirebaseCore (= 6.10.3) 11 | - firebase_admob (0.10.2): 12 | - Firebase/CoreOnly (~> 6.33.0) 13 | - firebase_core 14 | - Flutter 15 | - Google-Mobile-Ads-SDK 16 | - firebase_analytics (6.2.0): 17 | - Firebase/Analytics (~> 6.33.0) 18 | - Firebase/CoreOnly (~> 6.33.0) 19 | - firebase_core 20 | - Flutter 21 | - firebase_core (0.5.2-1): 22 | - Firebase/CoreOnly (~> 6.33.0) 23 | - Flutter 24 | - FirebaseAnalytics (6.8.3): 25 | - FirebaseCore (~> 6.10) 26 | - FirebaseInstallations (~> 1.6) 27 | - GoogleAppMeasurement (= 6.8.3) 28 | - GoogleUtilities/AppDelegateSwizzler (~> 6.7) 29 | - GoogleUtilities/MethodSwizzler (~> 6.7) 30 | - GoogleUtilities/Network (~> 6.7) 31 | - "GoogleUtilities/NSData+zlib (~> 6.7)" 32 | - nanopb (~> 1.30906.0) 33 | - FirebaseCore (6.10.3): 34 | - FirebaseCoreDiagnostics (~> 1.6) 35 | - GoogleUtilities/Environment (~> 6.7) 36 | - GoogleUtilities/Logger (~> 6.7) 37 | - FirebaseCoreDiagnostics (1.7.0): 38 | - GoogleDataTransport (~> 7.4) 39 | - GoogleUtilities/Environment (~> 6.7) 40 | - GoogleUtilities/Logger (~> 6.7) 41 | - nanopb (~> 1.30906.0) 42 | - FirebaseInstallations (1.7.0): 43 | - FirebaseCore (~> 6.10) 44 | - GoogleUtilities/Environment (~> 6.7) 45 | - GoogleUtilities/UserDefaults (~> 6.7) 46 | - PromisesObjC (~> 1.2) 47 | - Flutter (1.0.0) 48 | - FMDB (2.7.5): 49 | - FMDB/standard (= 2.7.5) 50 | - FMDB/standard (2.7.5) 51 | - Google-Mobile-Ads-SDK (7.67.0): 52 | - GoogleAppMeasurement (~> 6.0) 53 | - GoogleUserMessagingPlatform (~> 1.1) 54 | - GoogleAppMeasurement (6.8.3): 55 | - GoogleUtilities/AppDelegateSwizzler (~> 6.7) 56 | - GoogleUtilities/MethodSwizzler (~> 6.7) 57 | - GoogleUtilities/Network (~> 6.7) 58 | - "GoogleUtilities/NSData+zlib (~> 6.7)" 59 | - nanopb (~> 1.30906.0) 60 | - GoogleDataTransport (7.5.1): 61 | - nanopb (~> 1.30906.0) 62 | - GoogleUserMessagingPlatform (1.4.0) 63 | - GoogleUtilities/AppDelegateSwizzler (6.7.2): 64 | - GoogleUtilities/Environment 65 | - GoogleUtilities/Logger 66 | - GoogleUtilities/Network 67 | - GoogleUtilities/Environment (6.7.2): 68 | - PromisesObjC (~> 1.2) 69 | - GoogleUtilities/Logger (6.7.2): 70 | - GoogleUtilities/Environment 71 | - GoogleUtilities/MethodSwizzler (6.7.2): 72 | - GoogleUtilities/Logger 73 | - GoogleUtilities/Network (6.7.2): 74 | - GoogleUtilities/Logger 75 | - "GoogleUtilities/NSData+zlib" 76 | - GoogleUtilities/Reachability 77 | - "GoogleUtilities/NSData+zlib (6.7.2)" 78 | - GoogleUtilities/Reachability (6.7.2): 79 | - GoogleUtilities/Logger 80 | - GoogleUtilities/UserDefaults (6.7.2): 81 | - GoogleUtilities/Logger 82 | - integration_test (0.0.1): 83 | - Flutter 84 | - launch_review (0.0.1): 85 | - Flutter 86 | - nanopb (1.30906.0): 87 | - nanopb/decode (= 1.30906.0) 88 | - nanopb/encode (= 1.30906.0) 89 | - nanopb/decode (1.30906.0) 90 | - nanopb/encode (1.30906.0) 91 | - path_provider (0.0.1): 92 | - Flutter 93 | - PromisesObjC (1.2.11) 94 | - share (0.0.1): 95 | - Flutter 96 | - shared_preferences (0.0.1): 97 | - Flutter 98 | - sqflite (0.0.2): 99 | - Flutter 100 | - FMDB (>= 2.7.5) 101 | - url_launcher (0.0.1): 102 | - Flutter 103 | 104 | DEPENDENCIES: 105 | - audioplayers (from `.symlinks/plugins/audioplayers/ios`) 106 | - firebase_admob (from `.symlinks/plugins/firebase_admob/ios`) 107 | - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) 108 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`) 109 | - Flutter (from `Flutter`) 110 | - integration_test (from `.symlinks/plugins/integration_test/ios`) 111 | - launch_review (from `.symlinks/plugins/launch_review/ios`) 112 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 113 | - share (from `.symlinks/plugins/share/ios`) 114 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 115 | - sqflite (from `.symlinks/plugins/sqflite/ios`) 116 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 117 | 118 | SPEC REPOS: 119 | trunk: 120 | - Firebase 121 | - FirebaseAnalytics 122 | - FirebaseCore 123 | - FirebaseCoreDiagnostics 124 | - FirebaseInstallations 125 | - FMDB 126 | - Google-Mobile-Ads-SDK 127 | - GoogleAppMeasurement 128 | - GoogleDataTransport 129 | - GoogleUserMessagingPlatform 130 | - GoogleUtilities 131 | - nanopb 132 | - PromisesObjC 133 | 134 | EXTERNAL SOURCES: 135 | audioplayers: 136 | :path: ".symlinks/plugins/audioplayers/ios" 137 | firebase_admob: 138 | :path: ".symlinks/plugins/firebase_admob/ios" 139 | firebase_analytics: 140 | :path: ".symlinks/plugins/firebase_analytics/ios" 141 | firebase_core: 142 | :path: ".symlinks/plugins/firebase_core/ios" 143 | Flutter: 144 | :path: Flutter 145 | integration_test: 146 | :path: ".symlinks/plugins/integration_test/ios" 147 | launch_review: 148 | :path: ".symlinks/plugins/launch_review/ios" 149 | path_provider: 150 | :path: ".symlinks/plugins/path_provider/ios" 151 | share: 152 | :path: ".symlinks/plugins/share/ios" 153 | shared_preferences: 154 | :path: ".symlinks/plugins/shared_preferences/ios" 155 | sqflite: 156 | :path: ".symlinks/plugins/sqflite/ios" 157 | url_launcher: 158 | :path: ".symlinks/plugins/url_launcher/ios" 159 | 160 | SPEC CHECKSUMS: 161 | audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c 162 | Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 163 | firebase_admob: 4dfb68c1440c0f3ba19ff103f4d78928d5348047 164 | firebase_analytics: 52ba26fcfb9cc90f76b36c4e5200cc0a7e9024eb 165 | firebase_core: 7423d688a1c6f2f2d859d64ae26991be39989781 166 | FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193 167 | FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd 168 | FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 169 | FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 170 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 171 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 172 | Google-Mobile-Ads-SDK: 8b58584890539de4527c47ef01e4da941a10bc8a 173 | GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436 174 | GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 175 | GoogleUserMessagingPlatform: b168e8c46cd8f92aa3e34b584c4ca78a411ce367 176 | GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 177 | integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f 178 | launch_review: 75d5a956ba8eaa493e9c9d4bf4c05e505e8d5ed0 179 | nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc 180 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c 181 | PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f 182 | share: 0b2c3e82132f5888bccca3351c504d0003b3b410 183 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d 184 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 185 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef 186 | 187 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 188 | 189 | COCOAPODS: 1.10.0 190 | -------------------------------------------------------------------------------- /lib/presentation/settings/settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_redux/flutter_redux.dart'; 3 | import 'package:music_scales/application/actions/settings_action.dart'; 4 | import 'package:music_scales/application/store/store.dart'; 5 | import 'package:music_scales/domain/settings/settings.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | 8 | class SettingsScreen extends StatefulWidget { 9 | @override 10 | _SettingsScreen createState() => _SettingsScreen(); 11 | } 12 | 13 | class _SettingsScreen extends State { 14 | Future _changeInstrument(String temp) async { 15 | SharedPreferences prefs = await SharedPreferences.getInstance(); 16 | await prefs.setString('instrument', temp); 17 | } 18 | 19 | Future _changeFastChordAudioSpeed(bool fastChordAudioSpeed) async { 20 | SharedPreferences prefs = await SharedPreferences.getInstance(); 21 | prefs.setBool('fastChordAudioSpeed', fastChordAudioSpeed); 22 | } 23 | 24 | Future _changeShowFlatsInScales(bool showFlatsInScales) async { 25 | SharedPreferences prefs = await SharedPreferences.getInstance(); 26 | await prefs.setBool('showFlatsInScales', showFlatsInScales); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return StoreProvider( 32 | store: store, 33 | child: Scaffold( 34 | appBar: AppBar( 35 | title: Text("Settings"), 36 | elevation: 1, 37 | ), 38 | //bottomNavigationBar: Container(height: adpadding,), 39 | backgroundColor: Colors.white, 40 | body: StoreConnector( 41 | converter: (settings) => settings.state, 42 | builder: (context, settings) { 43 | return Center( 44 | child: Column( 45 | children: [ 46 | Container( 47 | margin: EdgeInsets.fromLTRB(12, 6, 0, 8), 48 | padding: EdgeInsets.all(5), 49 | child: Row( 50 | children: [ 51 | Text( 52 | "Default Instrument: ", 53 | style: TextStyle(fontSize: 17), 54 | ), 55 | DropdownButton( 56 | hint: Text( 57 | "${settings.instrument}", 58 | style: TextStyle(fontSize: 17), 59 | ), 60 | value: settings.instrument, 61 | items: 62 | ["Piano", "Guitar"].map((String value) { 63 | return DropdownMenuItem( 64 | value: value, 65 | child: Text("$value"), 66 | ); 67 | }).toList(), 68 | onChanged: (newValueSelected) async { 69 | store.dispatch(SettingsAction( 70 | settingsActionType: 71 | SettingsActionType.setInstrument, 72 | payload: newValueSelected)); 73 | if (newValueSelected != null) { 74 | await _changeInstrument(newValueSelected); 75 | } 76 | }, 77 | ), 78 | ], 79 | ), 80 | ), 81 | Divider( 82 | height: 0, 83 | color: Color.fromRGBO(0, 0, 200, 0.2), 84 | ), 85 | Container( 86 | margin: EdgeInsets.fromLTRB(12, 6, 0, 8), 87 | padding: EdgeInsets.all(6), 88 | child: Row( 89 | children: [ 90 | Text( 91 | "Chord Audio Speed: ", 92 | style: TextStyle(fontSize: 17), 93 | ), 94 | DropdownButton( 95 | hint: Text( 96 | "${settings.fastChordAudioSpeed ? "Fast" : "Slow"}", 97 | style: TextStyle(fontSize: 17), 98 | ), 99 | value: 100 | settings.fastChordAudioSpeed ? "Fast" : "Slow", 101 | items: ["Fast", "Slow"].map((String value) { 102 | return DropdownMenuItem( 103 | value: value, 104 | child: Text("$value"), 105 | ); 106 | }).toList(), 107 | onChanged: (newValueSelected) async { 108 | bool isFast = newValueSelected == "Fast"; 109 | store.dispatch(SettingsAction( 110 | settingsActionType: 111 | SettingsActionType.setFastChordAudioSpeed, 112 | payload: isFast)); 113 | await _changeFastChordAudioSpeed(isFast); 114 | }, 115 | ), 116 | ], 117 | ), 118 | ), 119 | Divider( 120 | height: 0, 121 | color: Color.fromRGBO(0, 0, 200, 0.2), 122 | ), 123 | Container( 124 | margin: EdgeInsets.fromLTRB(12, 6, 0, 8), 125 | padding: EdgeInsets.all(6), 126 | child: Row( 127 | children: [ 128 | Text( 129 | "Show Flats in Scales: ", 130 | style: TextStyle(fontSize: 17), 131 | ), 132 | DropdownButton( 133 | hint: Text( 134 | "${settings.showFlatsInScales ? "Yes" : "No"}", 135 | style: TextStyle(fontSize: 17), 136 | ), 137 | value: settings.showFlatsInScales ? "Yes" : "No", 138 | items: ["No", "Yes"].map((String value) { 139 | return DropdownMenuItem( 140 | value: value, 141 | child: Text("$value"), 142 | ); 143 | }).toList(), 144 | onChanged: (newValueSelected) { 145 | bool showFlatsInScales = 146 | newValueSelected == "Yes"; 147 | store.dispatch(SettingsAction( 148 | settingsActionType: 149 | SettingsActionType.setShowFlatsInScales, 150 | payload: showFlatsInScales)); 151 | _changeShowFlatsInScales(showFlatsInScales); 152 | }, 153 | ), 154 | ], 155 | ), 156 | ), 157 | Divider( 158 | height: 0, 159 | color: Color.fromRGBO(0, 0, 200, 0.2), 160 | ), 161 | ], 162 | ), 163 | ); 164 | }), 165 | ), 166 | ); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /lib/presentation/chords/search_chord.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:music_scales/domain/chords/chords.dart'; 4 | import 'package:music_scales/domain/notes/notes.dart'; 5 | 6 | class SearchChordScreen extends StatefulWidget { 7 | @override 8 | _SearchChordScreen createState() => _SearchChordScreen(); 9 | } 10 | 11 | class _SearchChordScreen extends State { 12 | List noteindexs = []; 13 | List scaleindexs = []; 14 | 15 | final myController = TextEditingController(); 16 | String searchText = ""; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | allChordsCalculate(); 22 | } 23 | 24 | void allChordsCalculate() { 25 | for (int i = 0; i < 12; i++) { 26 | for (int j = 0; j < 32; j++) { 27 | int index = i; 28 | for (int k = 0; k < searchChords[j].formula.length + 1; k++) { 29 | if (k != 0) index += searchChords[j].formula[k - 1]; 30 | if (index > 11) index %= 12; 31 | allChords[i][j].add(notes[index]); 32 | } 33 | } 34 | } 35 | } 36 | 37 | List calculateChord(int mode, int key) { 38 | List theChord = []; 39 | int index = key; 40 | late Chord chordObj; 41 | for (int i = 0; i < searchChords.length; i++) { 42 | if (mode == searchChords[i].index) chordObj = searchChords[i]; 43 | } 44 | for (int j = 0; j < chordObj.formula.length + 1; j++) { 45 | if (j != 0) index += chordObj.formula[j - 1]; 46 | if (index > 11) index %= 12; 47 | theChord.add(notes[index]); 48 | } 49 | return theChord; 50 | } 51 | 52 | void chordSearcher(List mynotes) { 53 | //When adding new scales, change the j number of iteration; and from main.dart, add the new indexs to allScales and change j 54 | noteindexs = []; 55 | scaleindexs = []; 56 | int ctr; 57 | for (int i = 0; i < 12; i++) { 58 | for (int j = 0; j < 32; j++) { 59 | ctr = 0; 60 | for (int k = 0; k < searchChords[j].formula.length + 1; k++) { 61 | for (int l = 0; l < mynotes.length; l++) { 62 | if (mynotes[l] == allChords[i][j][k].note) { 63 | ctr++; 64 | } 65 | } 66 | } 67 | if (ctr == mynotes.length) { 68 | noteindexs.add(i); 69 | scaleindexs.add(j); 70 | } 71 | } 72 | } 73 | } 74 | 75 | List bToSharp(List thenotes) { 76 | String temp; 77 | int tempcharcode; 78 | String tempfinal; 79 | List temptoreturn = []; 80 | for (int i = 0; i < thenotes.length; i++) { 81 | tempfinal = thenotes[i]; 82 | if (thenotes[i].length == 2) { 83 | if (thenotes[i][1] == "b") { 84 | tempcharcode = thenotes[i].codeUnitAt(0) - 1; 85 | if (tempcharcode == 64) tempcharcode = 71; 86 | temp = String.fromCharCode(tempcharcode); 87 | tempfinal = "$temp#"; 88 | } 89 | } 90 | print(tempfinal); 91 | temptoreturn.add(tempfinal); 92 | } 93 | return temptoreturn; 94 | } 95 | 96 | Text scaleNotesText(List mynotes) { 97 | if (mynotes.length == 3) { 98 | return Text( 99 | "${mynotes[0].note} ${mynotes[1].note} ${mynotes[2].note}", 100 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), 101 | ); 102 | } else if (mynotes.length == 4) { 103 | return Text( 104 | "${mynotes[0].note} ${mynotes[1].note} ${mynotes[2].note} ${mynotes[3].note}", 105 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), 106 | ); 107 | } else if (mynotes.length == 5) { 108 | return Text( 109 | "${mynotes[0].note} ${mynotes[1].note} ${mynotes[2].note} ${mynotes[3].note} ${mynotes[4].note}", 110 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), 111 | ); 112 | } else if (mynotes.length == 6) { 113 | return Text( 114 | "${mynotes[0].note} ${mynotes[1].note} ${mynotes[2].note} ${mynotes[3].note} ${mynotes[4].note} ${mynotes[5].note}", 115 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), 116 | ); 117 | } else if (mynotes.length == 7) { 118 | return Text( 119 | "${mynotes[0].note} ${mynotes[1].note} ${mynotes[2].note} ${mynotes[3].note} ${mynotes[4].note} ${mynotes[5].note} ${mynotes[6].note}", 120 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300), 121 | ); 122 | } 123 | return Text(""); 124 | } 125 | 126 | @override 127 | void dispose() { 128 | myController.dispose(); 129 | super.dispose(); 130 | } 131 | 132 | @override 133 | Widget build(BuildContext context) { 134 | return Scaffold( 135 | resizeToAvoidBottomInset: false, //Fixes keyboard overflow issue 136 | appBar: AppBar( 137 | title: Text("Search in a Chord", 138 | style: TextStyle(color: Color.fromRGBO(20, 20, 20, 1))), 139 | elevation: 1, 140 | actions: [ 141 | Padding( 142 | padding: EdgeInsets.only(right: 10), 143 | child: GestureDetector( 144 | child: Icon( 145 | Icons.help, 146 | size: 30, 147 | ), 148 | onTap: () { 149 | showDialog( 150 | context: context, 151 | builder: (ctxt) => AlertDialog( 152 | title: Text( 153 | "Help", 154 | textAlign: TextAlign.center, 155 | ), 156 | content: Text( 157 | "Write the notes in the search bar. Use '#' for sharp notes and 'b' for flat notes."), // Click the scale to view it. (Buggy) 158 | )); 159 | }, 160 | ), 161 | ), 162 | ], 163 | ), 164 | //bottomNavigationBar: Container(height: adpadding,), 165 | backgroundColor: Colors.white, 166 | body: Center( 167 | child: Column( 168 | children: [ 169 | Container( 170 | color: Color.fromRGBO(255, 195, 195, 0.5), 171 | padding: EdgeInsets.only(bottom: 17, top: 1), 172 | child: Row( 173 | mainAxisAlignment: MainAxisAlignment.center, 174 | children: [ 175 | Container( 176 | width: 200, 177 | child: TextField( 178 | controller: myController, 179 | textInputAction: TextInputAction.done, 180 | decoration: InputDecoration( 181 | labelStyle: TextStyle(color: Colors.black), 182 | hintText: "eg. A C# E", 183 | labelText: "Notes", 184 | icon: 185 | Icon(Icons.music_note, color: Colors.orange[600])), 186 | textAlign: TextAlign.center, 187 | style: TextStyle(fontSize: 20), 188 | textCapitalization: TextCapitalization.words, 189 | onSubmitted: (text) { 190 | setState(() { 191 | searchText = text; 192 | chordSearcher(bToSharp(text.trim().split(" "))); 193 | }); 194 | }, 195 | ), 196 | ), 197 | Padding( 198 | padding: EdgeInsets.only(right: 30), 199 | ) 200 | ], 201 | ), 202 | ), 203 | Divider( 204 | height: 0, 205 | color: Colors.black26, 206 | ), 207 | Container( 208 | child: Expanded( 209 | child: ListView.separated( 210 | itemCount: noteindexs.length, 211 | separatorBuilder: (BuildContext context, int index) { 212 | return Divider( 213 | height: 0, 214 | color: Colors.black26, 215 | ); 216 | }, 217 | itemBuilder: (BuildContext context, int index) { 218 | List> scaleNotes = []; 219 | for (int j = 0; j < noteindexs.length; j++) { 220 | scaleNotes.add(calculateChord( 221 | searchChords[scaleindexs[index]].index, 222 | notes[noteindexs[index]].index)); 223 | } 224 | return ListTile( 225 | title: Container( 226 | padding: EdgeInsets.fromLTRB(0, 6, 0, 10), 227 | child: Column( 228 | crossAxisAlignment: CrossAxisAlignment.start, 229 | children: [ 230 | Text( 231 | "${notes[noteindexs[index]].note} ${searchChords[scaleindexs[index]].note}", 232 | style: TextStyle(fontSize: 26), 233 | ), 234 | Padding( 235 | padding: EdgeInsets.only(bottom: 6), 236 | ), 237 | scaleNotesText(scaleNotes[index]), 238 | ], 239 | ), 240 | ), 241 | ); 242 | }, 243 | ), 244 | )) 245 | ], 246 | )), 247 | ); 248 | } 249 | 250 | var allChords = List>>.generate( 251 | 12, (index) => List>.generate(32, (index) => [])); 252 | } 253 | -------------------------------------------------------------------------------- /lib/presentation/scale/random_progression_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:audioplayers/audioplayers.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:music_scales/domain/chords/chords.dart'; 6 | import 'package:music_scales/domain/core/const.dart'; 7 | 8 | class RandomProgScreen extends StatelessWidget { 9 | final String progmode; 10 | final String musicKey; 11 | final int myindex; 12 | final List theScale; 13 | const RandomProgScreen({ 14 | required this.progmode, 15 | required this.musicKey, 16 | required this.myindex, 17 | required this.theScale, 18 | }); 19 | 20 | Widget build(BuildContext content) { 21 | AudioPlayer audio = new AudioPlayer(); 22 | String urlAudio(String chord) { 23 | return "https://www.scales-chords.com/chord-sounds/snd-guitar-chord-${chord.replaceFirst("#", "s")}.mp3"; 24 | } 25 | 26 | Future play(String chord) async { 27 | await audio.play(urlAudio(chord)); 28 | print(urlAudio(chord)); 29 | } 30 | 31 | TableCell tableCell(String chordname) { 32 | return TableCell( 33 | child: FlatButton( 34 | padding: EdgeInsets.zero, 35 | color: Color.fromRGBO(230, 80, 80, 0.12), 36 | onPressed: () { 37 | play(chordname); 38 | }, 39 | child: Padding( 40 | padding: 41 | EdgeInsets.fromLTRB(0, textSize * 0.7, 0, textSize * 0.75), 42 | child: Center( 43 | child: Text( 44 | "$chordname", 45 | style: TextStyle( 46 | fontSize: textSize * 0.85, 47 | color: Colors.red, 48 | fontWeight: FontWeight.w400), 49 | ))), 50 | ), 51 | ); 52 | } 53 | 54 | List progs() { 55 | List theProgs; 56 | if (progmode == "Major") 57 | theProgs = [ 58 | [1, 4, 5], 59 | [1, 5, 6, 4], 60 | [2, 5, 1], 61 | [1, 6, 4, 5], 62 | [1, 4, 2, 5], 63 | [1, 4, 1, 5], 64 | [1, 3, 4, 5], 65 | [1, 2, 5] 66 | ]; 67 | else 68 | theProgs = [ 69 | [1, 6, 7], 70 | [1, 4, 6], 71 | [1, 4, 5], 72 | [1, 6, 3, 7], 73 | [1, 7, 6, 7], 74 | [6, 7, 1, 1], 75 | [1, 4, 5, 1] 76 | ]; 77 | return theProgs; 78 | } 79 | 80 | List progressions = progs(); 81 | Column progTable(int number) { 82 | if (progressions[number].length == 3) { 83 | return Column( 84 | children: [ 85 | Padding( 86 | padding: EdgeInsets.fromLTRB(0, 26, 0, 6), 87 | child: Text( 88 | "Formula: ${progressions[number][0]} - ${progressions[number][1]} - ${progressions[number][2]}", 89 | style: TextStyle( 90 | fontSize: 28, color: Color.fromRGBO(70, 70, 70, 0.8)), 91 | ), 92 | ), 93 | Divider( 94 | height: 0, 95 | color: Colors.black26, 96 | ), 97 | Padding( 98 | padding: EdgeInsets.fromLTRB( 99 | 56 - textSize * 0.45, 20, 56 - textSize * 0.45, 0), 100 | child: Table( 101 | border: TableBorder.all( 102 | width: 1, color: Color.fromRGBO(20, 0, 160, 0.2)), 103 | children: [ 104 | TableRow( 105 | children: [ 106 | TableCell( 107 | child: Padding( 108 | padding: EdgeInsets.fromLTRB( 109 | 0, textSize * 0.3, 0, textSize * 0.35), 110 | child: Center( 111 | child: Text( 112 | "${progressions[number][0]}", 113 | style: TextStyle( 114 | fontSize: textSize * 0.85, 115 | color: Color.fromRGBO(20, 20, 20, 0.55)), 116 | ))), 117 | ), 118 | TableCell( 119 | child: Padding( 120 | padding: EdgeInsets.fromLTRB( 121 | 0, textSize * 0.3, 0, textSize * 0.35), 122 | child: Center( 123 | child: Text( 124 | "${progressions[number][1]}", 125 | style: TextStyle( 126 | fontSize: textSize * 0.85, 127 | color: Color.fromRGBO(20, 20, 20, 0.55)), 128 | ))), 129 | ), 130 | TableCell( 131 | child: Padding( 132 | padding: EdgeInsets.fromLTRB( 133 | 0, textSize * 0.3, 0, textSize * 0.35), 134 | child: Center( 135 | child: Text( 136 | "${progressions[number][2]}", 137 | style: TextStyle( 138 | fontSize: textSize * 0.85, 139 | color: Color.fromRGBO(20, 20, 20, 0.55)), 140 | ))), 141 | ), 142 | ], 143 | ), 144 | TableRow( 145 | children: [ 146 | tableCell(theScale[progressions[number][0] - 1].name), 147 | tableCell(theScale[progressions[number][1] - 1].name), 148 | tableCell(theScale[progressions[number][2] - 1].name), 149 | ], 150 | ), 151 | ], 152 | ), 153 | ) 154 | ], 155 | ); 156 | } else { 157 | return Column( 158 | children: [ 159 | Padding( 160 | padding: EdgeInsets.fromLTRB(0, 26, 0, 6), 161 | child: Text( 162 | "Formula: ${progressions[number][0]} - ${progressions[number][1]} - ${progressions[number][2]} - ${progressions[number][3]}", 163 | style: TextStyle( 164 | fontSize: 28, color: Color.fromRGBO(70, 70, 70, 0.8)), 165 | ), 166 | ), 167 | Divider( 168 | height: 0, 169 | color: Colors.black26, 170 | ), 171 | Padding( 172 | padding: EdgeInsets.fromLTRB( 173 | 44 - textSize * 0.6, 20, 44 - textSize * 0.6, 0), 174 | child: Table( 175 | border: TableBorder.all( 176 | width: 1, color: Color.fromRGBO(20, 0, 160, 0.2)), 177 | children: [ 178 | TableRow( 179 | children: [ 180 | TableCell( 181 | child: Padding( 182 | padding: EdgeInsets.fromLTRB( 183 | 0, textSize * 0.3, 0, textSize * 0.35), 184 | child: Center( 185 | child: Text( 186 | "${progressions[number][0]}", 187 | style: TextStyle( 188 | fontSize: textSize * 0.85, 189 | color: Color.fromRGBO(20, 20, 20, 0.55)), 190 | ))), 191 | ), 192 | TableCell( 193 | child: Padding( 194 | padding: EdgeInsets.fromLTRB( 195 | 0, textSize * 0.3, 0, textSize * 0.35), 196 | child: Center( 197 | child: Text( 198 | "${progressions[number][1]}", 199 | style: TextStyle( 200 | fontSize: textSize * 0.85, 201 | color: Color.fromRGBO(20, 20, 20, 0.55)), 202 | ))), 203 | ), 204 | TableCell( 205 | child: Padding( 206 | padding: EdgeInsets.fromLTRB( 207 | 0, textSize * 0.3, 0, textSize * 0.35), 208 | child: Center( 209 | child: Text( 210 | "${progressions[number][2]}", 211 | style: TextStyle( 212 | fontSize: textSize * 0.85, 213 | color: Color.fromRGBO(20, 20, 20, 0.55)), 214 | ))), 215 | ), 216 | TableCell( 217 | child: Padding( 218 | padding: EdgeInsets.fromLTRB( 219 | 0, textSize * 0.3, 0, textSize * 0.35), 220 | child: Center( 221 | child: Text( 222 | "${progressions[number][3]}", 223 | style: TextStyle( 224 | fontSize: textSize * 0.85, 225 | color: Color.fromRGBO(20, 20, 20, 0.55)), 226 | ))), 227 | ), 228 | ], 229 | ), 230 | TableRow( 231 | children: [ 232 | tableCell(theScale[progressions[number][0] - 1].name), 233 | tableCell(theScale[progressions[number][1] - 1].name), 234 | tableCell(theScale[progressions[number][2] - 1].name), 235 | tableCell(theScale[progressions[number][3] - 1].name), 236 | ], 237 | ), 238 | ], 239 | ), 240 | ), 241 | ], 242 | ); 243 | } 244 | } 245 | 246 | Random rand = new Random(); 247 | int myrand = rand.nextInt(progressions.length); 248 | return Scaffold( 249 | appBar: AppBar( 250 | title: Text("Random ${theScale[0].name} Progression"), 251 | elevation: 1, 252 | ), 253 | //bottomNavigationBar: Container(height: adpadding,), 254 | backgroundColor: Colors.white, 255 | body: SingleChildScrollView( 256 | child: Center( 257 | child: Column( 258 | children: [ 259 | progTable(myrand), 260 | ], 261 | ), 262 | ), 263 | ), 264 | ); 265 | } 266 | } 267 | --------------------------------------------------------------------------------