diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e297939f..ed8cabd4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: - master env: - flutter_version: "1.22.5" + flutter_version: "1.22.6" jobs: buildApk: diff --git a/.run/AndroidDev.run.xml b/.run/AndroidDev.run.xml new file mode 100644 index 00000000..4cfb2646 --- /dev/null +++ b/.run/AndroidDev.run.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.run/Dev.run.xml b/.run/Dev.run.xml deleted file mode 100644 index 8e84394c..00000000 --- a/.run/Dev.run.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/.run/IosDev.run.xml b/.run/IosDev.run.xml new file mode 100644 index 00000000..fc3affbe --- /dev/null +++ b/.run/IosDev.run.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.run/instrument_checker.dart.run.xml b/.run/instrument_checker.dart.run.xml new file mode 100644 index 00000000..fbaacbb0 --- /dev/null +++ b/.run/instrument_checker.dart.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/chaomao/hitnotes/MainActivity.kt b/android/app/src/main/kotlin/com/chaomao/hitnotes/MainActivity.kt index 0a3d8549..dfde49ca 100644 --- a/android/app/src/main/kotlin/com/chaomao/hitnotes/MainActivity.kt +++ b/android/app/src/main/kotlin/com/chaomao/hitnotes/MainActivity.kt @@ -8,6 +8,6 @@ import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) - MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.chaomao.hitnotes/sound_player").setMethodCallHandler(SoundPlayerPlugin()) + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.chaomao.hitnotes/sound_player").setMethodCallHandler(SoundMethodCallHandler()) } } diff --git a/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundMethodCallHandler.kt b/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundMethodCallHandler.kt new file mode 100644 index 00000000..dbeccc2e --- /dev/null +++ b/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundMethodCallHandler.kt @@ -0,0 +1,77 @@ +package com.chaomao.hitnotes + +import android.media.AudioAttributes +import android.media.AudioManager +import android.media.SoundPool +import android.os.Build +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import kotlin.math.pow + +class SoundMethodCallHandler : MethodChannel.MethodCallHandler { + private lateinit var soundPool: SoundPool + private var loadedCount = 0 + private var soundIds = mapOf() + private var rates = mapOf() + private var activeSounds = arrayListOf() + private val maxStreams = 8 + + override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) { + when (methodCall.method) { + "load" -> { + val arguments = methodCall.arguments as Map + val soundPaths = arguments["soundPaths"] as Map + val baseNotes = arguments["baseNotes"] as Map + soundPool = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + SoundPool.Builder() + .setMaxStreams(maxStreams) + .setAudioAttributes(AudioAttributes.Builder().setLegacyStreamType + (AudioManager.STREAM_MUSIC) + .setUsage(AudioAttributes.USAGE_GAME) + .build()) + .build() + } else { + SoundPool(maxStreams, AudioManager.STREAM_MUSIC, 1) + }.apply { + setOnLoadCompleteListener { _, _, _ -> + loadedCount++ + if (loadedCount == soundPaths.size) { + result.success(null) + } + } + } + val ids = hashMapOf() + for ((baseNote, path) in soundPaths) { + val soundId = soundPool.load(path, 1) + ids[baseNote] = soundId + } + rates = baseNotes.mapValues { 2f.pow((it.key - it.value).toFloat() / 12f) } + this.soundIds = baseNotes.mapValues { ids[it.value]!! } + } + "play" -> { + val arguments = methodCall.arguments as Map + val note = arguments["note"] as Int + val streamId = soundPool.play(soundIds[note]!!, 1.0f, 1.0f, 0, + 0, rates[note]!!) + activeSounds.add(streamId) + if (activeSounds.size > maxStreams) { + val firstSound = activeSounds.first() + soundPool.stop(firstSound) + activeSounds.remove(firstSound) + } + result.success(null) + } + "release" -> { + if (this::soundPool.isInitialized) { + soundPool.release() + } + loadedCount = 0 + activeSounds.clear() + result.success(null) + } + else -> { + result.notImplemented() + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundPlayerPlugin.kt b/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundPlayerPlugin.kt deleted file mode 100644 index 1d91409d..00000000 --- a/android/app/src/main/kotlin/com/chaomao/hitnotes/SoundPlayerPlugin.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.chaomao.hitnotes - -import android.media.AudioAttributes -import android.media.AudioManager -import android.media.SoundPool -import android.os.Build -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel - -class SoundPlayerPlugin : MethodChannel.MethodCallHandler { - private lateinit var soundPool: SoundPool - private val loadingSounds = hashMapOf() - - override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) { - when (methodCall.method) { - "init" -> { - val arguments = methodCall.arguments as Map - val streamTypeIndex = arguments["streamType"] as Int - val maxStreams = arguments["maxStreams"] as Int - val streamType = when (streamTypeIndex) { - 0 -> AudioManager.STREAM_RING - 1 -> AudioManager.STREAM_ALARM - 2 -> AudioManager.STREAM_MUSIC - 3 -> AudioManager.STREAM_NOTIFICATION - else -> -1 - } - if (streamType > -1) { - soundPool = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - val usage = when (streamType) { - AudioManager.STREAM_RING -> AudioAttributes.USAGE_NOTIFICATION_RINGTONE - AudioManager.STREAM_ALARM -> AudioAttributes.USAGE_ALARM - AudioManager.STREAM_NOTIFICATION -> AudioAttributes.USAGE_NOTIFICATION - else -> AudioAttributes.USAGE_GAME - } - SoundPool.Builder() - .setMaxStreams(maxStreams) - .setAudioAttributes(AudioAttributes.Builder().setLegacyStreamType - (streamType) - .setUsage(usage) - .build()) - .build() - } else { - SoundPool(maxStreams, streamType, 1) - }.apply { - setOnLoadCompleteListener { _, sampleId, status -> - val resultCallback = loadingSounds[sampleId] - resultCallback?.let { - if (status == 0) { - it.success(sampleId) - } else { - it.error("Loading failed", "Error code: $status", null) - } - loadingSounds.remove(sampleId) - } - } - } - result.success(null) - } else { - result.error("Init failed", null, null) - } - } - "load" -> { - val arguments = methodCall.arguments as Map - val path = arguments["path"] as String - val priority = arguments["priority"] as Int - val soundId = soundPool.load(path, priority) - if (soundId > -1) { - loadingSounds[soundId] = result - } else { - result.success(soundId) - } - } - "play" -> { - val arguments = methodCall.arguments as Map - val soundId = arguments["soundId"] as Int - val repeat = arguments["repeat"] as Int - val rate = arguments["rate"] as Double - val streamId = soundPool.play(soundId, 1.0f, 1.0f, 0, - repeat, rate.toFloat()) - result.success(streamId) - } - "stop" -> { - val arguments = methodCall.arguments as Map - val streamId = arguments["streamId"] as Int - soundPool.stop(streamId) - result.success(streamId) - } - "release" -> { - soundPool.release() - result.success(null) - } - else -> { - result.notImplemented() - } - } - } -} \ No newline at end of file diff --git a/database/db.json b/database/db.json index aaca257d..77e098a8 100644 --- a/database/db.json +++ b/database/db.json @@ -3,459 +3,246 @@ "instruments": { "acoustic_guitar": { "__collections__": {}, + "baseNotes": { + "31": 31, + "32": 31, + "33": 33, + "34": 33, + "35": 33, + "36": 36, + "37": 36, + "38": 36, + "39": 39, + "40": 39, + "41": 39, + "42": 43, + "43": 43, + "44": 43, + "45": 45, + "46": 45, + "47": 45, + "48": 48, + "49": 48, + "50": 48, + "51": 52, + "52": 52, + "53": 52, + "54": 54, + "55": 54, + "56": 54, + "57": 57, + "58": 57, + "59": 57, + "60": 60, + "61": 60, + "62": 60, + "63": 63, + "64": 63, + "65": 63, + "66": 66, + "67": 66, + "68": 66, + "69": 69, + "70": 69, + "71": 69, + "72": 72, + "73": 72, + "74": 72, + "75": 75, + "76": 75, + "77": 75, + "78": 78, + "79": 78, + "80": 78, + "81": 81, + "82": 81, + "83": 81, + "84": 84 + }, "id": "acoustic_guitar", "maxNote": 84, "minNote": 31, - "soundFiles": { - "31": "sounds/acoustic-guitar/31.mp3", - "33": "sounds/acoustic-guitar/33.mp3", - "36": "sounds/acoustic-guitar/36.mp3", - "39": "sounds/acoustic-guitar/39.mp3", - "43": "sounds/acoustic-guitar/43.mp3", - "45": "sounds/acoustic-guitar/45.mp3", - "48": "sounds/acoustic-guitar/48.mp3", - "52": "sounds/acoustic-guitar/52.mp3", - "54": "sounds/acoustic-guitar/54.mp3", - "57": "sounds/acoustic-guitar/57.mp3", - "60": "sounds/acoustic-guitar/60.mp3", - "63": "sounds/acoustic-guitar/63.mp3", - "66": "sounds/acoustic-guitar/66.mp3", - "69": "sounds/acoustic-guitar/69.mp3", - "72": "sounds/acoustic-guitar/72.mp3", - "75": "sounds/acoustic-guitar/75.mp3", - "78": "sounds/acoustic-guitar/78.mp3", - "81": "sounds/acoustic-guitar/81.mp3", - "84": "sounds/acoustic-guitar/84.mp3" - }, - "soundNotes": { - "31": { - "note": 31, - "pitch": 1 - }, - "32": { - "note": 31, - "pitch": 1.0594631 - }, - "33": { - "note": 33, - "pitch": 1 - }, - "34": { - "note": 33, - "pitch": 1.0594631 - }, - "35": { - "note": 33, - "pitch": 1.122462 - }, - "36": { - "note": 36, - "pitch": 1 - }, - "37": { - "note": 36, - "pitch": 1.0594631 - }, - "38": { - "note": 36, - "pitch": 1.122462 - }, - "39": { - "note": 39, - "pitch": 1 - }, - "40": { - "note": 39, - "pitch": 1.0594631 - }, - "41": { - "note": 39, - "pitch": 1.122462 - }, - "42": { - "note": 43, - "pitch": 0.9438743 - }, - "43": { - "note": 43, - "pitch": 1 - }, - "44": { - "note": 43, - "pitch": 1.0594631 - }, - "45": { - "note": 45, - "pitch": 1 - }, - "46": { - "note": 45, - "pitch": 1.0594631 - }, - "47": { - "note": 45, - "pitch": 1.122462 - }, - "48": { - "note": 48, - "pitch": 1 - }, - "49": { - "note": 48, - "pitch": 1.0594631 - }, - "50": { - "note": 48, - "pitch": 1.122462 - }, - "51": { - "note": 52, - "pitch": 0.9438743 - }, - "52": { - "note": 52, - "pitch": 1 - }, - "53": { - "note": 52, - "pitch": 1.0594631 - }, - "54": { - "note": 54, - "pitch": 1 - }, - "55": { - "note": 54, - "pitch": 1.0594631 - }, - "56": { - "note": 54, - "pitch": 1.122462 - }, - "57": { - "note": 57, - "pitch": 1 - }, - "58": { - "note": 57, - "pitch": 1.0594631 - }, - "59": { - "note": 57, - "pitch": 1.122462 - }, - "60": { - "note": 60, - "pitch": 1 - }, - "61": { - "note": 60, - "pitch": 1.0594631 - }, - "62": { - "note": 60, - "pitch": 1.122462 - }, - "63": { - "note": 63, - "pitch": 1 - }, - "64": { - "note": 63, - "pitch": 1.0594631 - }, - "65": { - "note": 63, - "pitch": 1.122462 - }, - "66": { - "note": 66, - "pitch": 1 - }, - "67": { - "note": 66, - "pitch": 1.0594631 - }, - "68": { - "note": 66, - "pitch": 1.122462 - }, - "69": { - "note": 69, - "pitch": 1 - }, - "70": { - "note": 69, - "pitch": 1.0594631 - }, - "71": { - "note": 69, - "pitch": 1.122462 - }, - "72": { - "note": 72, - "pitch": 1 - }, - "73": { - "note": 72, - "pitch": 1.0594631 - }, - "74": { - "note": 72, - "pitch": 1.122462 - }, - "75": { - "note": 75, - "pitch": 1 - }, - "76": { - "note": 75, - "pitch": 1.0594631 - }, - "77": { - "note": 75, - "pitch": 1.122462 - }, - "78": { - "note": 78, - "pitch": 1 - }, - "79": { - "note": 78, - "pitch": 1.0594631 - }, - "80": { - "note": 78, - "pitch": 1.122462 - }, - "81": { - "note": 81, - "pitch": 1 - }, - "82": { - "note": 81, - "pitch": 1.0594631 - }, - "83": { - "note": 81, - "pitch": 1.122462 - }, - "84": { - "note": 84, - "pitch": 1 - } - }, - "volume": 0.5 + "soundPaths": { + "31": "sounds/acoustic_guitar/31.mp3", + "33": "sounds/acoustic_guitar/33.mp3", + "36": "sounds/acoustic_guitar/36.mp3", + "39": "sounds/acoustic_guitar/39.mp3", + "43": "sounds/acoustic_guitar/43.mp3", + "45": "sounds/acoustic_guitar/45.mp3", + "48": "sounds/acoustic_guitar/48.mp3", + "52": "sounds/acoustic_guitar/52.mp3", + "54": "sounds/acoustic_guitar/54.mp3", + "57": "sounds/acoustic_guitar/57.mp3", + "60": "sounds/acoustic_guitar/60.mp3", + "63": "sounds/acoustic_guitar/63.mp3", + "66": "sounds/acoustic_guitar/66.mp3", + "69": "sounds/acoustic_guitar/69.mp3", + "72": "sounds/acoustic_guitar/72.mp3", + "75": "sounds/acoustic_guitar/75.mp3", + "78": "sounds/acoustic_guitar/78.mp3", + "81": "sounds/acoustic_guitar/81.mp3", + "84": "sounds/acoustic_guitar/84.mp3" + } }, "electric_guitar": { "__collections__": {}, + "baseNotes": { + "40": 40, + "41": 40, + "42": 40, + "43": 44, + "44": 44, + "45": 44, + "46": 44, + "47": 48, + "48": 48, + "49": 48, + "50": 48, + "51": 52, + "52": 52, + "53": 52, + "54": 52, + "55": 56, + "56": 56, + "57": 56, + "58": 56, + "59": 60, + "60": 60, + "61": 60, + "62": 60, + "63": 65, + "64": 65, + "65": 65, + "66": 65, + "67": 65, + "68": 68, + "69": 68, + "70": 68, + "71": 72, + "72": 72, + "73": 72, + "74": 72, + "75": 76, + "76": 76, + "77": 76, + "78": 76, + "79": 80, + "80": 80, + "81": 80, + "82": 80, + "83": 84, + "84": 84 + }, "id": "electric_guitar", "maxNote": 84, "minNote": 40, - "soundFiles": { - "40": "sounds/electric-guitar/40.mp3", - "44": "sounds/electric-guitar/44.mp3", - "48": "sounds/electric-guitar/48.mp3", - "52": "sounds/electric-guitar/52.mp3", - "56": "sounds/electric-guitar/56.mp3", - "60": "sounds/electric-guitar/60.mp3", - "65": "sounds/electric-guitar/65.mp3", - "68": "sounds/electric-guitar/68.mp3", - "72": "sounds/electric-guitar/72.mp3", - "76": "sounds/electric-guitar/76.mp3", - "80": "sounds/electric-guitar/80.mp3", - "84": "sounds/electric-guitar/84.mp3" - }, - "soundNotes": { - "40": { - "note": 40, - "pitch": 1 - }, - "41": { - "note": 40, - "pitch": 1.0594631 - }, - "42": { - "note": 40, - "pitch": 1.122462 - }, - "43": { - "note": 44, - "pitch": 0.9438743 - }, - "44": { - "note": 44, - "pitch": 1 - }, - "45": { - "note": 44, - "pitch": 1.0594631 - }, - "46": { - "note": 44, - "pitch": 1.122462 - }, - "47": { - "note": 48, - "pitch": 0.9438743 - }, - "48": { - "note": 48, - "pitch": 1 - }, - "49": { - "note": 48, - "pitch": 1.0594631 - }, - "50": { - "note": 48, - "pitch": 1.122462 - }, - "51": { - "note": 52, - "pitch": 0.9438743 - }, - "52": { - "note": 52, - "pitch": 1 - }, - "53": { - "note": 52, - "pitch": 1.0594631 - }, - "54": { - "note": 52, - "pitch": 1.122462 - }, - "55": { - "note": 56, - "pitch": 0.9438743 - }, - "56": { - "note": 56, - "pitch": 1 - }, - "57": { - "note": 56, - "pitch": 1.0594631 - }, - "58": { - "note": 56, - "pitch": 1.122462 - }, - "59": { - "note": 60, - "pitch": 0.9438743 - }, - "60": { - "note": 60, - "pitch": 1 - }, - "61": { - "note": 60, - "pitch": 1.0594631 - }, - "62": { - "note": 60, - "pitch": 1.122462 - }, - "63": { - "note": 65, - "pitch": 0.8908987 - }, - "64": { - "note": 65, - "pitch": 0.9438743 - }, - "65": { - "note": 65, - "pitch": 1 - }, - "66": { - "note": 65, - "pitch": 1.0594631 - }, - "67": { - "note": 65, - "pitch": 1.122462 - }, - "68": { - "note": 68, - "pitch": 1 - }, - "69": { - "note": 68, - "pitch": 1.0594631 - }, - "70": { - "note": 68, - "pitch": 1.122462 - }, - "71": { - "note": 72, - "pitch": 0.9438743 - }, - "72": { - "note": 72, - "pitch": 1 - }, - "73": { - "note": 72, - "pitch": 1.0594631 - }, - "74": { - "note": 72, - "pitch": 1.122462 - }, - "75": { - "note": 76, - "pitch": 0.9438743 - }, - "76": { - "note": 76, - "pitch": 1 - }, - "77": { - "note": 76, - "pitch": 1.0594631 - }, - "78": { - "note": 76, - "pitch": 1.122462 - }, - "79": { - "note": 80, - "pitch": 0.9438743 - }, - "80": { - "note": 80, - "pitch": 1 - }, - "81": { - "note": 80, - "pitch": 1.0594631 - }, - "82": { - "note": 80, - "pitch": 1.122462 - }, - "83": { - "note": 84, - "pitch": 0.9438743 - }, - "84": { - "note": 84, - "pitch": 1 - } - }, - "volume": 0.3 + "soundPaths": { + "40": "sounds/electric_guitar/40.mp3", + "44": "sounds/electric_guitar/44.mp3", + "48": "sounds/electric_guitar/48.mp3", + "52": "sounds/electric_guitar/52.mp3", + "56": "sounds/electric_guitar/56.mp3", + "60": "sounds/electric_guitar/60.mp3", + "65": "sounds/electric_guitar/65.mp3", + "68": "sounds/electric_guitar/68.mp3", + "72": "sounds/electric_guitar/72.mp3", + "76": "sounds/electric_guitar/76.mp3", + "80": "sounds/electric_guitar/80.mp3", + "84": "sounds/electric_guitar/84.mp3" + } }, "piano": { "__collections__": {}, + "baseNotes": { + "100": 99, + "101": 99, + "102": 102, + "103": 102, + "104": 102, + "105": 105, + "106": 105, + "107": 107, + "24": 24, + "25": 24, + "26": 24, + "27": 30, + "28": 30, + "29": 30, + "30": 30, + "31": 30, + "32": 30, + "33": 35, + "34": 35, + "35": 35, + "36": 35, + "37": 35, + "38": 39, + "39": 39, + "40": 39, + "41": 39, + "42": 42, + "43": 42, + "44": 42, + "45": 47, + "46": 47, + "47": 47, + "48": 47, + "49": 47, + "50": 51, + "51": 51, + "52": 51, + "53": 51, + "54": 54, + "55": 54, + "56": 54, + "57": 57, + "58": 57, + "59": 57, + "60": 60, + "61": 60, + "62": 60, + "63": 63, + "64": 63, + "65": 63, + "66": 66, + "67": 66, + "68": 66, + "69": 69, + "70": 69, + "71": 69, + "72": 72, + "73": 72, + "74": 72, + "75": 75, + "76": 75, + "77": 75, + "78": 78, + "79": 78, + "80": 78, + "81": 81, + "82": 81, + "83": 81, + "84": 84, + "85": 84, + "86": 84, + "87": 87, + "88": 87, + "89": 87, + "90": 90, + "91": 90, + "92": 90, + "93": 93, + "94": 93, + "95": 93, + "96": 96, + "97": 96, + "98": 96, + "99": 99 + }, "id": "piano", - "maxNote": 108, + "maxNote": 107, "minNote": 24, - "soundFiles": { + "soundPaths": { "102": "sounds/piano/102.mp3", "105": "sounds/piano/105.mp3", "107": "sounds/piano/107.mp3", @@ -482,350 +269,7 @@ "93": "sounds/piano/93.mp3", "96": "sounds/piano/96.mp3", "99": "sounds/piano/99.mp3" - }, - "soundNotes": { - "100": { - "note": 99, - "pitch": 1.0594631 - }, - "101": { - "note": 99, - "pitch": 1.122462 - }, - "102": { - "note": 102, - "pitch": 1 - }, - "103": { - "note": 102, - "pitch": 1.0594631 - }, - "104": { - "note": 102, - "pitch": 1.122462 - }, - "105": { - "note": 105, - "pitch": 1 - }, - "106": { - "note": 105, - "pitch": 1.0594631 - }, - "107": { - "note": 107, - "pitch": 1 - }, - "108": { - "note": 107, - "pitch": 1.0594631 - }, - "24": { - "note": 24, - "pitch": 1 - }, - "25": { - "note": 24, - "pitch": 1.0594631 - }, - "26": { - "note": 24, - "pitch": 1.122462 - }, - "27": { - "note": 30, - "pitch": 0.8408964 - }, - "28": { - "note": 30, - "pitch": 0.8908987 - }, - "29": { - "note": 30, - "pitch": 0.9438743 - }, - "30": { - "note": 30, - "pitch": 1 - }, - "31": { - "note": 30, - "pitch": 1.0594631 - }, - "32": { - "note": 30, - "pitch": 1.122462 - }, - "33": { - "note": 35, - "pitch": 0.8908987 - }, - "34": { - "note": 35, - "pitch": 0.9438743 - }, - "35": { - "note": 35, - "pitch": 1 - }, - "36": { - "note": 35, - "pitch": 1.0594631 - }, - "37": { - "note": 35, - "pitch": 1.122462 - }, - "38": { - "note": 39, - "pitch": 0.9438743 - }, - "39": { - "note": 39, - "pitch": 1 - }, - "40": { - "note": 39, - "pitch": 1.0594631 - }, - "41": { - "note": 39, - "pitch": 1.122462 - }, - "42": { - "note": 42, - "pitch": 1 - }, - "43": { - "note": 42, - "pitch": 1.0594631 - }, - "44": { - "note": 42, - "pitch": 1.122462 - }, - "45": { - "note": 47, - "pitch": 0.8908987 - }, - "46": { - "note": 47, - "pitch": 0.9438743 - }, - "47": { - "note": 47, - "pitch": 1 - }, - "48": { - "note": 47, - "pitch": 1.0594631 - }, - "49": { - "note": 47, - "pitch": 1.122462 - }, - "50": { - "note": 51, - "pitch": 0.9438743 - }, - "51": { - "note": 51, - "pitch": 1 - }, - "52": { - "note": 51, - "pitch": 1.0594631 - }, - "53": { - "note": 51, - "pitch": 1.122462 - }, - "54": { - "note": 54, - "pitch": 1 - }, - "55": { - "note": 54, - "pitch": 1.0594631 - }, - "56": { - "note": 54, - "pitch": 1.122462 - }, - "57": { - "note": 57, - "pitch": 1 - }, - "58": { - "note": 57, - "pitch": 1.0594631 - }, - "59": { - "note": 57, - "pitch": 1.122462 - }, - "60": { - "note": 60, - "pitch": 1 - }, - "61": { - "note": 60, - "pitch": 1.0594631 - }, - "62": { - "note": 60, - "pitch": 1.122462 - }, - "63": { - "note": 63, - "pitch": 1 - }, - "64": { - "note": 63, - "pitch": 1.0594631 - }, - "65": { - "note": 63, - "pitch": 1.122462 - }, - "66": { - "note": 66, - "pitch": 1 - }, - "67": { - "note": 66, - "pitch": 1.0594631 - }, - "68": { - "note": 66, - "pitch": 1.122462 - }, - "69": { - "note": 69, - "pitch": 1 - }, - "70": { - "note": 69, - "pitch": 1.0594631 - }, - "71": { - "note": 69, - "pitch": 1.122462 - }, - "72": { - "note": 72, - "pitch": 1 - }, - "73": { - "note": 72, - "pitch": 1.0594631 - }, - "74": { - "note": 72, - "pitch": 1.122462 - }, - "75": { - "note": 75, - "pitch": 1 - }, - "76": { - "note": 75, - "pitch": 1.0594631 - }, - "77": { - "note": 75, - "pitch": 1.122462 - }, - "78": { - "note": 78, - "pitch": 1 - }, - "79": { - "note": 78, - "pitch": 1.0594631 - }, - "80": { - "note": 78, - "pitch": 1.122462 - }, - "81": { - "note": 81, - "pitch": 1 - }, - "82": { - "note": 81, - "pitch": 1.0594631 - }, - "83": { - "note": 81, - "pitch": 1.122462 - }, - "84": { - "note": 84, - "pitch": 1 - }, - "85": { - "note": 84, - "pitch": 1.0594631 - }, - "86": { - "note": 84, - "pitch": 1.122462 - }, - "87": { - "note": 87, - "pitch": 1 - }, - "88": { - "note": 87, - "pitch": 1.0594631 - }, - "89": { - "note": 87, - "pitch": 1.122462 - }, - "90": { - "note": 90, - "pitch": 1 - }, - "91": { - "note": 90, - "pitch": 1.0594631 - }, - "92": { - "note": 90, - "pitch": 1.122462 - }, - "93": { - "note": 93, - "pitch": 1 - }, - "94": { - "note": 93, - "pitch": 1.0594631 - }, - "95": { - "note": 93, - "pitch": 1.122462 - }, - "96": { - "note": 96, - "pitch": 1 - }, - "97": { - "note": 96, - "pitch": 1.0594631 - }, - "98": { - "note": 96, - "pitch": 1.122462 - }, - "99": { - "note": 99, - "pitch": 1 - } - }, - "volume": 0.5 + } } }, "songs": { diff --git a/ios/.gitignore b/ios/.gitignore index e96ef602..4f8654b8 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -30,3 +30,4 @@ Runner/GeneratedPluginRegistrant.* !default.mode2v3 !default.pbxuser !default.perspectivev3 +/Runner/GoogleService-Info.plist diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee8..e8efba11 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee8..399e9340 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 00000000..9411102b --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '10.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 00000000..069ada0d --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,538 @@ +PODS: + - abseil/algorithm (0.20200225.0): + - abseil/algorithm/algorithm (= 0.20200225.0) + - abseil/algorithm/container (= 0.20200225.0) + - abseil/algorithm/algorithm (0.20200225.0): + - abseil/base/config + - abseil/algorithm/container (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/base (0.20200225.0): + - abseil/base/atomic_hook (= 0.20200225.0) + - abseil/base/base (= 0.20200225.0) + - abseil/base/base_internal (= 0.20200225.0) + - abseil/base/bits (= 0.20200225.0) + - abseil/base/config (= 0.20200225.0) + - abseil/base/core_headers (= 0.20200225.0) + - abseil/base/dynamic_annotations (= 0.20200225.0) + - abseil/base/endian (= 0.20200225.0) + - abseil/base/errno_saver (= 0.20200225.0) + - abseil/base/exponential_biased (= 0.20200225.0) + - abseil/base/log_severity (= 0.20200225.0) + - abseil/base/malloc_internal (= 0.20200225.0) + - abseil/base/periodic_sampler (= 0.20200225.0) + - abseil/base/pretty_function (= 0.20200225.0) + - abseil/base/raw_logging_internal (= 0.20200225.0) + - abseil/base/spinlock_wait (= 0.20200225.0) + - abseil/base/throw_delegate (= 0.20200225.0) + - abseil/base/atomic_hook (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/base (0.20200225.0): + - abseil/base/atomic_hook + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/log_severity + - abseil/base/raw_logging_internal + - abseil/base/spinlock_wait + - abseil/meta/type_traits + - abseil/base/base_internal (0.20200225.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/base/bits (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/config (0.20200225.0) + - abseil/base/core_headers (0.20200225.0): + - abseil/base/config + - abseil/base/dynamic_annotations (0.20200225.0) + - abseil/base/endian (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/errno_saver (0.20200225.0): + - abseil/base/config + - abseil/base/exponential_biased (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/log_severity (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/malloc_internal (0.20200225.0): + - abseil/base/base + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/raw_logging_internal + - abseil/base/periodic_sampler (0.20200225.0): + - abseil/base/core_headers + - abseil/base/exponential_biased + - abseil/base/pretty_function (0.20200225.0) + - abseil/base/raw_logging_internal (0.20200225.0): + - abseil/base/atomic_hook + - abseil/base/config + - abseil/base/core_headers + - abseil/base/log_severity + - abseil/base/spinlock_wait (0.20200225.0): + - abseil/base/base_internal + - abseil/base/core_headers + - abseil/base/errno_saver + - abseil/base/throw_delegate (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/container/compressed_tuple (0.20200225.0): + - abseil/utility/utility + - abseil/container/inlined_vector (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/container/inlined_vector_internal + - abseil/memory/memory + - abseil/container/inlined_vector_internal (0.20200225.0): + - abseil/base/core_headers + - abseil/container/compressed_tuple + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/span + - abseil/memory (0.20200225.0): + - abseil/memory/memory (= 0.20200225.0) + - abseil/memory/memory (0.20200225.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/meta (0.20200225.0): + - abseil/meta/type_traits (= 0.20200225.0) + - abseil/meta/type_traits (0.20200225.0): + - abseil/base/config + - abseil/numeric/int128 (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/strings/internal (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/meta/type_traits + - abseil/strings/str_format (0.20200225.0): + - abseil/strings/str_format_internal + - abseil/strings/str_format_internal (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/types/span + - abseil/strings/strings (0.20200225.0): + - abseil/base/base + - abseil/base/bits + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/base/throw_delegate + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/internal + - abseil/time (0.20200225.0): + - abseil/time/internal (= 0.20200225.0) + - abseil/time/time (= 0.20200225.0) + - abseil/time/internal (0.20200225.0): + - abseil/time/internal/cctz (= 0.20200225.0) + - abseil/time/internal/cctz (0.20200225.0): + - abseil/time/internal/cctz/civil_time (= 0.20200225.0) + - abseil/time/internal/cctz/time_zone (= 0.20200225.0) + - abseil/time/internal/cctz/civil_time (0.20200225.0): + - abseil/base/config + - abseil/time/internal/cctz/time_zone (0.20200225.0): + - abseil/base/config + - abseil/time/internal/cctz/civil_time + - abseil/time/time (0.20200225.0): + - abseil/base/base + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/time/internal/cctz/civil_time + - abseil/time/internal/cctz/time_zone + - abseil/types (0.20200225.0): + - abseil/types/any (= 0.20200225.0) + - abseil/types/bad_any_cast (= 0.20200225.0) + - abseil/types/bad_any_cast_impl (= 0.20200225.0) + - abseil/types/bad_optional_access (= 0.20200225.0) + - abseil/types/bad_variant_access (= 0.20200225.0) + - abseil/types/compare (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - abseil/types/span (= 0.20200225.0) + - abseil/types/variant (= 0.20200225.0) + - abseil/types/any (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_any_cast + - abseil/utility/utility + - abseil/types/bad_any_cast (0.20200225.0): + - abseil/base/config + - abseil/types/bad_any_cast_impl + - abseil/types/bad_any_cast_impl (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_optional_access (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_variant_access (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/compare (0.20200225.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/optional (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/bad_optional_access + - abseil/utility/utility + - abseil/types/span (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/meta/type_traits + - abseil/types/variant (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_variant_access + - abseil/utility/utility + - abseil/utility/utility (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/meta/type_traits + - AppAuth (1.4.0): + - AppAuth/Core (= 1.4.0) + - AppAuth/ExternalUserAgent (= 1.4.0) + - AppAuth/Core (1.4.0) + - AppAuth/ExternalUserAgent (1.4.0) + - audioplayers (0.0.1): + - Flutter + - BoringSSL-GRPC (0.0.7): + - BoringSSL-GRPC/Implementation (= 0.0.7) + - BoringSSL-GRPC/Interface (= 0.0.7) + - BoringSSL-GRPC/Implementation (0.0.7): + - BoringSSL-GRPC/Interface (= 0.0.7) + - BoringSSL-GRPC/Interface (0.0.7) + - cloud_firestore (0.16.0): + - Firebase/Firestore (= 7.3.0) + - firebase_core + - Flutter + - cloud_functions (0.9.0): + - Firebase/Functions (= 7.3.0) + - firebase_core + - Flutter + - device_info (0.0.1): + - Flutter + - FBSDKCoreKit (5.15.1): + - FBSDKCoreKit/Basics (= 5.15.1) + - FBSDKCoreKit/Core (= 5.15.1) + - FBSDKCoreKit/Basics (5.15.1) + - FBSDKCoreKit/Core (5.15.1): + - FBSDKCoreKit/Basics + - FBSDKLoginKit (5.15.1): + - FBSDKLoginKit/Login (= 5.15.1) + - FBSDKLoginKit/Login (5.15.1): + - FBSDKCoreKit (~> 5.0) + - Firebase/Auth (7.3.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 7.3.0) + - Firebase/CoreOnly (7.3.0): + - FirebaseCore (= 7.3.0) + - Firebase/DynamicLinks (7.3.0): + - Firebase/CoreOnly + - FirebaseDynamicLinks (~> 7.3.0) + - Firebase/Firestore (7.3.0): + - Firebase/CoreOnly + - FirebaseFirestore (~> 7.3.0) + - Firebase/Functions (7.3.0): + - Firebase/CoreOnly + - FirebaseFunctions (~> 7.3.0) + - Firebase/Storage (7.3.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 7.3.0) + - firebase_auth (0.20.0-1): + - Firebase/Auth (= 7.3.0) + - firebase_core + - Flutter + - firebase_core (0.7.0): + - Firebase/CoreOnly (= 7.3.0) + - Flutter + - firebase_dynamic_links (0.7.0-1): + - Firebase/DynamicLinks (= 7.3.0) + - firebase_core + - Flutter + - firebase_storage (7.0.0): + - Firebase/Storage (= 7.3.0) + - firebase_core + - Flutter + - FirebaseAuth (7.3.0): + - FirebaseCore (~> 7.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.0) + - GoogleUtilities/Environment (~> 7.0) + - GTMSessionFetcher/Core (~> 1.4) + - FirebaseCore (7.3.0): + - FirebaseCoreDiagnostics (~> 7.0) + - GoogleUtilities/Environment (~> 7.0) + - GoogleUtilities/Logger (~> 7.0) + - FirebaseCoreDiagnostics (7.3.0): + - GoogleDataTransport (~> 8.0) + - GoogleUtilities/Environment (~> 7.0) + - GoogleUtilities/Logger (~> 7.0) + - nanopb (~> 2.30906.0) + - FirebaseDynamicLinks (7.3.1): + - FirebaseCore (~> 7.0) + - FirebaseFirestore (7.3.0): + - abseil/algorithm (= 0.20200225.0) + - abseil/base (= 0.20200225.0) + - abseil/memory (= 0.20200225.0) + - abseil/meta (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/time (= 0.20200225.0) + - abseil/types (= 0.20200225.0) + - FirebaseCore (~> 7.0) + - "gRPC-C++ (~> 1.28.0)" + - leveldb-library (~> 1.22) + - nanopb (~> 2.30906.0) + - FirebaseFunctions (7.3.0): + - FirebaseCore (~> 7.0) + - GTMSessionFetcher/Core (~> 1.4) + - FirebaseStorage (7.3.0): + - FirebaseCore (~> 7.0) + - GTMSessionFetcher/Core (~> 1.4) + - Flutter (1.0.0) + - flutter_email_sender (0.0.1): + - Flutter + - flutter_facebook_login (0.0.1): + - FBSDKCoreKit (~> 5.5) + - FBSDKLoginKit (~> 5.5) + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - google_sign_in (0.0.1): + - Flutter + - GoogleSignIn (~> 5.0) + - GoogleDataTransport (8.1.0): + - nanopb (~> 2.30906.0) + - GoogleSignIn (5.0.2): + - AppAuth (~> 1.2) + - GTMAppAuth (~> 1.0) + - GTMSessionFetcher/Core (~> 1.1) + - GoogleUtilities/AppDelegateSwizzler (7.2.2): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.2.2): + - PromisesObjC (~> 1.2) + - GoogleUtilities/Logger (7.2.2): + - GoogleUtilities/Environment + - GoogleUtilities/Network (7.2.2): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.2.2)" + - GoogleUtilities/Reachability (7.2.2): + - GoogleUtilities/Logger + - "gRPC-C++ (1.28.2)": + - "gRPC-C++/Implementation (= 1.28.2)" + - "gRPC-C++/Interface (= 1.28.2)" + - "gRPC-C++/Implementation (1.28.2)": + - abseil/container/inlined_vector (= 0.20200225.0) + - abseil/memory/memory (= 0.20200225.0) + - abseil/strings/str_format (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - "gRPC-C++/Interface (= 1.28.2)" + - gRPC-Core (= 1.28.2) + - "gRPC-C++/Interface (1.28.2)" + - gRPC-Core (1.28.2): + - gRPC-Core/Implementation (= 1.28.2) + - gRPC-Core/Interface (= 1.28.2) + - gRPC-Core/Implementation (1.28.2): + - abseil/container/inlined_vector (= 0.20200225.0) + - abseil/memory/memory (= 0.20200225.0) + - abseil/strings/str_format (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - BoringSSL-GRPC (= 0.0.7) + - gRPC-Core/Interface (= 1.28.2) + - gRPC-Core/Interface (1.28.2) + - GTMAppAuth (1.1.0): + - AppAuth/Core (~> 1.4) + - GTMSessionFetcher (~> 1.4) + - GTMSessionFetcher (1.5.0): + - GTMSessionFetcher/Full (= 1.5.0) + - GTMSessionFetcher/Core (1.5.0) + - GTMSessionFetcher/Full (1.5.0): + - GTMSessionFetcher/Core (= 1.5.0) + - in_app_review (0.2.0): + - Flutter + - leveldb-library (1.22) + - nanopb (2.30906.0): + - nanopb/decode (= 2.30906.0) + - nanopb/encode (= 2.30906.0) + - nanopb/decode (2.30906.0) + - nanopb/encode (2.30906.0) + - package_info (0.0.1): + - Flutter + - path_provider (0.0.1): + - Flutter + - PromisesObjC (1.2.12) + - share (0.0.1): + - Flutter + - shared_preferences (0.0.1): + - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) + - url_launcher (0.0.1): + - Flutter + +DEPENDENCIES: + - audioplayers (from `.symlinks/plugins/audioplayers/ios`) + - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) + - cloud_functions (from `.symlinks/plugins/cloud_functions/ios`) + - device_info (from `.symlinks/plugins/device_info/ios`) + - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_dynamic_links (from `.symlinks/plugins/firebase_dynamic_links/ios`) + - firebase_storage (from `.symlinks/plugins/firebase_storage/ios`) + - Flutter (from `Flutter`) + - flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`) + - flutter_facebook_login (from `.symlinks/plugins/flutter_facebook_login/ios`) + - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`) + - in_app_review (from `.symlinks/plugins/in_app_review/ios`) + - package_info (from `.symlinks/plugins/package_info/ios`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - share (from `.symlinks/plugins/share/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + +SPEC REPOS: + trunk: + - abseil + - AppAuth + - BoringSSL-GRPC + - FBSDKCoreKit + - FBSDKLoginKit + - Firebase + - FirebaseAuth + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDynamicLinks + - FirebaseFirestore + - FirebaseFunctions + - FirebaseStorage + - FMDB + - GoogleDataTransport + - GoogleSignIn + - GoogleUtilities + - "gRPC-C++" + - gRPC-Core + - GTMAppAuth + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + +EXTERNAL SOURCES: + audioplayers: + :path: ".symlinks/plugins/audioplayers/ios" + cloud_firestore: + :path: ".symlinks/plugins/cloud_firestore/ios" + cloud_functions: + :path: ".symlinks/plugins/cloud_functions/ios" + device_info: + :path: ".symlinks/plugins/device_info/ios" + firebase_auth: + :path: ".symlinks/plugins/firebase_auth/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_dynamic_links: + :path: ".symlinks/plugins/firebase_dynamic_links/ios" + firebase_storage: + :path: ".symlinks/plugins/firebase_storage/ios" + Flutter: + :path: Flutter + flutter_email_sender: + :path: ".symlinks/plugins/flutter_email_sender/ios" + flutter_facebook_login: + :path: ".symlinks/plugins/flutter_facebook_login/ios" + google_sign_in: + :path: ".symlinks/plugins/google_sign_in/ios" + in_app_review: + :path: ".symlinks/plugins/in_app_review/ios" + package_info: + :path: ".symlinks/plugins/package_info/ios" + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + share: + :path: ".symlinks/plugins/share/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + +SPEC CHECKSUMS: + abseil: 6c8eb7892aefa08d929b39f9bb108e5367e3228f + AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7 + audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c + BoringSSL-GRPC: 8edf627ee524575e2f8d19d56f068b448eea3879 + cloud_firestore: 433cf1aece50c727965355ae00e8dbeeceae66b1 + cloud_functions: b4880478d8484299647004b1ee9d2d75b156ee03 + device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 + FBSDKCoreKit: 1d5acf7c9d7a2f92bb1a242dc60cae5b7adb91df + FBSDKLoginKit: f1ea8026a58b52d30c9f2e6a58ca7d813619fb83 + Firebase: 26223c695fe322633274198cb19dca8cb7e54416 + firebase_auth: b55e5136528dced982022ee073ed4b48f15c055c + firebase_core: 91b27774a52f41f8b58484a75edf71197ac01c59 + firebase_dynamic_links: 14bf04008446c471b5c9f6e6542e14210bf26bd5 + firebase_storage: 554b8ce9192bfe0bd35f63da42d0d1f6ae819ccc + FirebaseAuth: c224a0cf1afa0949bd5c7bfcf154b4f5ce8ddef2 + FirebaseCore: 4d3c72622ce0e2106aaa07bb4b2935ba2c370972 + FirebaseCoreDiagnostics: d50e11039e5984d92c8a512be2395f13df747350 + FirebaseDynamicLinks: a6df95d6dbc746c2bbf7d511343cda1344e2cf70 + FirebaseFirestore: 1906bf163afdb7c432d2e3b5c40ceb9dd2df5820 + FirebaseFunctions: 56b7275ad46d936b77b64ecacd306e77db7be251 + FirebaseStorage: 5002b1895bfe74a5ce92ad54f966e6162d0da2e5 + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b + flutter_facebook_login: cfb5659f686b1c575ef205c6b6fd20db9679d3c4 + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc + GoogleDataTransport: 116c84c4bdeb76be2a7a46de51244368f9794eab + GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213 + GoogleUtilities: 31c5b01f978a70c6cff2afc6272b3f1921614b43 + "gRPC-C++": 13d8ccef97d5c3c441b7e3c529ef28ebee86fad2 + gRPC-Core: 4afa11bfbedf7cdecd04de535a9e046893404ed5 + GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9 + GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 + in_app_review: 4a97249f7a2f539a0f294c2d9196b7fe35e49541 + leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 + nanopb: 1bf24dd71191072e120b83dd02d08f3da0d65e53 + package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97 + share: 0b2c3e82132f5888bccca3351c504d0003b3b410 + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + +PODFILE CHECKSUM: fe0e1ee7f3d1f7d00b11b474b62dd62134535aea + +COCOAPODS: 1.10.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 31f9995e..048bb196 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,12 +3,15 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ + 1405C8E5B0F94F4AC872A4BF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F18839835C9F5E66BB582475 /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 5EA1D41725DC1A06001FB55B /* SoundMethodCallHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EA1D41625DC1A06001FB55B /* SoundMethodCallHandler.swift */; }; + 5EA1D41B25DC1A57001FB55B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5EA1D41A25DC1A57001FB55B /* GoogleService-Info.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -29,9 +32,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0F647CDEE689C36BF8CAF4ED /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 5EA1D41625DC1A06001FB55B /* SoundMethodCallHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoundMethodCallHandler.swift; sourceTree = ""; }; + 5EA1D41A25DC1A57001FB55B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -42,6 +48,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9F2D0A378488812A48B4A08A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F18839835C9F5E66BB582475 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FAB176F29BBF5AD5287F9740 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -49,12 +58,23 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1405C8E5B0F94F4AC872A4BF /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 58ABB834509D49F1995FB017 /* Pods */ = { + isa = PBXGroup; + children = ( + 9F2D0A378488812A48B4A08A /* Pods-Runner.debug.xcconfig */, + FAB176F29BBF5AD5287F9740 /* Pods-Runner.release.xcconfig */, + 0F647CDEE689C36BF8CAF4ED /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +92,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 58ABB834509D49F1995FB017 /* Pods */, + DA9F9612F89A0D08D4844F8E /* Frameworks */, ); sourceTree = ""; }; @@ -86,6 +108,8 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 5EA1D41A25DC1A57001FB55B /* GoogleService-Info.plist */, + 5EA1D41625DC1A06001FB55B /* SoundMethodCallHandler.swift */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -98,6 +122,14 @@ path = Runner; sourceTree = ""; }; + DA9F9612F89A0D08D4844F8E /* Frameworks */ = { + isa = PBXGroup; + children = ( + F18839835C9F5E66BB582475 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -105,12 +137,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + EA90F68703DC121426BA7B27 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + A2F5482701A71BB1B60A1AF3 /* [CP] Embed Pods Frameworks */, + 8A4FB4697E0D80A731769358 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -161,6 +196,7 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 5EA1D41B25DC1A57001FB55B /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -183,6 +219,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 8A4FB4697E0D80A731769358 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -197,6 +250,45 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A2F5482701A71BB1B60A1AF3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + EA90F68703DC121426BA7B27 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -204,6 +296,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5EA1D41725DC1A06001FB55B /* SoundMethodCallHandler.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); @@ -288,18 +381,24 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = N86MB5VSWU; ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hitnotes; + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hittick; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -407,7 +506,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -420,18 +520,24 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = N86MB5VSWU; ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hitnotes; + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hittick; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -447,18 +553,23 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = N86MB5VSWU; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hitnotes; + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.chaomao.hittick; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..fb2dffc4 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4a..f08266bb 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -3,11 +3,14 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + FlutterMethodChannel(name: "com.chaomao.hitnotes/sound_player", + binaryMessenger: controller.binaryMessenger).setMethodCallHandler(SoundMethodCallHandler().handle) + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc9ada47..7f9ea81e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 28c6bf03..8a503580 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 2ccbfd96..f7e2a265 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index f091b6b0..0fcf9c03 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cde1211..05988e93 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index d0ef06e7..d70014d7 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index dcdc2306..d5e31837 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 2ccbfd96..f7e2a265 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index c8f9ed8f..c6b06ef3 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index a6d6b860..5f0073bf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b860..5f0073bf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164..9d4ab07e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d3..b518a51a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 6a84f41e..9a0185ad 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index d0e1f585..9dfff4e2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png index 9da19eac..cb35ca49 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png index 9da19eac..4decbff9 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png index 9da19eac..3c44c0d2 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index b504c7ab..b19ea04d 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + HitNotes CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) + $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion - $(FLUTTER_BUILD_NUMBER) + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS UILaunchStoryboardName @@ -28,15 +30,21 @@ Main UISupportedInterfaceOrientations - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.839556303918-qc22f79vfgfd6r03958nofvv0tcssldf + + + UISupportedInterfaceOrientations~ipad - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance diff --git a/ios/Runner/SoundMethodCallHandler.swift b/ios/Runner/SoundMethodCallHandler.swift new file mode 100644 index 00000000..7cb9d9ca --- /dev/null +++ b/ios/Runner/SoundMethodCallHandler.swift @@ -0,0 +1,71 @@ +import Flutter +import UIKit +import AVFoundation + + +public class SoundMethodCallHandler: NSObject { + + private lazy var engine = AVAudioEngine() + private lazy var players = [Int: AVAudioPlayerNode]() + private lazy var files = [Int: AVAudioFile]() + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "load": + let attributes = call.arguments as! NSDictionary + let soundPaths = attributes["soundPaths"] as! [Int: String] + let baseNotes = attributes["baseNotes"] as! [Int: Int] + + var audioFiles = [Int: AVAudioFile]() + + for (baseNote, path) in soundPaths { + let fileUrl = NSURL.init(fileURLWithPath: path) + let file = try! AVAudioFile(forReading:fileUrl.absoluteURL!) + audioFiles[baseNote] = file + } + + for (note, baseNote) in baseNotes { + let file = audioFiles[baseNote]! + let player = AVAudioPlayerNode() + let pitch: Float = Float((note - baseNote) * 100) + players[note] = player + files[note] = file + engine.attach(player) + if (pitch != 0) { + let pitchEffect = AVAudioUnitTimePitch() + pitchEffect.pitch = pitch + engine.attach(pitchEffect) + engine.connect(player, to: pitchEffect, format: file.processingFormat) + engine.connect(pitchEffect, to: engine.mainMixerNode, format: file.processingFormat) + } else { + engine.connect(player, to: engine.mainMixerNode, format: file.processingFormat) + } + } + engine.prepare() + do { + try engine.start() + } catch let err { + print(err.localizedDescription) + } + result(nil) + case "play": + let attributes = call.arguments as! NSDictionary + let note = attributes["note"] as! Int + let player = players[note]! + if player.isPlaying { + player.stop() + } + player.scheduleFile(files[note]!, at: nil) + player.play() + result(nil) + case "release": + players.removeAll() + files.removeAll() + engine.stop() + engine.reset() + result(nil) + default: + result("notImplemented") + } + } +} diff --git a/lib/authentication/authentication_bloc.dart b/lib/authentication/authentication_bloc.dart index c1926ca2..45cdb690 100644 --- a/lib/authentication/authentication_bloc.dart +++ b/lib/authentication/authentication_bloc.dart @@ -37,7 +37,7 @@ class AuthenticationBloc if (currentUser == null) { await FirebaseAuth.instance.signInAnonymously(); } - _userRepository.changUser(); + _userRepository.subscribeUser(); yield Authenticated('Anonymous'); } catch (_) { yield Unauthenticated(); @@ -53,7 +53,7 @@ class AuthenticationBloc idToken: googleAuth.idToken, ); await _tryToLinkWithCurrentUser(credential); - _userRepository.changUser(); + _userRepository.subscribeUser(); yield Authenticated('Google'); } on Exception { yield Unauthenticated(); @@ -68,7 +68,7 @@ class AuthenticationBloc final credential = FacebookAuthProvider.credential(result.accessToken.token); await _tryToLinkWithCurrentUser(credential); - _userRepository.changUser(); + _userRepository.subscribeUser(); yield Authenticated('Facebook'); break; default: diff --git a/lib/game/complete_dialog.dart b/lib/game/complete_dialog.dart index 62364a26..3846dd3a 100644 --- a/lib/game/complete_dialog.dart +++ b/lib/game/complete_dialog.dart @@ -12,74 +12,77 @@ class CompleteDialog extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: Align( - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image( - image: AssetImage((_gameReward.stars >= 1) - ? 'assets/images/img_star_rate.png' - : 'assets/images/img_star_rate_disable.png')), - SizedBox(width: 8), - Image( - image: AssetImage((_gameReward.stars >= 2) - ? 'assets/images/img_star_rate.png' - : 'assets/images/img_star_rate_disable.png')), - SizedBox(width: 8), - Image( - image: AssetImage((_gameReward.stars >= 3) - ? 'assets/images/img_star_rate.png' - : 'assets/images/img_star_rate_disable.png')), - ], - ), - SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image(image: AssetImage('assets/images/img_note.png')), - SizedBox(width: 8), - Text(_gameReward.playedNotes.toString()) - ], - ), - ], - )), - ), - Row( - children: [ - SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - }, - child: Text(S.of(context).txt_button_quit), - ), - ), - SizedBox(width: 8), - Expanded( - child: ElevatedButton( + child: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Align( + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + image: AssetImage((_gameReward.stars >= 1) + ? 'assets/images/img_star_rate.png' + : 'assets/images/img_star_rate_disable.png')), + SizedBox(width: 8), + Image( + image: AssetImage((_gameReward.stars >= 2) + ? 'assets/images/img_star_rate.png' + : 'assets/images/img_star_rate_disable.png')), + SizedBox(width: 8), + Image( + image: AssetImage((_gameReward.stars >= 3) + ? 'assets/images/img_star_rate.png' + : 'assets/images/img_star_rate_disable.png')), + ], + ), + SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + image: AssetImage('assets/images/img_note.png')), + SizedBox(width: 8), + Text(_gameReward.playedNotes.toString()) + ], + ), + ], + )), + ), + Row( + children: [ + SizedBox(width: 8), + Expanded( + child: ElevatedButton( onPressed: () { - _onRestart(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); Navigator.of(context).pop(); }, - child: Text(S.of(context).txt_button_restart)), - ), - SizedBox(width: 8) - ], - ) - ], + child: Text(S.of(context).txt_button_quit), + ), + ), + SizedBox(width: 8), + Expanded( + child: ElevatedButton( + onPressed: () { + _onRestart(); + Navigator.of(context).pop(); + }, + child: Text(S.of(context).txt_button_restart)), + ), + SizedBox(width: 8) + ], + ) + ], + ), ), ); } diff --git a/lib/game/game_widget.dart b/lib/game/game_widget.dart index 3a6b4c50..9500fa0b 100644 --- a/lib/game/game_widget.dart +++ b/lib/game/game_widget.dart @@ -35,12 +35,14 @@ class _GameWidgetState extends State { BlocProvider.of(context).pauseStream.listen((event) { showDialog( context: context, + useSafeArea: false, builder: (_) => PauseDialog(_onRestart), ); }); BlocProvider.of(context).completeStream.listen((event) { showDialog( context: context, + useSafeArea: false, builder: (_) => CompleteDialog(event, _onRestart), ); }); @@ -90,54 +92,63 @@ class _GameWidgetState extends State { height: NON_TOUCH_REGION_HEIGHT.toDouble(), child: Material( color: Colors.transparent, - child: Column( - children: [ - LinearProgressIndicator( - backgroundColor: onBackgroundColor.withOpacity(0.1), - valueColor: AlwaysStoppedAnimation(secondaryColor), - value: (state as GameUpdated).time / - (state as GameUpdated).maxTime, - ), - Padding( - padding: EdgeInsets.all(8), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text((state as GameUpdated).songName, - style: Theme.of(context).textTheme.headline6), - Text( - '${(state as GameUpdated).time.toInt() ~/ 60}:${((state as GameUpdated).time.toInt() % 60).toString().padLeft(2, '0')}/${(state as GameUpdated).maxTime.toInt() ~/ 60}:${((state as GameUpdated).maxTime.toInt() % 60).toString().padLeft(2, '0')}', - style: Theme.of(context).textTheme.headline6) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - iconSize: 38, - icon: Icon(Icons.pause_circle_outline_rounded), - onPressed: () { - BlocProvider.of(context) - .add(PauseGame()); - }, - ), - Text((state as GameUpdated).tilesCount.toString(), - style: Theme.of(context) - .textTheme - .headline4 - .copyWith(color: secondaryColor)) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [GuideTextWidget()], - ) - ], + child: SafeArea( + child: Column( + children: [ + LinearProgressIndicator( + backgroundColor: onBackgroundColor.withOpacity(0.1), + valueColor: + AlwaysStoppedAnimation(secondaryColor), + value: (state as GameUpdated).time / + (state as GameUpdated).maxTime, ), - ) - ], + Padding( + padding: EdgeInsets.all(8), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text((state as GameUpdated).songName, + style: + Theme.of(context).textTheme.headline6), + Text( + '${(state as GameUpdated).time.toInt() ~/ 60}:${((state as GameUpdated).time.toInt() % 60).toString().padLeft(2, '0')}/${(state as GameUpdated).maxTime.toInt() ~/ 60}:${((state as GameUpdated).maxTime.toInt() % 60).toString().padLeft(2, '0')}', + style: + Theme.of(context).textTheme.headline6) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + iconSize: 38, + icon: + Icon(Icons.pause_circle_outline_rounded), + onPressed: () { + BlocProvider.of(context) + .add(PauseGame()); + }, + ), + Text( + (state as GameUpdated) + .tilesCount + .toString(), + style: Theme.of(context) + .textTheme + .headline4 + .copyWith(color: secondaryColor)) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [GuideTextWidget()], + ) + ], + ), + ) + ], + ), ), )) ]); @@ -198,22 +209,24 @@ class LoadingSoundWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - child: Padding( - padding: EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Align( - alignment: Alignment.center, - child: Image( - image: AssetImage('assets/images/img_app_icon.png')), + child: SafeArea( + child: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Align( + alignment: Alignment.center, + child: Image( + image: AssetImage('assets/images/img_app_icon.png')), + ), ), - ), - Text(S.of(context).txt_dialog_loading_sound_description) - ], - )), + Text(S.of(context).txt_dialog_loading_sound_description) + ], + )), + ), ); } } @@ -226,22 +239,24 @@ class LoadingGiftWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - child: Padding( - padding: EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Align( - alignment: Alignment.center, - child: Image( - image: AssetImage('assets/images/img_app_icon.png')), + child: SafeArea( + child: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Align( + alignment: Alignment.center, + child: Image( + image: AssetImage('assets/images/img_app_icon.png')), + ), ), - ), - Text(S.of(context).txt_game_complete_loading_gift) - ], - )), + Text(S.of(context).txt_game_complete_loading_gift) + ], + )), + ), ); } } diff --git a/lib/game/pause_dialog.dart b/lib/game/pause_dialog.dart index 5093ba72..7bdf8b7b 100644 --- a/lib/game/pause_dialog.dart +++ b/lib/game/pause_dialog.dart @@ -11,32 +11,34 @@ class PauseDialog extends StatelessWidget { Widget build(BuildContext context) { return Material( color: Colors.transparent, - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - }, - child: Text(S.of(context).txt_button_quit), - ), - ElevatedButton( - onPressed: () { - _onRestart(); - Navigator.of(context).pop(); - }, - child: Text(S.of(context).txt_button_restart), - ), - ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text(S.of(context).txt_game_button_continue), - ) - ], + child: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + child: Text(S.of(context).txt_button_quit), + ), + ElevatedButton( + onPressed: () { + _onRestart(); + Navigator.of(context).pop(); + }, + child: Text(S.of(context).txt_button_restart), + ), + ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(S.of(context).txt_game_button_continue), + ) + ], + ), ), ); } diff --git a/lib/game/tile/tile_converter.dart b/lib/game/tile/tile_converter.dart index b1895013..5acb625d 100644 --- a/lib/game/tile/tile_converter.dart +++ b/lib/game/tile/tile_converter.dart @@ -13,7 +13,7 @@ const NUMBER_TILE_COLUMN = 4; const UNIT_DURATION_HEIGHT = 72; const TILE_WIDTH = 36.0; const TILE_HEIGHT = TILE_WIDTH; -const NON_TOUCH_REGION_HEIGHT = 150; +const NON_TOUCH_REGION_HEIGHT = 160; const startVisibleY = 0; double tickToSecond(int resolution, int bpm) { diff --git a/lib/game_config/game_config_widget.dart b/lib/game_config/game_config_widget.dart index 81347ac1..b6003e87 100644 --- a/lib/game_config/game_config_widget.dart +++ b/lib/game_config/game_config_widget.dart @@ -16,120 +16,123 @@ class GameConfigWidget extends StatelessWidget { appBar: AppBar( title: Text(S.of(context).txt_configure, style: Theme.of(context).appBarTheme.textTheme.headline5)), - body: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(S.of(context).txt_difficulty, - style: Theme.of(context).textTheme.headline5), - SizedBox(height: 8), - Row( - children: [ - SizedBox(width: 8), - CardWidget( - selected: state.difficulty == 0, - text: S.of(context).txt_easy, - caption: S.of(context).txt_fingers(2), - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeDifficultyEvent(0)); - }, - ), - SizedBox(width: 8), - CardWidget( - selected: state.difficulty == 1, - text: S.of(context).txt_medium, - caption: S.of(context).txt_fingers(3), - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeDifficultyEvent(1)); - }, - ), - SizedBox(width: 8), - CardWidget( - selected: state.difficulty == 2, - text: S.of(context).txt_difficult, - caption: S.of(context).txt_fingers(4), - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeDifficultyEvent(2)); - }, - ), - SizedBox(width: 8) - ], - ) - ], + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(S.of(context).txt_difficulty, + style: Theme.of(context).textTheme.headline5), + SizedBox(height: 8), + Row( + children: [ + SizedBox(width: 8), + CardWidget( + selected: state.difficulty == 0, + text: S.of(context).txt_easy, + caption: S.of(context).txt_fingers(2), + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeDifficultyEvent(0)); + }, + ), + SizedBox(width: 8), + CardWidget( + selected: state.difficulty == 1, + text: S.of(context).txt_medium, + caption: S.of(context).txt_fingers(3), + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeDifficultyEvent(1)); + }, + ), + SizedBox(width: 8), + CardWidget( + selected: state.difficulty == 2, + text: S.of(context).txt_difficult, + caption: S.of(context).txt_fingers(4), + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeDifficultyEvent(2)); + }, + ), + SizedBox(width: 8) + ], + ) + ], + ), ), - ), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, + Expanded( + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(S.of(context).txt_speed, + style: Theme.of(context).textTheme.headline5), + SizedBox(height: 8), + Row( + children: [ + SizedBox(width: 8), + CardWidget( + selected: state.speed == 0, + text: S.of(context).txt_slow, + caption: 'x0.75', + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeSpeedEvent(0)); + }, + ), + SizedBox(width: 8), + CardWidget( + selected: state.speed == 1, + text: S.of(context).txt_normal, + caption: 'x1.0', + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeSpeedEvent(1)); + }, + ), + SizedBox(width: 8), + CardWidget( + selected: state.speed == 2, + text: S.of(context).txt_fast, + caption: 'x1.25', + onTap: () { + BlocProvider.of(context) + ..add(GameConfigChangeSpeedEvent(2)); + }, + ), + SizedBox(width: 8) + ], + ) + ], + ), + ), + Row( children: [ - Text(S.of(context).txt_speed, - style: Theme.of(context).textTheme.headline5), - SizedBox(height: 8), - Row( - children: [ - SizedBox(width: 8), - CardWidget( - selected: state.speed == 0, - text: S.of(context).txt_slow, - caption: 'x0.75', - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeSpeedEvent(0)); - }, - ), - SizedBox(width: 8), - CardWidget( - selected: state.speed == 1, - text: S.of(context).txt_normal, - caption: 'x1.0', - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeSpeedEvent(1)); - }, - ), - SizedBox(width: 8), - CardWidget( - selected: state.speed == 2, - text: S.of(context).txt_fast, - caption: 'x1.25', - onTap: () { - BlocProvider.of(context) - ..add(GameConfigChangeSpeedEvent(2)); + SizedBox(width: 8), + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.pushNamed(context, Routes.game, + arguments: { + 'song': song, + 'difficulty': state.difficulty, + 'speed': state.speed + }); }, - ), - SizedBox(width: 8) - ], - ) + child: Text(S.of(context).txt_start)), + ), + SizedBox(width: 8) ], - ), - ), - Row( - children: [ - SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: () { - Navigator.pushNamed(context, Routes.game, arguments: { - 'song': song, - 'difficulty': state.difficulty, - 'speed': state.speed - }); - }, - child: Text(S.of(context).txt_start)), - ), - SizedBox(width: 8) - ], - ) - ], + ) + ], + ), )); }); } diff --git a/lib/home/home_bloc.dart b/lib/home/home_bloc.dart deleted file mode 100644 index 270209f3..00000000 --- a/lib/home/home_bloc.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'dart:async'; - -import 'package:bloc/bloc.dart'; - -import '../instrument/instruments_repository.dart'; -import '../midi_processor.dart'; -import '../user/user_repository.dart'; -import 'home_event.dart'; -import 'home_state.dart'; - -class HomeBloc extends Bloc { - final UserRepository _userRepository; - final InstrumentsRepository _instrumentsRepository; - - HomeBloc(this._userRepository, this._instrumentsRepository) - : super(HomeInitial()) { - _userRepository.getCurrentUser().listen((user) async { - if (state is HomeInitial) { - final instrument = (await _instrumentsRepository.instruments()) - .firstWhere( - (instrument) => instrument.id == user.user.instrumentId); - MidiProcessor.getInstance().onSelectInstrument(instrument); - } else if (state is HomeUpdated) { - final oldUser = (state as HomeUpdated).user; - if (oldUser.user.instrumentId != user.user.instrumentId) { - final instrument = (await _instrumentsRepository.instruments()) - .firstWhere( - (instrument) => instrument.id == user.user.instrumentId); - MidiProcessor.getInstance().onSelectInstrument(instrument); - } - } - add(HomeUpdate(user)); - }); - } - - @override - Stream mapEventToState(HomeEvent event) async* { - if (event is HomeUpdate) { - yield HomeUpdated(event.user); - } - } -} diff --git a/lib/home/home_event.dart b/lib/home/home_event.dart deleted file mode 100644 index a740bbaa..00000000 --- a/lib/home/home_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:equatable/equatable.dart'; - -import '../user/user_repository.dart'; - -abstract class HomeEvent extends Equatable { - const HomeEvent(); -} - -class HomeUpdate extends HomeEvent { - final AppUser user; - - const HomeUpdate(this.user); - - @override - List get props => [user]; -} diff --git a/lib/home/home_state.dart b/lib/home/home_state.dart deleted file mode 100644 index 2a24aa20..00000000 --- a/lib/home/home_state.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:equatable/equatable.dart'; - -import '../user/user_repository.dart'; - -abstract class HomeState extends Equatable { - const HomeState(); - - @override - List get props => []; -} - -class HomeInitial extends HomeState {} - -class HomeUpdated extends HomeState { - final AppUser user; - - const HomeUpdated(this.user); - - @override - List get props => [user]; - - @override - String toString() => 'HomeUpdated { photoUrl: $user }'; -} diff --git a/lib/home/home_widget.dart b/lib/home/home_widget.dart index c0e183f1..39c264e1 100644 --- a/lib/home/home_widget.dart +++ b/lib/home/home_widget.dart @@ -7,13 +7,12 @@ import '../main.dart'; import '../routes.dart'; import '../search/search_widget.dart'; import '../songs/songs_widget.dart'; -import 'home_bloc.dart'; -import 'home_state.dart'; +import '../user/user_bloc.dart'; class HomeWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocBuilder( builder: (context, state) { return Scaffold( body: DefaultTabController( @@ -53,7 +52,7 @@ class HomeWidget extends StatelessWidget { }), IconButton( icon: ClipOval( - child: (state is HomeUpdated && + child: (state is UserUpdated && !state.user.isAnonymous) ? Image.network(state.user.photoUrl) : Icon(Icons.account_circle_rounded), diff --git a/lib/instrument/instrument.dart b/lib/instrument/instrument.dart index 04a65408..837d4847 100644 --- a/lib/instrument/instrument.dart +++ b/lib/instrument/instrument.dart @@ -2,8 +2,6 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; -import 'pitch_note.dart'; - part 'instrument.g.dart'; abstract class Instrument implements Built { @@ -15,13 +13,11 @@ abstract class Instrument implements Built { String get id; - BuiltMap get soundFiles; + BuiltMap get soundPaths; - BuiltMap get soundNotes; + BuiltMap get baseNotes; int get minNote; int get maxNote; - - double get volume; } diff --git a/lib/instrument/instrument.g.dart b/lib/instrument/instrument.g.dart index 2328653f..9313d2e7 100644 --- a/lib/instrument/instrument.g.dart +++ b/lib/instrument/instrument.g.dart @@ -20,21 +20,18 @@ class _$InstrumentSerializer implements StructuredSerializer { final result = [ 'id', serializers.serialize(object.id, specifiedType: const FullType(String)), - 'soundFiles', - serializers.serialize(object.soundFiles, + 'soundPaths', + serializers.serialize(object.soundPaths, specifiedType: const FullType( BuiltMap, const [const FullType(int), const FullType(String)])), - 'soundNotes', - serializers.serialize(object.soundNotes, - specifiedType: const FullType(BuiltMap, - const [const FullType(int), const FullType(PitchNote)])), + 'baseNotes', + serializers.serialize(object.baseNotes, + specifiedType: const FullType( + BuiltMap, const [const FullType(int), const FullType(int)])), 'minNote', serializers.serialize(object.minNote, specifiedType: const FullType(int)), 'maxNote', serializers.serialize(object.maxNote, specifiedType: const FullType(int)), - 'volume', - serializers.serialize(object.volume, - specifiedType: const FullType(double)), ]; return result; @@ -55,15 +52,15 @@ class _$InstrumentSerializer implements StructuredSerializer { result.id = serializers.deserialize(value, specifiedType: const FullType(String)) as String; break; - case 'soundFiles': - result.soundFiles.replace(serializers.deserialize(value, + case 'soundPaths': + result.soundPaths.replace(serializers.deserialize(value, specifiedType: const FullType(BuiltMap, const [const FullType(int), const FullType(String)]))); break; - case 'soundNotes': - result.soundNotes.replace(serializers.deserialize(value, - specifiedType: const FullType(BuiltMap, - const [const FullType(int), const FullType(PitchNote)]))); + case 'baseNotes': + result.baseNotes.replace(serializers.deserialize(value, + specifiedType: const FullType( + BuiltMap, const [const FullType(int), const FullType(int)]))); break; case 'minNote': result.minNote = serializers.deserialize(value, @@ -73,10 +70,6 @@ class _$InstrumentSerializer implements StructuredSerializer { result.maxNote = serializers.deserialize(value, specifiedType: const FullType(int)) as int; break; - case 'volume': - result.volume = serializers.deserialize(value, - specifiedType: const FullType(double)) as double; - break; } } @@ -88,35 +81,28 @@ class _$Instrument extends Instrument { @override final String id; @override - final BuiltMap soundFiles; + final BuiltMap soundPaths; @override - final BuiltMap soundNotes; + final BuiltMap baseNotes; @override final int minNote; @override final int maxNote; - @override - final double volume; factory _$Instrument([void Function(InstrumentBuilder) updates]) => (new InstrumentBuilder()..update(updates)).build(); _$Instrument._( - {this.id, - this.soundFiles, - this.soundNotes, - this.minNote, - this.maxNote, - this.volume}) + {this.id, this.soundPaths, this.baseNotes, this.minNote, this.maxNote}) : super._() { if (id == null) { throw new BuiltValueNullFieldError('Instrument', 'id'); } - if (soundFiles == null) { - throw new BuiltValueNullFieldError('Instrument', 'soundFiles'); + if (soundPaths == null) { + throw new BuiltValueNullFieldError('Instrument', 'soundPaths'); } - if (soundNotes == null) { - throw new BuiltValueNullFieldError('Instrument', 'soundNotes'); + if (baseNotes == null) { + throw new BuiltValueNullFieldError('Instrument', 'baseNotes'); } if (minNote == null) { throw new BuiltValueNullFieldError('Instrument', 'minNote'); @@ -124,9 +110,6 @@ class _$Instrument extends Instrument { if (maxNote == null) { throw new BuiltValueNullFieldError('Instrument', 'maxNote'); } - if (volume == null) { - throw new BuiltValueNullFieldError('Instrument', 'volume'); - } } @override @@ -141,34 +124,30 @@ class _$Instrument extends Instrument { if (identical(other, this)) return true; return other is Instrument && id == other.id && - soundFiles == other.soundFiles && - soundNotes == other.soundNotes && + soundPaths == other.soundPaths && + baseNotes == other.baseNotes && minNote == other.minNote && - maxNote == other.maxNote && - volume == other.volume; + maxNote == other.maxNote; } @override int get hashCode { return $jf($jc( $jc( - $jc( - $jc($jc($jc(0, id.hashCode), soundFiles.hashCode), - soundNotes.hashCode), - minNote.hashCode), - maxNote.hashCode), - volume.hashCode)); + $jc($jc($jc(0, id.hashCode), soundPaths.hashCode), + baseNotes.hashCode), + minNote.hashCode), + maxNote.hashCode)); } @override String toString() { return (newBuiltValueToStringHelper('Instrument') ..add('id', id) - ..add('soundFiles', soundFiles) - ..add('soundNotes', soundNotes) + ..add('soundPaths', soundPaths) + ..add('baseNotes', baseNotes) ..add('minNote', minNote) - ..add('maxNote', maxNote) - ..add('volume', volume)) + ..add('maxNote', maxNote)) .toString(); } } @@ -180,17 +159,17 @@ class InstrumentBuilder implements Builder { String get id => _$this._id; set id(String id) => _$this._id = id; - MapBuilder _soundFiles; - MapBuilder get soundFiles => - _$this._soundFiles ??= new MapBuilder(); - set soundFiles(MapBuilder soundFiles) => - _$this._soundFiles = soundFiles; + MapBuilder _soundPaths; + MapBuilder get soundPaths => + _$this._soundPaths ??= new MapBuilder(); + set soundPaths(MapBuilder soundPaths) => + _$this._soundPaths = soundPaths; - MapBuilder _soundNotes; - MapBuilder get soundNotes => - _$this._soundNotes ??= new MapBuilder(); - set soundNotes(MapBuilder soundNotes) => - _$this._soundNotes = soundNotes; + MapBuilder _baseNotes; + MapBuilder get baseNotes => + _$this._baseNotes ??= new MapBuilder(); + set baseNotes(MapBuilder baseNotes) => + _$this._baseNotes = baseNotes; int _minNote; int get minNote => _$this._minNote; @@ -200,20 +179,15 @@ class InstrumentBuilder implements Builder { int get maxNote => _$this._maxNote; set maxNote(int maxNote) => _$this._maxNote = maxNote; - double _volume; - double get volume => _$this._volume; - set volume(double volume) => _$this._volume = volume; - InstrumentBuilder(); InstrumentBuilder get _$this { if (_$v != null) { _id = _$v.id; - _soundFiles = _$v.soundFiles?.toBuilder(); - _soundNotes = _$v.soundNotes?.toBuilder(); + _soundPaths = _$v.soundPaths?.toBuilder(); + _baseNotes = _$v.baseNotes?.toBuilder(); _minNote = _$v.minNote; _maxNote = _$v.maxNote; - _volume = _$v.volume; _$v = null; } return this; @@ -239,18 +213,17 @@ class InstrumentBuilder implements Builder { _$result = _$v ?? new _$Instrument._( id: id, - soundFiles: soundFiles.build(), - soundNotes: soundNotes.build(), + soundPaths: soundPaths.build(), + baseNotes: baseNotes.build(), minNote: minNote, - maxNote: maxNote, - volume: volume); + maxNote: maxNote); } catch (_) { String _$failedField; try { - _$failedField = 'soundFiles'; - soundFiles.build(); - _$failedField = 'soundNotes'; - soundNotes.build(); + _$failedField = 'soundPaths'; + soundPaths.build(); + _$failedField = 'baseNotes'; + baseNotes.build(); } catch (e) { throw new BuiltValueNestedFieldError( 'Instrument', _$failedField, e.toString()); diff --git a/lib/instrument/pitch_note.dart b/lib/instrument/pitch_note.dart deleted file mode 100644 index 8c0e0b44..00000000 --- a/lib/instrument/pitch_note.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; - -part 'pitch_note.g.dart'; - -abstract class PitchNote implements Built { - static Serializer get serializer => _$pitchNoteSerializer; - - factory PitchNote([Function(PitchNoteBuilder) updates]) = _$PitchNote; - - PitchNote._(); - - int get note; - - double get pitch; -} diff --git a/lib/instrument/pitch_note.g.dart b/lib/instrument/pitch_note.g.dart deleted file mode 100644 index 1f2b6852..00000000 --- a/lib/instrument/pitch_note.g.dart +++ /dev/null @@ -1,145 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'pitch_note.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializer _$pitchNoteSerializer = new _$PitchNoteSerializer(); - -class _$PitchNoteSerializer implements StructuredSerializer { - @override - final Iterable types = const [PitchNote, _$PitchNote]; - @override - final String wireName = 'PitchNote'; - - @override - Iterable serialize(Serializers serializers, PitchNote object, - {FullType specifiedType = FullType.unspecified}) { - final result = [ - 'note', - serializers.serialize(object.note, specifiedType: const FullType(int)), - 'pitch', - serializers.serialize(object.pitch, - specifiedType: const FullType(double)), - ]; - - return result; - } - - @override - PitchNote deserialize(Serializers serializers, Iterable serialized, - {FullType specifiedType = FullType.unspecified}) { - final result = new PitchNoteBuilder(); - - final iterator = serialized.iterator; - while (iterator.moveNext()) { - final key = iterator.current as String; - iterator.moveNext(); - final dynamic value = iterator.current; - switch (key) { - case 'note': - result.note = serializers.deserialize(value, - specifiedType: const FullType(int)) as int; - break; - case 'pitch': - result.pitch = serializers.deserialize(value, - specifiedType: const FullType(double)) as double; - break; - } - } - - return result.build(); - } -} - -class _$PitchNote extends PitchNote { - @override - final int note; - @override - final double pitch; - - factory _$PitchNote([void Function(PitchNoteBuilder) updates]) => - (new PitchNoteBuilder()..update(updates)).build(); - - _$PitchNote._({this.note, this.pitch}) : super._() { - if (note == null) { - throw new BuiltValueNullFieldError('PitchNote', 'note'); - } - if (pitch == null) { - throw new BuiltValueNullFieldError('PitchNote', 'pitch'); - } - } - - @override - PitchNote rebuild(void Function(PitchNoteBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - PitchNoteBuilder toBuilder() => new PitchNoteBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is PitchNote && note == other.note && pitch == other.pitch; - } - - @override - int get hashCode { - return $jf($jc($jc(0, note.hashCode), pitch.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('PitchNote') - ..add('note', note) - ..add('pitch', pitch)) - .toString(); - } -} - -class PitchNoteBuilder implements Builder { - _$PitchNote _$v; - - int _note; - int get note => _$this._note; - set note(int note) => _$this._note = note; - - double _pitch; - double get pitch => _$this._pitch; - set pitch(double pitch) => _$this._pitch = pitch; - - PitchNoteBuilder(); - - PitchNoteBuilder get _$this { - if (_$v != null) { - _note = _$v.note; - _pitch = _$v.pitch; - _$v = null; - } - return this; - } - - @override - void replace(PitchNote other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$PitchNote; - } - - @override - void update(void Function(PitchNoteBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$PitchNote build() { - final _$result = _$v ?? new _$PitchNote._(note: note, pitch: pitch); - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/lib/instrument_checker.dart b/lib/instrument_checker.dart new file mode 100644 index 00000000..c8a8487b --- /dev/null +++ b/lib/instrument_checker.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; +import 'dart:io'; + +void main() { + File('database/db.json') + .readAsString() + .then((fileContents) => json.decode(fileContents)) + .then((jsonData) { + final dir = Directory('storage/sounds'); + final collections = jsonData['__collections__']; + final instruments = {}; + dir + .listSync(recursive: true) + .whereType() + .toList() + .forEach((childDir) { + final id = childDir.path.split('/').last; + final instrument = {}; + final soundPaths = {}; + childDir + .listSync(recursive: true) + .whereType() + .toList() + .forEach((file) { + soundPaths[file.path.split('/').last.split('.').first] = + file.path.replaceAll('storage/', ''); + }); + final notes = soundPaths.keys.map((e) => int.parse(e)).toList()..sort(); + final maxNote = notes.last; + final minNote = notes.first; + var i = 0; + final baseNotes = {}; + for (var note = minNote; note <= maxNote; note++) { + if ((i + 1) < notes.length && note >= notes[i + 1]) { + i++; + } else if ((i + 1) < notes.length && note > (notes[i] + 2)) { + i++; + } + final int = notes[i].toInt(); + baseNotes[note.toString()] = int; + } + + instrument['id'] = id; + instrument['maxNote'] = maxNote; + instrument['minNote'] = minNote; + instrument['soundPaths'] = soundPaths; + instrument['baseNotes'] = baseNotes; + instrument['__collections__'] = {}; + instruments[id] = instrument; + }); + collections['instruments'] = instruments; + jsonData['__collections__'] = collections; + File('database/db.json').writeAsStringSync(json.encode(jsonData)); + }); +} diff --git a/lib/main.dart b/lib/main.dart index 66605749..7c2be5e4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,12 +4,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'authentication/authentication_bloc.dart'; +import 'authentication/authentication_event.dart'; import 'game/game_bloc.dart'; import 'game/game_widget.dart'; import 'game_config/game_config_bloc.dart'; import 'game_config/game_config_widget.dart'; import 'generated/l10n.dart'; -import 'home/home_bloc.dart'; import 'home/home_widget.dart'; import 'instrument/instruments_repository_impl.dart'; import 'instrument/instruments_widget.dart'; @@ -67,7 +67,8 @@ class App extends StatelessWidget { ), BlocProvider( create: (context) { - return AuthenticationBloc(userRepository); + return AuthenticationBloc(userRepository) + ..add(SignInAnonymouslyEvent()); }, ), BlocProvider( @@ -106,10 +107,7 @@ class App extends StatelessWidget { return SplashWidget(); }, Routes.home: (context) { - return BlocProvider( - create: (context) => - HomeBloc(userRepository, instrumentsRepository), - child: HomeWidget()); + return HomeWidget(); }, Routes.gameConfig: (context) { primaryColor = Theme.of(context).colorScheme.primary; diff --git a/lib/midi_processor.dart b/lib/midi_processor.dart index c1ff655e..216978c1 100644 --- a/lib/midi_processor.dart +++ b/lib/midi_processor.dart @@ -16,50 +16,38 @@ class MidiProcessor { return _instance; } - Map> _noteToSoundIdAndPitches = {}; Instrument _instrument; - /* - Limit the number of simultaneous sounds, because, SoundPool only have 1MB heap size (media/libmediaplayerservice/MediaPlayerService.cpp), if exceeded, sound cannot be played. - AudioFlinger could not create track, status: -12 - SoundPool: Error creating AudioTrack - (Error -12 out of memory) - */ - static const _maxStreams = 8; final _soundPlayer = SoundPlayer(); - final _activeSounds = {}; - - final StreamController _soundLoadedController = BehaviorSubject(); + final _soundLoadedController = BehaviorSubject(); Stream get soundLoadedStream => _soundLoadedController.stream; + final _soundPaths = {}; void onSelectInstrument(Instrument instrument) { if (_instrument != instrument) { - dispose(); - _soundPlayer.init(2, _maxStreams); + _soundPaths.clear(); + _soundPlayer.release(); + _soundLoadedController.add(false); _instrument = instrument; - Future.wait(instrument.soundFiles.values - .map((e) => FirebaseCacheManager().getSingleFile(e))) - .then((files) => { - Future.wait(files.map((file) => _soundPlayer.load(file.path))) - .then((soundIds) => { - _noteToSoundIdAndPitches = _instrument.soundNotes - .map((note, pitchNote) => MapEntry( - note, - Pair( - soundIds[_instrument.soundFiles.keys - .toList() - .indexOf(pitchNote.note)], - pitchNote.pitch))) - .asMap(), - if (soundIds.length == _instrument.soundFiles.length) - {_soundLoadedController.add(true)} - }) - }); + Future.wait(instrument.soundPaths + .asMap() + .map((note, path) => MapEntry(note, getFile(note, path))) + .values + .toList()) + .then((_) async { + await _soundPlayer.load(_soundPaths, _instrument.baseNotes.toMap()); + _soundLoadedController.add(true); + }); } } + Future getFile(int note, String path) async { + final file = await FirebaseCacheManager().getSingleFile(path); + _soundPaths[note] = file.path; + } + Future playNote(int note) async { print(note.toString()); var pitchNote = note.toInt(); @@ -69,28 +57,6 @@ class MidiProcessor { while (pitchNote < _instrument.minNote) { pitchNote += 12; } - final soundIdAndPitch = _noteToSoundIdAndPitches[pitchNote]; - if (soundIdAndPitch != null) { - _activeSounds.add(await _soundPlayer.play(soundIdAndPitch.first, - rate: soundIdAndPitch.second)); - if (_activeSounds.length == _maxStreams) { - final firstSound = _activeSounds.first; - await _soundPlayer.stop(firstSound); - _activeSounds.remove(firstSound); - } - } + await _soundPlayer.play(pitchNote); } - - void dispose() { - _soundPlayer?.release(); - _soundLoadedController.add(false); - _activeSounds.clear(); - } -} - -class Pair { - final A first; - final B second; - - const Pair(this.first, this.second); } diff --git a/lib/serializers.dart b/lib/serializers.dart index 25737af8..949834fa 100644 --- a/lib/serializers.dart +++ b/lib/serializers.dart @@ -6,7 +6,6 @@ import 'package:built_value/standard_json_plugin.dart'; import 'game/game_reward.dart'; import 'instrument/instrument.dart'; -import 'instrument/pitch_note.dart'; import 'songs/song.dart'; import 'user/user.dart'; @@ -17,7 +16,6 @@ part 'serializers.g.dart'; Instrument, Song, GameReward, - PitchNote, User, ]) final Serializers serializers = (_$serializers.toBuilder() diff --git a/lib/serializers.g.dart b/lib/serializers.g.dart index 76477ef1..9297484b 100644 --- a/lib/serializers.g.dart +++ b/lib/serializers.g.dart @@ -9,7 +9,6 @@ part of 'serializers.dart'; Serializers _$serializers = (new Serializers().toBuilder() ..add(GameReward.serializer) ..add(Instrument.serializer) - ..add(PitchNote.serializer) ..add(Song.serializer) ..add(User.serializer) ..addBuilderFactory( @@ -30,8 +29,8 @@ Serializers _$serializers = (new Serializers().toBuilder() () => new MapBuilder()) ..addBuilderFactory( const FullType( - BuiltMap, const [const FullType(int), const FullType(PitchNote)]), - () => new MapBuilder())) + BuiltMap, const [const FullType(int), const FullType(int)]), + () => new MapBuilder())) .build(); // ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/lib/setting/setting_bloc.dart b/lib/setting/setting_bloc.dart index 9a60dbeb..614e5876 100644 --- a/lib/setting/setting_bloc.dart +++ b/lib/setting/setting_bloc.dart @@ -10,16 +10,16 @@ part 'setting_event.dart'; part 'setting_state.dart'; class SettingBloc extends Bloc { - SettingBloc() : super(SettingState(Locale('en', ''), ThemeMode.system)) { + SettingBloc() : super(SettingState(null, null)) { Preferences.getInstance().then((preferences) { - if (preferences.localeName != null) { - add(ChangeLocaleEvent( - Locale.fromSubtags(languageCode: preferences.localeName))); - } - if (preferences.themeName != null) { - add(ChangeThemeEvent(ThemeMode.values - .firstWhere((e) => e.toString() == preferences.themeName))); - } + final locale = (preferences.localeName != null) + ? Locale.fromSubtags(languageCode: preferences.localeName) + : null; + final themeMode = (preferences.themeName != null) + ? ThemeMode.values + .firstWhere((e) => e.toString() == preferences.themeName) + : ThemeMode.system; + add(LoadThemeAndLocaleEvent(themeMode, locale)); }); } @@ -37,6 +37,8 @@ class SettingBloc extends Bloc { preferences.themeName = event.theme.toString(); }); yield SettingState(state.locale, event.theme); + } else if (event is LoadThemeAndLocaleEvent) { + yield SettingState(event.locale, event.theme); } } } diff --git a/lib/setting/setting_event.dart b/lib/setting/setting_event.dart index 410a725b..8f3bc5c1 100644 --- a/lib/setting/setting_event.dart +++ b/lib/setting/setting_event.dart @@ -21,3 +21,13 @@ class ChangeThemeEvent extends SettingEvent { @override List get props => [theme]; } + +class LoadThemeAndLocaleEvent extends SettingEvent { + final ThemeMode theme; + final Locale locale; + + LoadThemeAndLocaleEvent(this.theme, this.locale); + + @override + List get props => [theme, locale]; +} diff --git a/lib/song_checker.dart b/lib/song_checker.dart index 45bbbfeb..715e977c 100644 --- a/lib/song_checker.dart +++ b/lib/song_checker.dart @@ -14,34 +14,34 @@ void main() { .then((jsonData) { final dir = Directory('storage/songs'); final collections = jsonData['__collections__']; - final songsMap = {}; + final songs = {}; dir.listSync(recursive: true).whereType().toList().forEach((file) { - final key = file.uri.toString().split('/').last.replaceAll('.mid', ''); + final id = file.uri.toString().split('/').last.replaceAll('.mid', ''); final temp = file.uri.toString().split('/'); final genre = temp[temp.length - 2]; print( - '*************************** Checking $key ***************************'); - final artist = key.split('-').first; - final title = key.replaceAll('$artist-', '').replaceAll('_', ' '); + '*************************** Checking $id ***************************'); + final artist = id.split('-').first; + final title = id.replaceAll('$artist-', '').replaceAll('_', ' '); final artist1 = artist.replaceAll('_', ' '); final midiFile = MidiParser().parseMidiFromFile(File(file.path)); final events = midiFile.tracks[0]; final track = midiFile.tracks.length; - final value = {}; + final song = {}; if (track != 2) { print('WARNING trackCount $track'); } - value['bpm'] = 0; + song['bpm'] = 0; for (final midiEvent in events) { if (midiEvent is SetTempoEvent) { final tempo = 60000000 ~/ midiEvent.microsecondsPerBeat; print('Tempo changes to $tempo'); - if (value['bpm'] <= tempo) { - value['bpm'] = tempo; + if (song['bpm'] <= tempo) { + song['bpm'] = tempo; } } } - print('Select largest tempo ${value['bpm']}'); + print('Select largest tempo ${song['bpm']}'); final tileChunks = createTileChunks(midiFile); final groupByDurationToPrevious = Map.fromEntries(groupBy( tileChunks, (TileChunk tileChunk) => tileChunk.durationToPrevious) @@ -66,8 +66,9 @@ void main() { var unitDuration = 0; final durations = groupByDurationToPrevious.keys.iterator; var tick2Second = - tickToSecond(midiFile.header.ticksPerBeat, value['bpm'] as int); - final minimumSingleTileSeconds = 0.25; // 4 touches per second, slow enough to click continuously + tickToSecond(midiFile.header.ticksPerBeat, song['bpm'] as int); + final minimumSingleTileSeconds = + 0.25; // 4 touches per second, slow enough to click continuously while (singleTileSeconds < minimumSingleTileSeconds && durations.moveNext() && unitDuration < mostCountDurationToPrevious) { @@ -78,13 +79,14 @@ void main() { } if (singleTileSeconds < minimumSingleTileSeconds) { - print('WARNING $key, Still too fast $singleTileSeconds'); - final newBpm = - ((value['bpm'] as int) * (singleTileSeconds / minimumSingleTileSeconds)).toInt(); + print('WARNING $id, Still too fast $singleTileSeconds'); + final newBpm = ((song['bpm'] as int) * + (singleTileSeconds / minimumSingleTileSeconds)) + .toInt(); print('Reduce bpm to $newBpm'); - value['bpm'] = newBpm; + song['bpm'] = newBpm; tick2Second = - tickToSecond(midiFile.header.ticksPerBeat, value['bpm'] as int); + tickToSecond(midiFile.header.ticksPerBeat, song['bpm'] as int); } final speedDpsPerTick = UNIT_DURATION_HEIGHT / unitDuration; final speedDpsPerSecond = speedDpsPerTick / tick2Second; @@ -92,7 +94,7 @@ void main() { print('There are ${tiles.length} tiles'); final tileCount = tiles.length; if (tileCount < 50) { - print('WARNING Number tile to small $key, number tiles $tileCount'); + print('WARNING Number tile to small $id, number tiles $tileCount'); } final duration = (0.5 + ((0.0 - tiles.last.initialY) * 1000000) / speedDpsPerSecond) @@ -100,15 +102,15 @@ void main() { 60000000; print('Duration is $duration minutes'); if (duration > 10) { - print('WARNING Too long $key, $duration minutes'); + print('WARNING Too long $id, $duration minutes'); } - value['unitDuration'] = unitDuration; - value['tilesCount'] = [ + song['unitDuration'] = unitDuration; + song['tilesCount'] = [ createTiles(tileChunks, unitDuration, 2).length, createTiles(tileChunks, unitDuration, 3).length, createTiles(tileChunks, unitDuration, 4).length ]; - value['duration'] = [ + song['duration'] = [ (0.5 + ((0.0 - tiles.last.initialY) * 1000000) / (speedDpsPerSecond * 0.75)) @@ -120,15 +122,15 @@ void main() { (speedDpsPerSecond * 1.25)) .toInt() ]; - value['artist'] = artist1; - value['id'] = key; - value['tags'] = [genre]; - value['title'] = title; - value['url'] = file.uri.toString().replaceAll('storage/', ''); - value['__collections__'] = {}; - songsMap[key] = value; + song['id'] = id; + song['artist'] = artist1; + song['tags'] = [genre]; + song['title'] = title; + song['url'] = file.uri.toString().replaceAll('storage/', ''); + song['__collections__'] = {}; + songs[id] = song; }); - collections['songs'] = songsMap; + collections['songs'] = songs; jsonData['__collections__'] = collections; File('database/db.json').writeAsStringSync(json.encode(jsonData)); }); diff --git a/lib/sound_player.dart b/lib/sound_player.dart index 9eddb145..c3ac40ff 100644 --- a/lib/sound_player.dart +++ b/lib/sound_player.dart @@ -3,35 +3,19 @@ import 'package:flutter/services.dart'; class SoundPlayer { MethodChannel channel = MethodChannel('com.chaomao.hitnotes/sound_player'); - Future init(int streamType, int maxStreams) { - return channel.invokeMethod('init', { - 'streamType': streamType, - 'maxStreams': maxStreams, - }); + Future load(Map soundPaths, Map baseNotes) { + print('load'); + return channel.invokeMethod('load', + {'soundPaths': soundPaths, 'baseNotes': baseNotes}); } - Future load(String path, {int priority = 1}) { - return channel.invokeMethod('load', { - 'path': path, - 'priority': priority, - }); - } - - Future play(int soundId, {int repeat = 0, double rate = 1.0}) { - return channel.invokeMethod('play', { - 'soundId': soundId, - 'repeat': repeat, - 'rate': rate, - }); - } - - Future stop(int streamId) { - return channel.invokeMethod('stop', { - 'streamId': streamId, - }); + Future play(int note) { + print('play $note'); + return channel.invokeMethod('play', {'note': note}); } Future release() { + print('release'); return channel.invokeMethod('release'); } } diff --git a/lib/splash_widget.dart b/lib/splash_widget.dart index 7a7974bf..a148622c 100644 --- a/lib/splash_widget.dart +++ b/lib/splash_widget.dart @@ -2,14 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'authentication/authentication_bloc.dart'; -import 'authentication/authentication_event.dart'; import 'authentication/authentication_state.dart'; import 'routes.dart'; class SplashWidget extends StatelessWidget { @override Widget build(BuildContext context) { - BlocProvider.of(context)..add(SignInAnonymouslyEvent()); BlocProvider.of(context).listen((state) { if (state is Authenticated) { Navigator.pushNamedAndRemoveUntil( diff --git a/lib/user/user_bloc.dart b/lib/user/user_bloc.dart index cab58352..b3fe1db3 100644 --- a/lib/user/user_bloc.dart +++ b/lib/user/user_bloc.dart @@ -6,9 +6,11 @@ import 'package:meta/meta.dart'; import '../instrument/instrument.dart'; import '../instrument/instruments_repository.dart'; +import '../midi_processor.dart'; import 'user_repository.dart'; part 'user_event.dart'; + part 'user_state.dart'; class UserBloc extends Bloc { @@ -31,6 +33,15 @@ class UserBloc extends Bloc { UserEvent event, ) async* { if (event is UpdateUser) { + if (state is UserLoading || + (state is UserUpdated && + ((state as UserUpdated).user.user.instrumentId != + event.user.user.instrumentId))) { + final instrument = (await _instrumentsRepository.instruments()) + .firstWhere( + (instrument) => instrument.id == event.user.user.instrumentId); + MidiProcessor.getInstance().onSelectInstrument(instrument); + } yield UserUpdated(event.user, event.instruments); } else if (event is ChangeInstrument) { _userRepository.changeInstrument(event.instrumentId); diff --git a/lib/user/user_repository.dart b/lib/user/user_repository.dart index 5422d33c..ca46ab43 100644 --- a/lib/user/user_repository.dart +++ b/lib/user/user_repository.dart @@ -1,7 +1,7 @@ import 'user.dart'; abstract class UserRepository { - void changUser(); + void subscribeUser(); void changeInstrument(String instrumentId); diff --git a/lib/user/user_repository_impl.dart b/lib/user/user_repository_impl.dart index d7d3f8f6..f6bac943 100644 --- a/lib/user/user_repository_impl.dart +++ b/lib/user/user_repository_impl.dart @@ -21,7 +21,7 @@ class UserRepositoryImpl implements UserRepository { } @override - Future changUser() async { + Future subscribeUser() async { await _userSubscription?.cancel(); _userSubscription = FirebaseFirestore.instance .collection('users') diff --git a/lib/user/user_widget.dart b/lib/user/user_widget.dart index 14847a61..0d5dbf69 100644 --- a/lib/user/user_widget.dart +++ b/lib/user/user_widget.dart @@ -32,7 +32,7 @@ class UserWidget extends StatelessWidget { child: ListView( shrinkWrap: true, controller: scrollController, - children: [buildColumn(state, context)]))); + children: [buildUI(state, context)]))); } else { return Container(); } @@ -41,226 +41,236 @@ class UserWidget extends StatelessWidget { ); } - Column buildColumn(UserUpdated state, BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + Widget buildUI(UserUpdated state, BuildContext context) { + return SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + () { + if (!state.user.isAnonymous) { + return buildAnonymousUI(state, context); + } else { + return buildUserUI(context); + } + }(), + Card( + color: Colors.transparent, + elevation: 0, + child: buildUserStatisticUI(state, context)), + ], + ), + ); + } + + Table buildUserStatisticUI(UserUpdated state, BuildContext context) { + return Table( children: [ - () { - if (!state.user.isAnonymous) { - return Card( - color: Colors.transparent, - elevation: 0, - child: Container( - padding: EdgeInsets.all(8.0), - child: Row( - children: [ - ClipOval( - child: Image.network(state.user.photoUrl, width: 72), - ), - SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - state.user.name, - style: Theme.of(context).textTheme.headline5, - ), - SizedBox(height: 8), - Row( - children: [ - Icon( - Icons.today, - size: 16, - ), - SizedBox(width: 8), - Text( - S.of(context).txt_joined(DateFormat.yMMMd() - .format(state.user.creationTime)), - style: Theme.of(context).textTheme.subtitle1, - ), - ], - ), - Row( - children: [ - Image( - image: AssetImage( - 'assets/images/img_guitar.png'), - width: 16, - height: 16, - ), - SizedBox(width: 8), - Text(S.of(context).txt_using(Intl.message( - '', - /* FIXME Localization name of instrument should be taken from server, not from local text resources */ - name: state.user.user.instrumentId, - desc: '', - args: [], - ))), - ], - ), - ], - ) - ], - ))); - } else { - return Card( - color: Colors.transparent, - elevation: 0, - child: Container( - padding: EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - OutlinedButton( - onPressed: () { - BlocProvider.of(context) - ..add(SignInWithGoogleEvent()); - }, - child: Padding( - padding: const EdgeInsets.all(8), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image( - image: AssetImage( - 'assets/images/img_google.png')), - SizedBox(width: 8), - Text(S.of(context).txt_button_sign_in_google, - style: - Theme.of(context).textTheme.subtitle1) - ], - ), - ), - ), - SizedBox(height: 8), - OutlinedButton( - onPressed: () { - BlocProvider.of(context) - ..add(SignInWithFacebookEvent()); - }, - child: Padding( - padding: const EdgeInsets.all(8), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image( - image: AssetImage( - 'assets/images/img_facebook.png')), - SizedBox(width: 8), - Text( - S.of(context).txt_button_sign_in_facebook, - style: - Theme.of(context).textTheme.subtitle1) - ], - ), - ), - ), - ]))); - } - }(), - Card( + TableRow(children: [ + Card( color: Colors.transparent, elevation: 0, - child: Table( - children: [ - TableRow(children: [ - Card( - color: Colors.transparent, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - // if you need this - side: BorderSide( - color: Colors.grey.withOpacity(0.2), - width: 1, - ), - ), - child: Container( - //color: Colors.white, - //width: 200, - //height: 200, - child: Column( - children: [ - SizedBox(height: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + // if you need this + side: BorderSide( + color: Colors.grey.withOpacity(0.2), + width: 1, + ), + ), + child: Container( + //color: Colors.white, + //width: 200, + //height: 200, + child: Column( + children: [ + SizedBox(height: 8), + Image( + image: AssetImage('assets/images/img_star.png'), + ), + SizedBox(height: 8), + Text(state.user.user.stars.toString(), + style: Theme.of(context).textTheme.subtitle1), + SizedBox(height: 8), + ], + ), + ), + ), + Card( + color: Colors.transparent, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + // if you need this + side: BorderSide( + color: Colors.grey.withOpacity(0.2), + width: 1, + ), + ), + child: Container( + //color: Colors.white, + // width: 200, + //height: 200, + child: Column( + children: [ + SizedBox(height: 8), + Image( + image: AssetImage('assets/images/img_note.png'), + ), + SizedBox(height: 8), + Text(state.user.user.playedNotes.toString(), + style: Theme.of(context).textTheme.subtitle1), + SizedBox(height: 8), + ], + ), + ), + ), + Card( + color: Colors.transparent, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + // if you need this + side: BorderSide( + color: Colors.grey.withOpacity(0.2), + width: 1, + ), + ), + child: Container( + //color: Colors.white, + //width: 200, + //height: 200, + child: Column( + children: [ + SizedBox(height: 8), + Image( + image: AssetImage('assets/images/img_clock.png'), + ), + SizedBox(height: 8), + Text( + state.user.user.playedTime + .toString() + .substring(0, 4) + .toString(), + style: Theme.of(context).textTheme.subtitle1), + SizedBox(height: 8), + ], + ), + ), + ), + ]), + ], + ); + } + + Card buildUserUI(BuildContext context) { + return Card( + color: Colors.transparent, + elevation: 0, + child: Container( + padding: EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + OutlinedButton( + onPressed: () { + BlocProvider.of(context) + ..add(SignInWithGoogleEvent()); + }, + child: Padding( + padding: const EdgeInsets.all(8), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ Image( - image: AssetImage('assets/images/img_star.png'), - ), - SizedBox(height: 8), - Text(state.user.user.stars.toString(), - style: Theme.of(context).textTheme.subtitle1), - SizedBox(height: 8), + image: + AssetImage('assets/images/img_google.png')), + SizedBox(width: 8), + Text(S.of(context).txt_button_sign_in_google, + style: Theme.of(context).textTheme.subtitle1) ], ), ), ), - Card( - color: Colors.transparent, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - // if you need this - side: BorderSide( - color: Colors.grey.withOpacity(0.2), - width: 1, - ), - ), - child: Container( - //color: Colors.white, - // width: 200, - //height: 200, - child: Column( - children: [ - SizedBox(height: 8), + SizedBox(height: 8), + OutlinedButton( + onPressed: () { + BlocProvider.of(context) + ..add(SignInWithFacebookEvent()); + }, + child: Padding( + padding: const EdgeInsets.all(8), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: [ Image( - image: AssetImage('assets/images/img_note.png'), - ), - SizedBox(height: 8), - Text(state.user.user.playedNotes.toString(), - style: Theme.of(context).textTheme.subtitle1), - SizedBox(height: 8), + image: + AssetImage('assets/images/img_facebook.png')), + SizedBox(width: 8), + Text(S.of(context).txt_button_sign_in_facebook, + style: Theme.of(context).textTheme.subtitle1) ], ), ), ), - Card( - color: Colors.transparent, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - // if you need this - side: BorderSide( - color: Colors.grey.withOpacity(0.2), - width: 1, - ), + ]))); + } + + Card buildAnonymousUI(UserUpdated state, BuildContext context) { + return Card( + color: Colors.transparent, + elevation: 0, + child: Container( + padding: EdgeInsets.all(8.0), + child: Row( + children: [ + ClipOval( + child: Image.network(state.user.photoUrl, width: 72), + ), + SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + state.user.name, + style: Theme.of(context).textTheme.headline5, ), - child: Container( - //color: Colors.white, - //width: 200, - //height: 200, - child: Column( - children: [ - SizedBox(height: 8), - Image( - image: AssetImage('assets/images/img_clock.png'), - ), - SizedBox(height: 8), - Text( - state.user.user.playedTime - .toString() - .substring(0, 4) - .toString(), - style: Theme.of(context).textTheme.subtitle1), - SizedBox(height: 8), - ], - ), + SizedBox(height: 8), + Row( + children: [ + Icon( + Icons.today, + size: 16, + ), + SizedBox(width: 8), + Text( + S.of(context).txt_joined(DateFormat.yMMMd() + .format(state.user.creationTime)), + style: Theme.of(context).textTheme.subtitle1, + ), + ], ), - ), - ]), + Row( + children: [ + Image( + image: AssetImage('assets/images/img_guitar.png'), + width: 16, + height: 16, + ), + SizedBox(width: 8), + Text(S.of(context).txt_using(Intl.message( + '', + /* FIXME Localization name of instrument should be taken from server, not from local text resources */ + name: state.user.user.instrumentId, + desc: '', + args: [], + ))), + ], + ), + ], + ) ], - )), - ], - ); + ))); } } diff --git a/pubspec.lock b/pubspec.lock index 7c00eb5f..0c5d7b5a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -273,7 +273,7 @@ packages: name: equatable url: "https://pub.dartlang.org" source: hosted - version: "1.2.5" + version: "1.2.6" ffi: dependency: transitive description: @@ -371,7 +371,7 @@ packages: name: flame url: "https://pub.dartlang.org" source: hosted - version: "0.29.0" + version: "0.29.2" flare_dart: dependency: transitive description: @@ -397,7 +397,7 @@ packages: name: flutter_bloc url: "https://pub.dartlang.org" source: hosted - version: "6.1.1" + version: "6.1.2" flutter_cache_manager: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 56d9ae16..03868fe9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,13 +8,13 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - flutter_bloc: ^6.0.6 - equatable: ^1.2.5 + flutter_bloc: ^6.1.2 + equatable: ^1.2.6 cloud_firestore: ^0.16.0 firebase_auth: ^0.20.0+1 firebase_storage: ^7.0.0 cloud_functions: ^0.9.0 - flame: 0.29.0 + flame: 0.29.2 dart_midi: ^1.0.1 cupertino_icons: ^1.0.0 built_value: ^7.1.0 diff --git a/resources/.gitignore b/resources/.gitignore index 71e41c9c..5b3f254b 100644 --- a/resources/.gitignore +++ b/resources/.gitignore @@ -1,3 +1,4 @@ +/venv /.idea/* !/.idea/codeStyles/ !/.idea/runConfigurations/ diff --git a/resources/gen_ios-images.py b/resources/gen_ios-images.py new file mode 100644 index 00000000..d39dd91c --- /dev/null +++ b/resources/gen_ios-images.py @@ -0,0 +1,26 @@ +import os +import subprocess + +multipliers = { + 20: [1, 2, 3], + 29: [1, 2, 3], + 40: [1, 2, 3], + 60: [2, 3], + 76: [1, 2], + 83.5: [2], + 1024: [1] +} +inkscape_default_dpi = 96 + +svg_default_folder = 'ios-images' +root = '../ios/Runner/Assets.xcassets/AppIcon.appiconset' + +for size, scales in multipliers.items(): + for scale in scales: + png_file_path = os.path.join(root, f"Icon-App-{size}x{size}@{scale}x" + '.png') + call_params = ["inkscape", + "--vacuum-defs", + "--export-dpi=%s" % int((size * scale) * 2), + "--export-filename=%s" % png_file_path, + os.path.join(svg_default_folder, 'ic_launcher.svg')] + subprocess.check_call(call_params, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) diff --git a/resources/gen_ios-launch-images.py b/resources/gen_ios-launch-images.py new file mode 100644 index 00000000..53e1d795 --- /dev/null +++ b/resources/gen_ios-launch-images.py @@ -0,0 +1,29 @@ +import os +import subprocess + +multipliers = [ + 1, + 2, + 3, +] +inkscape_default_dpi = 96 + +svg_default_folder = 'ios-launch-images' +root = '../ios/Runner/Assets.xcassets/LaunchImage.imageset' + +file_paths = [] +file_names = os.listdir(svg_default_folder) +for svg_file_name in file_names: + file_paths.append(os.path.join(svg_default_folder, svg_file_name)) + +for scale in multipliers: + for file_path in file_paths: + png_file_path = os.path.join(root, f"LaunchImage@{scale}x" + '.png') + if scale == 1: + png_file_path = os.path.join(root, f"LaunchImage" + '.png') + call_params = ["inkscape", + "--vacuum-defs", + "--export-dpi=%s" % int(scale * inkscape_default_dpi), + "--export-filename=%s" % png_file_path, + file_path] + subprocess.check_call(call_params, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) diff --git a/resources/ios-images/ic_launcher.svg b/resources/ios-images/ic_launcher.svg new file mode 100644 index 00000000..66567ffc --- /dev/null +++ b/resources/ios-images/ic_launcher.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/ios-launch-images/LaunchImage.svg b/resources/ios-launch-images/LaunchImage.svg new file mode 100644 index 00000000..f2dfaa2e --- /dev/null +++ b/resources/ios-launch-images/LaunchImage.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/storage/sounds/acoustic-guitar/31.mp3 b/storage/sounds/acoustic_guitar/31.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/31.mp3 rename to storage/sounds/acoustic_guitar/31.mp3 diff --git a/storage/sounds/acoustic-guitar/33.mp3 b/storage/sounds/acoustic_guitar/33.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/33.mp3 rename to storage/sounds/acoustic_guitar/33.mp3 diff --git a/storage/sounds/acoustic-guitar/36.mp3 b/storage/sounds/acoustic_guitar/36.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/36.mp3 rename to storage/sounds/acoustic_guitar/36.mp3 diff --git a/storage/sounds/acoustic-guitar/39.mp3 b/storage/sounds/acoustic_guitar/39.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/39.mp3 rename to storage/sounds/acoustic_guitar/39.mp3 diff --git a/storage/sounds/acoustic-guitar/43.mp3 b/storage/sounds/acoustic_guitar/43.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/43.mp3 rename to storage/sounds/acoustic_guitar/43.mp3 diff --git a/storage/sounds/acoustic-guitar/45.mp3 b/storage/sounds/acoustic_guitar/45.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/45.mp3 rename to storage/sounds/acoustic_guitar/45.mp3 diff --git a/storage/sounds/acoustic-guitar/48.mp3 b/storage/sounds/acoustic_guitar/48.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/48.mp3 rename to storage/sounds/acoustic_guitar/48.mp3 diff --git a/storage/sounds/acoustic-guitar/52.mp3 b/storage/sounds/acoustic_guitar/52.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/52.mp3 rename to storage/sounds/acoustic_guitar/52.mp3 diff --git a/storage/sounds/acoustic-guitar/54.mp3 b/storage/sounds/acoustic_guitar/54.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/54.mp3 rename to storage/sounds/acoustic_guitar/54.mp3 diff --git a/storage/sounds/acoustic-guitar/57.mp3 b/storage/sounds/acoustic_guitar/57.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/57.mp3 rename to storage/sounds/acoustic_guitar/57.mp3 diff --git a/storage/sounds/acoustic-guitar/60.mp3 b/storage/sounds/acoustic_guitar/60.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/60.mp3 rename to storage/sounds/acoustic_guitar/60.mp3 diff --git a/storage/sounds/acoustic-guitar/63.mp3 b/storage/sounds/acoustic_guitar/63.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/63.mp3 rename to storage/sounds/acoustic_guitar/63.mp3 diff --git a/storage/sounds/acoustic-guitar/66.mp3 b/storage/sounds/acoustic_guitar/66.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/66.mp3 rename to storage/sounds/acoustic_guitar/66.mp3 diff --git a/storage/sounds/acoustic-guitar/69.mp3 b/storage/sounds/acoustic_guitar/69.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/69.mp3 rename to storage/sounds/acoustic_guitar/69.mp3 diff --git a/storage/sounds/acoustic-guitar/72.mp3 b/storage/sounds/acoustic_guitar/72.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/72.mp3 rename to storage/sounds/acoustic_guitar/72.mp3 diff --git a/storage/sounds/acoustic-guitar/75.mp3 b/storage/sounds/acoustic_guitar/75.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/75.mp3 rename to storage/sounds/acoustic_guitar/75.mp3 diff --git a/storage/sounds/acoustic-guitar/78.mp3 b/storage/sounds/acoustic_guitar/78.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/78.mp3 rename to storage/sounds/acoustic_guitar/78.mp3 diff --git a/storage/sounds/acoustic-guitar/81.mp3 b/storage/sounds/acoustic_guitar/81.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/81.mp3 rename to storage/sounds/acoustic_guitar/81.mp3 diff --git a/storage/sounds/acoustic-guitar/84.mp3 b/storage/sounds/acoustic_guitar/84.mp3 similarity index 100% rename from storage/sounds/acoustic-guitar/84.mp3 rename to storage/sounds/acoustic_guitar/84.mp3 diff --git a/storage/sounds/electric-guitar/40.mp3 b/storage/sounds/electric_guitar/40.mp3 similarity index 100% rename from storage/sounds/electric-guitar/40.mp3 rename to storage/sounds/electric_guitar/40.mp3 diff --git a/storage/sounds/electric-guitar/44.mp3 b/storage/sounds/electric_guitar/44.mp3 similarity index 100% rename from storage/sounds/electric-guitar/44.mp3 rename to storage/sounds/electric_guitar/44.mp3 diff --git a/storage/sounds/electric-guitar/48.mp3 b/storage/sounds/electric_guitar/48.mp3 similarity index 100% rename from storage/sounds/electric-guitar/48.mp3 rename to storage/sounds/electric_guitar/48.mp3 diff --git a/storage/sounds/electric-guitar/52.mp3 b/storage/sounds/electric_guitar/52.mp3 similarity index 100% rename from storage/sounds/electric-guitar/52.mp3 rename to storage/sounds/electric_guitar/52.mp3 diff --git a/storage/sounds/electric-guitar/56.mp3 b/storage/sounds/electric_guitar/56.mp3 similarity index 100% rename from storage/sounds/electric-guitar/56.mp3 rename to storage/sounds/electric_guitar/56.mp3 diff --git a/storage/sounds/electric-guitar/60.mp3 b/storage/sounds/electric_guitar/60.mp3 similarity index 100% rename from storage/sounds/electric-guitar/60.mp3 rename to storage/sounds/electric_guitar/60.mp3 diff --git a/storage/sounds/electric-guitar/65.mp3 b/storage/sounds/electric_guitar/65.mp3 similarity index 100% rename from storage/sounds/electric-guitar/65.mp3 rename to storage/sounds/electric_guitar/65.mp3 diff --git a/storage/sounds/electric-guitar/68.mp3 b/storage/sounds/electric_guitar/68.mp3 similarity index 100% rename from storage/sounds/electric-guitar/68.mp3 rename to storage/sounds/electric_guitar/68.mp3 diff --git a/storage/sounds/electric-guitar/72.mp3 b/storage/sounds/electric_guitar/72.mp3 similarity index 100% rename from storage/sounds/electric-guitar/72.mp3 rename to storage/sounds/electric_guitar/72.mp3 diff --git a/storage/sounds/electric-guitar/76.mp3 b/storage/sounds/electric_guitar/76.mp3 similarity index 100% rename from storage/sounds/electric-guitar/76.mp3 rename to storage/sounds/electric_guitar/76.mp3 diff --git a/storage/sounds/electric-guitar/80.mp3 b/storage/sounds/electric_guitar/80.mp3 similarity index 100% rename from storage/sounds/electric-guitar/80.mp3 rename to storage/sounds/electric_guitar/80.mp3 diff --git a/storage/sounds/electric-guitar/84.mp3 b/storage/sounds/electric_guitar/84.mp3 similarity index 100% rename from storage/sounds/electric-guitar/84.mp3 rename to storage/sounds/electric_guitar/84.mp3