Initial commit: InTono — app KMP per l'apprendimento musicale
App Kotlin Multiplatform (Android/iOS/Desktop) con Compose Multiplatform: controllo intonazione (YIN), pratica guidata, metronomo, ear training, sfide, scansione spartiti via AI, spartiti bundled e pentagramma con glifi tipografici, travature, battute e spaziatura proporzionale. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No files matched your search
@@ -0,0 +1,70 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.notemusicali"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.notemusicali"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
val keystorePath = System.getenv("INTONO_KEYSTORE_PATH")
|
||||
if (keystorePath != null) {
|
||||
storeFile = file(keystorePath)
|
||||
storePassword = System.getenv("INTONO_KEYSTORE_PASSWORD")
|
||||
keyAlias = System.getenv("INTONO_KEY_ALIAS")
|
||||
keyPassword = System.getenv("INTONO_KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
val keystorePath = System.getenv("INTONO_KEYSTORE_PATH")
|
||||
if (keystorePath != null) {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":shared"))
|
||||
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.ui)
|
||||
implementation(libs.androidx.material3)
|
||||
|
||||
debugImplementation(libs.androidx.ui.tooling)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
# ProGuard rules for InTono (NoteMusicali)
|
||||
|
||||
# --- Kotlin ---
|
||||
-keepattributes *Annotation*
|
||||
-keepattributes Signature
|
||||
-keepattributes InnerClasses
|
||||
-keepattributes EnclosingMethod
|
||||
-keep class kotlin.Metadata { *; }
|
||||
-dontwarn kotlin.**
|
||||
|
||||
# --- Kotlin Serialization ---
|
||||
-keepattributes RuntimeVisibleAnnotations
|
||||
-keep class kotlinx.serialization.** { *; }
|
||||
-keepclassmembers class * {
|
||||
@kotlinx.serialization.Serializable <fields>;
|
||||
}
|
||||
-keepclassmembers @kotlinx.serialization.Serializable class * {
|
||||
*** Companion;
|
||||
*** serializer(...);
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
-keepclasseswithmembers class * {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# --- Ktor ---
|
||||
-keep class io.ktor.** { *; }
|
||||
-dontwarn io.ktor.**
|
||||
-keep class io.ktor.client.engine.** { *; }
|
||||
-keepclassmembers class io.ktor.** { volatile <fields>; }
|
||||
|
||||
# --- Coroutines ---
|
||||
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
||||
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
||||
-keepclassmembers class kotlinx.coroutines.** { volatile <fields>; }
|
||||
-dontwarn kotlinx.coroutines.**
|
||||
|
||||
# --- Compose ---
|
||||
-keep class androidx.compose.** { *; }
|
||||
-dontwarn androidx.compose.**
|
||||
|
||||
# --- Multiplatform Settings ---
|
||||
-keep class com.russhwolf.settings.** { *; }
|
||||
|
||||
# --- App classes ---
|
||||
-keep class com.notemusicali.** { *; }
|
||||
|
||||
# --- CameraX ---
|
||||
-keep class androidx.camera.** { *; }
|
||||
-dontwarn androidx.camera.**
|
||||
|
||||
# --- Standard Android ---
|
||||
-keepclassmembers class * implements android.os.Parcelable {
|
||||
public static final ** CREATOR;
|
||||
}
|
||||
-keepclassmembers class * implements java.io.Serializable {
|
||||
static final long serialVersionUID;
|
||||
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||
!static !transient <fields>;
|
||||
private void writeObject(java.io.ObjectOutputStream);
|
||||
private void readObject(java.io.ObjectInputStream);
|
||||
java.lang.Object writeReplace();
|
||||
java.lang.Object readResolve();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.NoteMusicali">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.NoteMusicali">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.notemusicali
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.notemusicali.navigation.AppNavigation
|
||||
import com.notemusicali.scores.ScoreProviderContext
|
||||
import com.notemusicali.scan.AppSettings
|
||||
import com.notemusicali.ui.theme.NoteMusicaliTheme
|
||||
import com.notemusicali.util.CrashHandler
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { _ -> }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
CrashHandler.install()
|
||||
AppSettings.migrateIfNeeded()
|
||||
enableEdgeToEdge()
|
||||
ScoreProviderContext.init(this, getExternalFilesDir(null))
|
||||
|
||||
val permissionsToRequest = mutableListOf<String>()
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
permissionsToRequest.add(Manifest.permission.RECORD_AUDIO)
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
permissionsToRequest.add(Manifest.permission.CAMERA)
|
||||
}
|
||||
permissionsToRequest.forEach { requestPermissionLauncher.launch(it) }
|
||||
|
||||
setContent {
|
||||
NoteMusicaliTheme {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding(),
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
) {
|
||||
AppNavigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:type="radial"
|
||||
android:centerX="0.5"
|
||||
android:centerY="0.5"
|
||||
android:gradientRadius="60%p"
|
||||
android:startColor="#2D1B69"
|
||||
android:endColor="#0A0118" />
|
||||
</shape>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<!-- Subtle glow behind note -->
|
||||
<path
|
||||
android:fillColor="#33FFD700"
|
||||
android:pathData="M54,54 m-22,0 a22,22 0,1 1,44 0 a22,22 0,1 1,-44 0" />
|
||||
|
||||
<!-- Decorative ring -->
|
||||
<path
|
||||
android:strokeColor="#22FFD700"
|
||||
android:strokeWidth="0.5"
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M54,54 m-28,0 a28,28 0,1 1,56 0 a28,28 0,1 1,-56 0" />
|
||||
|
||||
<!-- Eighth note - gold -->
|
||||
<path
|
||||
android:fillColor="#FFD700"
|
||||
android:pathData="M52,34 L52,68 C51.5,67.2 50.5,66.6 49,66.4 C45.5,65.8 42,67.5 41.5,70.2 C41,72.9 43.5,75.2 47,75.8 C50.5,76.4 53.5,74.8 54,72.2 L54,72 L54,46 L66,42 L66,38 Z" />
|
||||
|
||||
<!-- Flag -->
|
||||
<path
|
||||
android:fillColor="#FFD700"
|
||||
android:pathData="M54,34 C58,36 62,40 60,46 L54,42 Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">InTono</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.NoteMusicali" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
</resources>
|
||||