Compare commits
	
		
			1 Commits
		
	
	
		
			master
			...
			view-songs
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d3d1f482a8 | 
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -13,9 +13,3 @@
 | 
			
		||||
.externalNativeBuild
 | 
			
		||||
.cxx
 | 
			
		||||
local.properties
 | 
			
		||||
/music_database
 | 
			
		||||
/music_database-shm
 | 
			
		||||
/music_database-wal
 | 
			
		||||
/note_database
 | 
			
		||||
/note_database-shm
 | 
			
		||||
/note_database-wal
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -6,4 +6,3 @@
 | 
			
		||||
# Datasource local storage ignored files
 | 
			
		||||
/dataSources/
 | 
			
		||||
/dataSources.local.xml
 | 
			
		||||
/AndroidProjectSystem.xml
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
NoteVault
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="AndroidProjectSystem">
 | 
			
		||||
    <option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
<component name="ProjectCodeStyleConfiguration">
 | 
			
		||||
  <code_scheme name="Project" version="173">
 | 
			
		||||
    <JetCodeStyleSettings>
 | 
			
		||||
      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
 | 
			
		||||
    </JetCodeStyleSettings>
 | 
			
		||||
    <codeStyleSettings language="kotlin">
 | 
			
		||||
      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
 | 
			
		||||
    </codeStyleSettings>
 | 
			
		||||
  </code_scheme>
 | 
			
		||||
</component>
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<component name="ProjectCodeStyleConfiguration">
 | 
			
		||||
  <state>
 | 
			
		||||
    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
 | 
			
		||||
    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
 | 
			
		||||
  </state>
 | 
			
		||||
</component>
 | 
			
		||||
@ -1,71 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
 | 
			
		||||
    <data-source source="LOCAL" name="music_database" uuid="95a3c2ec-2c29-4336-900a-3993de90ae66">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$USER_HOME$/.cache/JetBrains/IntelliJIdea2025.1/device-explorer/samsung SM-P610/_/data/data/com.stormtales.notevault/databases/music_database</jdbc-url>
 | 
			
		||||
      <jdbc-additional-properties>
 | 
			
		||||
        <property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
 | 
			
		||||
      </jdbc-additional-properties>
 | 
			
		||||
      <working-dir>$ProjectFileDir$</working-dir>
 | 
			
		||||
      <libraries>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
      </libraries>
 | 
			
		||||
    </data-source>
 | 
			
		||||
    <data-source source="LOCAL" name="note_database" uuid="b3770d7c-0a73-40c6-aab8-010effaa19b6">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$USER_HOME$/.cache/JetBrains/IntelliJIdea2025.1/device-explorer/samsung SM-P610/_/data/data/come.stormborntales.notevault/databases/note_database</jdbc-url>
 | 
			
		||||
      <jdbc-additional-properties>
 | 
			
		||||
        <property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
 | 
			
		||||
      </jdbc-additional-properties>
 | 
			
		||||
      <working-dir>$ProjectFileDir$</working-dir>
 | 
			
		||||
      <libraries>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
      </libraries>
 | 
			
		||||
    </data-source>
 | 
			
		||||
    <data-source source="LOCAL" name="note_database [2]" uuid="ad94cfd9-e485-4151-8bf4-a080c51fa27c">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/note_database</jdbc-url>
 | 
			
		||||
      <jdbc-additional-properties>
 | 
			
		||||
        <property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
 | 
			
		||||
      </jdbc-additional-properties>
 | 
			
		||||
      <working-dir>$ProjectFileDir$</working-dir>
 | 
			
		||||
      <libraries>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
        <library>
 | 
			
		||||
          <url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
 | 
			
		||||
        </library>
 | 
			
		||||
      </libraries>
 | 
			
		||||
    </data-source>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										13
									
								
								.idea/deploymentTargetDropDown.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,13 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="deploymentTargetDropDown">
 | 
			
		||||
    <value>
 | 
			
		||||
      <entry key="NoteVault">
 | 
			
		||||
        <State />
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry key="app">
 | 
			
		||||
        <State />
 | 
			
		||||
      </entry>
 | 
			
		||||
    </value>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -4,14 +4,6 @@
 | 
			
		||||
    <selectionStates>
 | 
			
		||||
      <SelectionState runConfigName="app">
 | 
			
		||||
        <option name="selectionMode" value="DROPDOWN" />
 | 
			
		||||
        <DropdownSelection timestamp="2025-05-03T08:34:29.354537334Z">
 | 
			
		||||
          <Target type="DEFAULT_BOOT">
 | 
			
		||||
            <handle>
 | 
			
		||||
              <DeviceId pluginId="PhysicalDevice" identifier="serial=R52N50NLGRT" />
 | 
			
		||||
            </handle>
 | 
			
		||||
          </Target>
 | 
			
		||||
        </DropdownSelection>
 | 
			
		||||
        <DialogSelection />
 | 
			
		||||
      </SelectionState>
 | 
			
		||||
    </selectionStates>
 | 
			
		||||
  </component>
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
    <option name="linkedExternalProjectsSettings">
 | 
			
		||||
      <GradleProjectSettings>
 | 
			
		||||
        <option name="externalProjectPath" value="$PROJECT_DIR$" />
 | 
			
		||||
        <option name="gradleJvm" value="21" />
 | 
			
		||||
        <option name="modules">
 | 
			
		||||
          <set>
 | 
			
		||||
            <option value="$PROJECT_DIR$" />
 | 
			
		||||
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
<component name="InspectionProjectProfileManager">
 | 
			
		||||
  <profile version="1.0">
 | 
			
		||||
    <option name="myName" value="Project Default" />
 | 
			
		||||
    <inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewDeviceShouldUseNewSpec" enabled="true" level="WEAK WARNING" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewParameterProviderOnFirstParameter" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
    <inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
 | 
			
		||||
      <option name="composableFile" value="true" />
 | 
			
		||||
    </inspection_tool>
 | 
			
		||||
  </profile>
 | 
			
		||||
</component>
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="KotlinJpsPluginSettings">
 | 
			
		||||
    <option name="version" value="2.0.0" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -3,5 +3,10 @@
 | 
			
		||||
  <component name="FrameworkDetectionExcludesConfiguration">
 | 
			
		||||
    <file type="web" url="file://$PROJECT_DIR$" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
 | 
			
		||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
 | 
			
		||||
    <output url="file://$PROJECT_DIR$/build/classes" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectType">
 | 
			
		||||
    <option name="id" value="Android" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="RunConfigurationProducerService">
 | 
			
		||||
    <option name="ignoredProducers">
 | 
			
		||||
      <set>
 | 
			
		||||
        <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
 | 
			
		||||
        <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
 | 
			
		||||
        <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
 | 
			
		||||
        <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
 | 
			
		||||
        <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
 | 
			
		||||
        <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
 | 
			
		||||
        <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
 | 
			
		||||
        <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
 | 
			
		||||
      </set>
 | 
			
		||||
    </option>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="VcsDirectoryMappings">
 | 
			
		||||
    <mapping directory="" vcs="Git" />
 | 
			
		||||
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,17 +1,15 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    alias(libs.plugins.android.application)
 | 
			
		||||
    alias(libs.plugins.kotlin.android)
 | 
			
		||||
    alias(libs.plugins.kotlin.compose)
 | 
			
		||||
    alias(libs.plugins.ksp) // NEU
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    namespace = "come.stormborntales.notevault"
 | 
			
		||||
    namespace = "core.notevault"
 | 
			
		||||
    compileSdk = 34
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId = "come.stormborntales.notevault"
 | 
			
		||||
        minSdk = 24
 | 
			
		||||
        applicationId = "core.notevault"
 | 
			
		||||
        minSdk = 26
 | 
			
		||||
        targetSdk = 34
 | 
			
		||||
        versionCode = 1
 | 
			
		||||
        versionName = "1.0"
 | 
			
		||||
@ -26,41 +24,35 @@ android {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility = JavaVersion.VERSION_11
 | 
			
		||||
        targetCompatibility = JavaVersion.VERSION_11
 | 
			
		||||
    }
 | 
			
		||||
    kotlinOptions {
 | 
			
		||||
        jvmTarget = "11"
 | 
			
		||||
        sourceCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
        targetCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
    }
 | 
			
		||||
    buildFeatures {
 | 
			
		||||
        compose = true
 | 
			
		||||
        viewBinding = true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
 | 
			
		||||
    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.ui.graphics)
 | 
			
		||||
    implementation(libs.androidx.ui.tooling.preview)
 | 
			
		||||
    implementation(libs.androidx.material3)
 | 
			
		||||
    implementation(libs.androidx.navigation.compose)
 | 
			
		||||
    implementation(libs.androidx.lifecycle.viewmodel.compose)
 | 
			
		||||
    testImplementation(libs.junit)
 | 
			
		||||
    androidTestImplementation(libs.androidx.junit)
 | 
			
		||||
    androidTestImplementation(libs.androidx.espresso.core)
 | 
			
		||||
    androidTestImplementation(platform(libs.androidx.compose.bom))
 | 
			
		||||
    androidTestImplementation(libs.androidx.ui.test.junit4)
 | 
			
		||||
    debugImplementation(libs.androidx.ui.tooling)
 | 
			
		||||
    debugImplementation(libs.androidx.ui.test.manifest)
 | 
			
		||||
    implementation(libs.androidx.foundation)
 | 
			
		||||
    implementation(libs.androidx.room.runtime)
 | 
			
		||||
    implementation(libs.androidx.room.ktx)
 | 
			
		||||
    implementation(libs.appcompat)
 | 
			
		||||
    implementation(libs.material)
 | 
			
		||||
    implementation(libs.constraintlayout)
 | 
			
		||||
    implementation(libs.lifecycle.livedata.ktx)
 | 
			
		||||
    implementation(libs.compose.runtime.livedata)
 | 
			
		||||
    implementation(libs.coil.compose)
 | 
			
		||||
    ksp(libs.androidx.room.compiler)
 | 
			
		||||
    implementation(libs.lifecycle.viewmodel.ktx)
 | 
			
		||||
    implementation(libs.navigation.fragment)
 | 
			
		||||
    implementation(libs.navigation.ui)
 | 
			
		||||
    implementation(libs.room.common)
 | 
			
		||||
    implementation("androidx.recyclerview:recyclerview:1.3.2")
 | 
			
		||||
    testImplementation(libs.junit)
 | 
			
		||||
    androidTestImplementation(libs.ext.junit)
 | 
			
		||||
    androidTestImplementation(libs.espresso.core)
 | 
			
		||||
 | 
			
		||||
    val room_version = "2.6.1" // Aktuelle Room-Version
 | 
			
		||||
 | 
			
		||||
    implementation("androidx.room:room-runtime:$room_version")
 | 
			
		||||
    annotationProcessor("androidx.room:room-compiler:$room_version") // Für Annotation Processing
 | 
			
		||||
 | 
			
		||||
    // Optional: Unterstützung für Kotlin Coroutines oder RxJava
 | 
			
		||||
    implementation("androidx.room:room-ktx:$room_version") // Für Kotlin-Extensions
 | 
			
		||||
    implementation("androidx.room:room-rxjava3:$room_version") // Für RxJava-Unterstützung
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault
 | 
			
		||||
 | 
			
		||||
import androidx.test.platform.app.InstrumentationRegistry
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
import org.junit.runner.RunWith
 | 
			
		||||
 | 
			
		||||
import org.junit.Assert.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instrumented test, which will execute on an Android device.
 | 
			
		||||
 *
 | 
			
		||||
 * See [testing documentation](http://d.android.com/tools/testing).
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(AndroidJUnit4::class)
 | 
			
		||||
class ExampleInstrumentedTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    fun useAppContext() {
 | 
			
		||||
        // Context of the app under test.
 | 
			
		||||
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
 | 
			
		||||
        assertEquals("come.stormborntales.notevault", appContext.packageName)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
package core.notevault;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import androidx.test.platform.app.InstrumentationRegistry;
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Instrumented test, which will execute on an Android device.
 | 
			
		||||
 *
 | 
			
		||||
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(AndroidJUnit4.class)
 | 
			
		||||
public class ExampleInstrumentedTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void useAppContext() {
 | 
			
		||||
        // Context of the app under test.
 | 
			
		||||
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 | 
			
		||||
        assertEquals("core.notevault", appContext.getPackageName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
          xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 | 
			
		||||
    <application
 | 
			
		||||
            android:allowBackup="true"
 | 
			
		||||
            android:dataExtractionRules="@xml/data_extraction_rules"
 | 
			
		||||
@ -16,14 +16,13 @@
 | 
			
		||||
                android:name=".MainActivity"
 | 
			
		||||
                android:exported="true"
 | 
			
		||||
                android:label="@string/app_name"
 | 
			
		||||
                android:theme="@style/Theme.NoteVault">
 | 
			
		||||
                android:theme="@style/Theme.NoteVault.NoActionBar">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.MAIN"/>
 | 
			
		||||
 | 
			
		||||
                <category android:name="android.intent.category.LAUNCHER"/>
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity android:name=".FullscreenImageViewerActivity" />
 | 
			
		||||
 | 
			
		||||
    </application>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 197 KiB  | 
@ -1,26 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault
 | 
			
		||||
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.activity.ComponentActivity
 | 
			
		||||
import androidx.activity.compose.setContent
 | 
			
		||||
import come.stormborntales.notevault.ui.screens.FullscreenImageViewer
 | 
			
		||||
import come.stormborntales.notevault.ui.theme.NoteVaultTheme
 | 
			
		||||
 | 
			
		||||
// FullscreenImageViewerActivity.kt
 | 
			
		||||
class FullscreenImageViewerActivity : ComponentActivity() {
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        val imageUris = intent.getParcelableArrayListExtra<Uri>("imageUris") ?: emptyList()
 | 
			
		||||
 | 
			
		||||
        setContent {
 | 
			
		||||
            NoteVaultTheme {
 | 
			
		||||
                FullscreenImageViewer(
 | 
			
		||||
                    images = imageUris,
 | 
			
		||||
                    onClose = { finish() }
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,253 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault
 | 
			
		||||
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.activity.ComponentActivity
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.compose.setContent
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.filled.AccountCircle
 | 
			
		||||
import androidx.compose.material.icons.filled.Menu
 | 
			
		||||
import androidx.compose.material3.DrawerValue
 | 
			
		||||
import androidx.compose.material3.DropdownMenu
 | 
			
		||||
import androidx.compose.material3.DropdownMenuItem
 | 
			
		||||
import androidx.compose.material3.ExperimentalMaterial3Api
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.IconButton
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.ModalDrawerSheet
 | 
			
		||||
import androidx.compose.material3.ModalNavigationDrawer
 | 
			
		||||
import androidx.compose.material3.NavigationDrawerItem
 | 
			
		||||
import androidx.compose.material3.NavigationDrawerItemDefaults
 | 
			
		||||
import androidx.compose.material3.Scaffold
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TextField
 | 
			
		||||
import androidx.compose.material3.TextFieldDefaults
 | 
			
		||||
import androidx.compose.material3.TopAppBar
 | 
			
		||||
import androidx.compose.material3.rememberDrawerState
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.lifecycle.viewmodel.compose.viewModel
 | 
			
		||||
import androidx.navigation.compose.NavHost
 | 
			
		||||
import androidx.navigation.compose.composable
 | 
			
		||||
import androidx.navigation.compose.currentBackStackEntryAsState
 | 
			
		||||
import androidx.navigation.compose.rememberNavController
 | 
			
		||||
import come.stormborntales.notevault.data.local.AppDatabase
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
import come.stormborntales.notevault.data.repository.NoteRepository
 | 
			
		||||
import come.stormborntales.notevault.ui.screens.AddNoteDialog
 | 
			
		||||
import come.stormborntales.notevault.ui.screens.MainScreen
 | 
			
		||||
import come.stormborntales.notevault.ui.screens.NotesScreen
 | 
			
		||||
import come.stormborntales.notevault.ui.screens.SettingsScreen
 | 
			
		||||
import come.stormborntales.notevault.ui.theme.NoteVaultTheme
 | 
			
		||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
 | 
			
		||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModelFactory
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MainActivity : ComponentActivity() {
 | 
			
		||||
    @OptIn(ExperimentalMaterial3Api::class)
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        val applicationContext = applicationContext
 | 
			
		||||
        val database = AppDatabase.getDatabase(applicationContext)
 | 
			
		||||
        val repository = NoteRepository(database.noteDao())
 | 
			
		||||
        val viewModelFactory = NoteViewModelFactory(repository)
 | 
			
		||||
 | 
			
		||||
        setContent {
 | 
			
		||||
            NoteVaultTheme {
 | 
			
		||||
                val navController = rememberNavController()
 | 
			
		||||
                val viewModel: NoteViewModel = viewModel(factory = viewModelFactory)
 | 
			
		||||
 | 
			
		||||
                var selectedUris by remember { mutableStateOf<List<Uri>>(emptyList()) }
 | 
			
		||||
                var showDialog by remember { mutableStateOf(false) }
 | 
			
		||||
                var noteToEdit by remember { mutableStateOf<NoteEntity?>(null) }
 | 
			
		||||
                val drawerState = rememberDrawerState(DrawerValue.Closed)
 | 
			
		||||
                val scope = rememberCoroutineScope()
 | 
			
		||||
 | 
			
		||||
                val imagePickerLauncher = rememberLauncherForActivityResult(
 | 
			
		||||
                    contract = ActivityResultContracts.OpenMultipleDocuments(),
 | 
			
		||||
                    onResult = { uris ->
 | 
			
		||||
                        if (uris.isNotEmpty()) {
 | 
			
		||||
                            selectedUris = uris
 | 
			
		||||
                            showDialog = true
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                val openDialog: (NoteEntity?) -> Unit = { note ->
 | 
			
		||||
                    Log.d("EditNote", "NoteEntity: ${note?.title}")
 | 
			
		||||
                    noteToEdit = note
 | 
			
		||||
                    showDialog = true
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                val navItems = listOf(
 | 
			
		||||
                    "Home" to "main",
 | 
			
		||||
                    "Notes" to "notes",
 | 
			
		||||
                    "Einstellungen" to "settings"
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                ModalNavigationDrawer(
 | 
			
		||||
                    drawerState = drawerState,
 | 
			
		||||
                    drawerContent = {
 | 
			
		||||
                        ModalDrawerSheet {
 | 
			
		||||
                            Text("Navigation", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
 | 
			
		||||
                            navItems.forEach { (label, route) ->
 | 
			
		||||
                                NavigationDrawerItem(
 | 
			
		||||
                                    label = { Text(label) },
 | 
			
		||||
                                    selected = false,
 | 
			
		||||
                                    onClick = {
 | 
			
		||||
                                        navController.navigate(route) {
 | 
			
		||||
                                            popUpTo(navController.graph.startDestinationId) { saveState = true }
 | 
			
		||||
                                            launchSingleTop = true
 | 
			
		||||
                                            restoreState = true
 | 
			
		||||
                                        }
 | 
			
		||||
                                        scope.launch { drawerState.close() }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ) {
 | 
			
		||||
                    Scaffold(
 | 
			
		||||
                        topBar = {
 | 
			
		||||
                            var searchQuery by remember { mutableStateOf("") }
 | 
			
		||||
                            var isMenuExpanded by remember { mutableStateOf(false) }
 | 
			
		||||
 | 
			
		||||
                            val navBackStackEntry by navController.currentBackStackEntryAsState()
 | 
			
		||||
                            val currentRoute = navBackStackEntry?.destination?.route
 | 
			
		||||
 | 
			
		||||
                            TopAppBar(
 | 
			
		||||
                                title = {
 | 
			
		||||
                                    if(currentRoute == "main") {
 | 
			
		||||
                                        TextField(
 | 
			
		||||
                                            value = searchQuery,
 | 
			
		||||
                                            onValueChange = {
 | 
			
		||||
                                                searchQuery = it
 | 
			
		||||
                                                viewModel.searchQuery.value = it
 | 
			
		||||
                                            },
 | 
			
		||||
                                            placeholder = { Text("Suche...") },
 | 
			
		||||
                                            singleLine = true,
 | 
			
		||||
                                            modifier = Modifier
 | 
			
		||||
                                                .fillMaxWidth()
 | 
			
		||||
                                                .padding(end = 48.dp), // Platz für Avatar
 | 
			
		||||
                                            textStyle = MaterialTheme.typography.bodyLarge,
 | 
			
		||||
                                            colors = TextFieldDefaults.textFieldColors(
 | 
			
		||||
                                                containerColor = Color.Transparent,
 | 
			
		||||
                                                unfocusedIndicatorColor = Color.Transparent,
 | 
			
		||||
                                                focusedIndicatorColor = Color.Transparent
 | 
			
		||||
                                            )
 | 
			
		||||
                                        )
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        Text("NoteVault")
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                navigationIcon = {
 | 
			
		||||
                                    IconButton(onClick = { scope.launch { drawerState.open() } }) {
 | 
			
		||||
                                        Icon(Icons.Default.Menu, contentDescription = "Menü öffnen")
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                actions = {
 | 
			
		||||
                                    Box {
 | 
			
		||||
                                        IconButton(onClick = { isMenuExpanded = true }) {
 | 
			
		||||
                                            Icon(
 | 
			
		||||
                                                imageVector = Icons.Default.AccountCircle, // Avatar-Icon
 | 
			
		||||
                                                contentDescription = "Benutzerprofil"
 | 
			
		||||
                                            )
 | 
			
		||||
                                        }
 | 
			
		||||
                                        DropdownMenu(
 | 
			
		||||
                                            expanded = isMenuExpanded,
 | 
			
		||||
                                            onDismissRequest = { isMenuExpanded = false }
 | 
			
		||||
                                        ) {
 | 
			
		||||
                                            DropdownMenuItem(
 | 
			
		||||
                                                text = { Text("Profil") },
 | 
			
		||||
                                                onClick = {
 | 
			
		||||
                                                    isMenuExpanded = false
 | 
			
		||||
                                                    // TODO: Navigiere ggf. zu Profilscreen
 | 
			
		||||
                                                }
 | 
			
		||||
                                            )
 | 
			
		||||
                                            DropdownMenuItem(
 | 
			
		||||
                                                text = { Text("Abmelden") },
 | 
			
		||||
                                                onClick = {
 | 
			
		||||
                                                    isMenuExpanded = false
 | 
			
		||||
                                                    // TODO: Logout-Logik
 | 
			
		||||
                                                }
 | 
			
		||||
                                            )
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    ) { innerPadding ->
 | 
			
		||||
                        NavHost(
 | 
			
		||||
                            navController = navController,
 | 
			
		||||
                            startDestination = "main",
 | 
			
		||||
                            modifier = Modifier.padding(innerPadding)
 | 
			
		||||
                        ) {
 | 
			
		||||
                            composable("main") {
 | 
			
		||||
                                MainScreen(
 | 
			
		||||
                                    viewModel = viewModel,
 | 
			
		||||
                                    onAddNoteClicked = {
 | 
			
		||||
                                        imagePickerLauncher.launch(arrayOf("image/*"))
 | 
			
		||||
                                    },
 | 
			
		||||
                                    onEditNote = openDialog
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                            composable("settings") {
 | 
			
		||||
                                SettingsScreen()
 | 
			
		||||
                            }
 | 
			
		||||
                            composable("notes") {
 | 
			
		||||
                                NotesScreen()
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (showDialog) {
 | 
			
		||||
                            val context = LocalContext.current
 | 
			
		||||
                            AddNoteDialog(
 | 
			
		||||
                                onDismiss = { showDialog = false },
 | 
			
		||||
                                onSave = { title, composer, year, genre, description ->
 | 
			
		||||
                                    if (noteToEdit == null) {
 | 
			
		||||
                                        viewModel.addNote(
 | 
			
		||||
                                            context = context,
 | 
			
		||||
                                            title = title,
 | 
			
		||||
                                            composer = composer,
 | 
			
		||||
                                            year = year,
 | 
			
		||||
                                            genre = genre,
 | 
			
		||||
                                            description = description,
 | 
			
		||||
                                            selectedUris = selectedUris,
 | 
			
		||||
                                            onDone = { showDialog = false }
 | 
			
		||||
                                        )
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        viewModel.updateNote(
 | 
			
		||||
                                            editedNote = noteToEdit!!,
 | 
			
		||||
                                            updatedTitle = title,
 | 
			
		||||
                                            updatedComposer = composer,
 | 
			
		||||
                                            updatedYear = year,
 | 
			
		||||
                                            updatedGenre = genre,
 | 
			
		||||
                                            updatedDescription = description,
 | 
			
		||||
                                            onDone = { showDialog = false }
 | 
			
		||||
                                        )
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                initialTitle = noteToEdit?.title ?: "",
 | 
			
		||||
                                initialComposer = noteToEdit?.composer,
 | 
			
		||||
                                initialYear = noteToEdit?.year,
 | 
			
		||||
                                initialGenre = noteToEdit?.genre,
 | 
			
		||||
                                initialDescription = noteToEdit?.description
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.local
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.room.Database
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import androidx.room.RoomDatabase
 | 
			
		||||
import androidx.room.TypeConverters
 | 
			
		||||
import come.stormborntales.notevault.data.local.dao.NoteDao
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteCollection
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
 | 
			
		||||
@Database(entities = [NoteEntity::class, NoteCollection::class], version = 1)
 | 
			
		||||
@TypeConverters(UriListConverter::class)
 | 
			
		||||
abstract class AppDatabase : RoomDatabase() {
 | 
			
		||||
    abstract fun noteDao(): NoteDao
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        @Volatile
 | 
			
		||||
        private var INSTANCE: AppDatabase? = null
 | 
			
		||||
 | 
			
		||||
        fun getDatabase(context: Context): AppDatabase {
 | 
			
		||||
            return INSTANCE ?: synchronized(this) {
 | 
			
		||||
                val instance = Room.databaseBuilder(
 | 
			
		||||
                    context.applicationContext,
 | 
			
		||||
                    AppDatabase::class.java,
 | 
			
		||||
                    "note_database"
 | 
			
		||||
                ).build()
 | 
			
		||||
                INSTANCE = instance
 | 
			
		||||
                Log.d("AppDatabase", "Datenbank erstellt: ${instance.openHelper.writableDatabase}")
 | 
			
		||||
                instance
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.local
 | 
			
		||||
 | 
			
		||||
import androidx.room.TypeConverter
 | 
			
		||||
 | 
			
		||||
class UriListConverter {
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    fun fromList(list: List<String>): String = list.joinToString(",")
 | 
			
		||||
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    fun toList(data: String): List<String> = if (data.isBlank()) emptyList() else data.split(",")
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.local.dao
 | 
			
		||||
 | 
			
		||||
import androidx.room.Dao
 | 
			
		||||
import androidx.room.Delete
 | 
			
		||||
import androidx.room.Insert
 | 
			
		||||
import androidx.room.OnConflictStrategy
 | 
			
		||||
import androidx.room.Query
 | 
			
		||||
import androidx.room.Update
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface NoteDao {
 | 
			
		||||
    @Query("SELECT * FROM notes")
 | 
			
		||||
    fun getAll(): Flow<List<NoteEntity>>
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    suspend fun insert(note: NoteEntity)
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    suspend fun delete(note: NoteEntity)
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    suspend fun update(note: NoteEntity)
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.local.entity
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
 | 
			
		||||
@Entity("note_collections")
 | 
			
		||||
data class NoteCollection(
 | 
			
		||||
    @PrimaryKey(autoGenerate = true) var id: Int = 0,
 | 
			
		||||
    var name: String,
 | 
			
		||||
    var parentId: Int? = null
 | 
			
		||||
)
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.local.entity
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.ForeignKey
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "notes",
 | 
			
		||||
    foreignKeys = [ForeignKey(
 | 
			
		||||
        entity = NoteCollection::class,
 | 
			
		||||
        parentColumns = ["id"],
 | 
			
		||||
        childColumns = ["collectionId"],
 | 
			
		||||
        onDelete = ForeignKey.CASCADE
 | 
			
		||||
    )])
 | 
			
		||||
data class NoteEntity(
 | 
			
		||||
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
 | 
			
		||||
    var title: String,
 | 
			
		||||
    val images: List<String>, // oder String + TypeConverter
 | 
			
		||||
    var composer: String?,
 | 
			
		||||
    var year: Int?,
 | 
			
		||||
    var genre: String?,
 | 
			
		||||
    var description: String?,
 | 
			
		||||
    val imagePreview: String,
 | 
			
		||||
    val collectionId: Int?
 | 
			
		||||
)
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.model
 | 
			
		||||
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
 | 
			
		||||
class NoteEntry(
 | 
			
		||||
    val title: String, val images: List<Uri>, val composer: String?, val year: Int?,
 | 
			
		||||
    val genre: String?, val description: String?
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.data.repository
 | 
			
		||||
 | 
			
		||||
import come.stormborntales.notevault.data.local.dao.NoteDao
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
class NoteRepository(private val dao: NoteDao) {
 | 
			
		||||
    val allNotes: Flow<List<NoteEntity>> = dao.getAll()
 | 
			
		||||
 | 
			
		||||
    suspend fun insert(note: NoteEntity) = dao.insert(note)
 | 
			
		||||
    suspend fun delete(note: NoteEntity) = dao.delete(note)
 | 
			
		||||
 | 
			
		||||
    suspend fun update(note: NoteEntity) = dao.update(note);
 | 
			
		||||
}
 | 
			
		||||
@ -1,126 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.screens
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.material3.*
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun AddNoteDialog(
 | 
			
		||||
    onDismiss: () -> Unit,
 | 
			
		||||
    onSave: (title: String, composer: String?, year: Int?, genre: String?, description: String?) -> Unit,
 | 
			
		||||
    initialTitle: String = "",
 | 
			
		||||
    initialComposer: String? = null,
 | 
			
		||||
    initialYear: Int? = null,
 | 
			
		||||
    initialGenre: String? = null,
 | 
			
		||||
    initialDescription: String? = null
 | 
			
		||||
) {
 | 
			
		||||
    var title by remember { mutableStateOf(initialTitle) }
 | 
			
		||||
    var composer by remember { mutableStateOf(initialComposer ?: "") }
 | 
			
		||||
    var yearText by remember { mutableStateOf(initialYear?.toString() ?: "") }
 | 
			
		||||
    var genre by remember { mutableStateOf(initialGenre ?: "") }
 | 
			
		||||
    var description by remember { mutableStateOf(initialDescription ?: "") }
 | 
			
		||||
    var showTitleError by remember { mutableStateOf(false) }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    AlertDialog(
 | 
			
		||||
        onDismissRequest = onDismiss,
 | 
			
		||||
        confirmButton = {
 | 
			
		||||
            TextButton(onClick = {
 | 
			
		||||
                if (title.isBlank()) {
 | 
			
		||||
                    showTitleError = true
 | 
			
		||||
                } else {
 | 
			
		||||
                    val year = yearText.toIntOrNull()
 | 
			
		||||
                    onSave(
 | 
			
		||||
                        title.trim(),
 | 
			
		||||
                        composer.takeIf { it.isNotBlank() },
 | 
			
		||||
                        year,
 | 
			
		||||
                        genre.takeIf { it.isNotBlank() },
 | 
			
		||||
                        description.takeIf { it.isNotBlank() }
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }) {
 | 
			
		||||
                Text("Speichern")
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        dismissButton = {
 | 
			
		||||
            TextButton(onClick = onDismiss) {
 | 
			
		||||
                Text("Abbrechen")
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        title = {
 | 
			
		||||
            Text("Notenblatt hinzufügen", style = MaterialTheme.typography.titleLarge)
 | 
			
		||||
        },
 | 
			
		||||
        text = {
 | 
			
		||||
            Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
 | 
			
		||||
                OutlinedTextField(
 | 
			
		||||
                    value = title,
 | 
			
		||||
                    onValueChange = {
 | 
			
		||||
                        title = it
 | 
			
		||||
                        if (it.isNotBlank()) showTitleError = false
 | 
			
		||||
                    },
 | 
			
		||||
                    label = { Text("Titel*") },
 | 
			
		||||
                    isError = showTitleError,
 | 
			
		||||
                    singleLine = true,
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .padding(vertical = 4.dp)
 | 
			
		||||
                )
 | 
			
		||||
                if (showTitleError) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        "Titel darf nicht leer sein",
 | 
			
		||||
                        color = MaterialTheme.colorScheme.error,
 | 
			
		||||
                        style = MaterialTheme.typography.bodySmall,
 | 
			
		||||
                        modifier = Modifier.padding(start = 16.dp, bottom = 4.dp)
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                OutlinedTextField(
 | 
			
		||||
                    value = composer,
 | 
			
		||||
                    onValueChange = { composer = it },
 | 
			
		||||
                    label = { Text("Komponist (optional)") },
 | 
			
		||||
                    singleLine = true,
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .padding(vertical = 4.dp)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                OutlinedTextField(
 | 
			
		||||
                    value = yearText,
 | 
			
		||||
                    onValueChange = { yearText = it.filter { c -> c.isDigit() } },
 | 
			
		||||
                    label = { Text("Erscheinungsjahr (optional)") },
 | 
			
		||||
                    singleLine = true,
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .padding(vertical = 4.dp)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                OutlinedTextField(
 | 
			
		||||
                    value = genre,
 | 
			
		||||
                    onValueChange = { genre = it },
 | 
			
		||||
                    label = { Text("Genre (optional)") },
 | 
			
		||||
                    singleLine = true,
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .padding(vertical = 4.dp)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                OutlinedTextField(
 | 
			
		||||
                    value = description,
 | 
			
		||||
                    onValueChange = { description = it },
 | 
			
		||||
                    label = { Text("Beschreibung (optional)") },
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxWidth()
 | 
			
		||||
                        .padding(vertical = 4.dp),
 | 
			
		||||
                    maxLines = 4
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.screens
 | 
			
		||||
import androidx.compose.foundation.Image
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.foundation.pager.HorizontalPager
 | 
			
		||||
import androidx.compose.foundation.pager.rememberPagerState
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.filled.ArrowBack
 | 
			
		||||
import androidx.compose.material3.*
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import androidx.compose.foundation.ExperimentalFoundationApi
 | 
			
		||||
import androidx.compose.material.icons.filled.Close
 | 
			
		||||
import androidx.compose.ui.layout.ContentScale
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalFoundationApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun FullscreenImageViewer(
 | 
			
		||||
    images: List<Uri>,
 | 
			
		||||
    onClose: () -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    val pagerState = rememberPagerState(pageCount = { images.size })
 | 
			
		||||
 | 
			
		||||
    Box(modifier = Modifier.fillMaxSize()) {
 | 
			
		||||
        HorizontalPager(state = pagerState) { page ->
 | 
			
		||||
            val context = LocalContext.current
 | 
			
		||||
            val imageBitmap = remember(images[page]) {
 | 
			
		||||
                loadImageBitmap(context, images[page].toString())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            imageBitmap?.let {
 | 
			
		||||
                Image(
 | 
			
		||||
                    bitmap = it,
 | 
			
		||||
                    contentDescription = "Notenbild",
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .fillMaxSize()
 | 
			
		||||
                        .background(Color.Black),
 | 
			
		||||
                    contentScale = ContentScale.Fit
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IconButton(
 | 
			
		||||
            onClick = onClose,
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .align(Alignment.TopStart)
 | 
			
		||||
                .padding(16.dp)
 | 
			
		||||
        ) {
 | 
			
		||||
            Icon(Icons.Default.Close, contentDescription = "Schließen", tint = Color.White)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,269 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.screens
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.BitmapFactory
 | 
			
		||||
import android.graphics.ImageDecoder
 | 
			
		||||
import android.media.Image
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.compose.foundation.Image
 | 
			
		||||
import androidx.compose.foundation.horizontalScroll
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.filled.Add
 | 
			
		||||
import androidx.compose.material3.*
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.runtime.livedata.observeAsState
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.clip
 | 
			
		||||
import androidx.compose.ui.graphics.ImageBitmap
 | 
			
		||||
import androidx.compose.ui.graphics.asImageBitmap
 | 
			
		||||
import androidx.compose.ui.platform.LocalConfiguration
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import come.stormborntales.notevault.FullscreenImageViewerActivity
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
import come.stormborntales.notevault.data.model.NoteEntry
 | 
			
		||||
import come.stormborntales.notevault.ui.viewmodel.NoteViewModel
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.lifecycle.viewmodel.compose.viewModel
 | 
			
		||||
import coil.compose.AsyncImage
 | 
			
		||||
 | 
			
		||||
fun loadImageBitmap(context: Context, uriString: String): ImageBitmap? {
 | 
			
		||||
    return try {
 | 
			
		||||
        val uri = uriString.toUri()
 | 
			
		||||
        val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
 | 
			
		||||
        val bitmap = BitmapFactory.decodeStream(inputStream)
 | 
			
		||||
        bitmap?.asImageBitmap()
 | 
			
		||||
    } catch (e: Exception) {
 | 
			
		||||
        e.printStackTrace()
 | 
			
		||||
        null
 | 
			
		||||
    }
 | 
			
		||||
}@Composable
 | 
			
		||||
fun NoteCard(note: NoteEntity, onDeleteNote: (NoteEntity) -> Unit, onEditNote: (NoteEntity) -> Unit) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
 | 
			
		||||
    val screenWidth = LocalConfiguration.current.screenWidthDp // Bildschirmbreite in dp
 | 
			
		||||
 | 
			
		||||
    // Dynamische Bildgröße basierend auf der Bildschirmbreite
 | 
			
		||||
    val imageSize = if (screenWidth < 400) 80.dp else 120.dp
 | 
			
		||||
 | 
			
		||||
    Card(
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .fillMaxWidth()
 | 
			
		||||
            .padding(vertical = 8.dp),
 | 
			
		||||
        shape = RoundedCornerShape(16.dp),
 | 
			
		||||
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
 | 
			
		||||
    ) {
 | 
			
		||||
        // Responsive Layout: Überprüfen, ob der Bildschirm schmaler als 360 dp ist
 | 
			
		||||
        if (screenWidth < 400) {
 | 
			
		||||
            // Wenn der Bildschirm schmal ist, arrangiere die Elemente vertikal
 | 
			
		||||
            Row(modifier = Modifier.padding(16.dp)) {
 | 
			
		||||
                AsyncImage(
 | 
			
		||||
                    model = note.imagePreview,
 | 
			
		||||
                    contentDescription = "Vorschaubild",
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .size(imageSize)
 | 
			
		||||
                        .clip(RoundedCornerShape(12.dp))
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                Column(modifier = Modifier.padding(16.dp)) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        text = note.title,
 | 
			
		||||
                        style = MaterialTheme.typography.titleMedium
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    note.composer?.let {
 | 
			
		||||
                        Text("von $it", style = MaterialTheme.typography.labelMedium)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Spacer(modifier = Modifier.height(4.dp))
 | 
			
		||||
 | 
			
		||||
                    note.year?.let {
 | 
			
		||||
                        Text("Jahr: $it", style = MaterialTheme.typography.bodySmall)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    note.genre?.let {
 | 
			
		||||
                        Text("Genre: $it", style = MaterialTheme.typography.bodySmall)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    note.description?.let {
 | 
			
		||||
                        Text("Beschreibung: $it", style = MaterialTheme.typography.bodySmall, maxLines = 2)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Spacer(modifier = Modifier.height(16.dp)) // Abstand zwischen Text und Buttons
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Buttons unter dem Text
 | 
			
		||||
            Row(
 | 
			
		||||
                horizontalArrangement = Arrangement.spacedBy(8.dp),
 | 
			
		||||
                modifier = Modifier.fillMaxWidth().padding(16.dp),
 | 
			
		||||
            ) {
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        val uris = ArrayList<Uri>()
 | 
			
		||||
                        note.images.forEach { uris.add(it.toUri()) }
 | 
			
		||||
 | 
			
		||||
                        val intent = Intent(context, FullscreenImageViewerActivity::class.java).apply {
 | 
			
		||||
                            putParcelableArrayListExtra("imageUris", ArrayList(uris))
 | 
			
		||||
                        }
 | 
			
		||||
                        context.startActivity(intent)
 | 
			
		||||
                    },
 | 
			
		||||
                    contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text("Anzeigen", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        onEditNote(note)
 | 
			
		||||
                    },
 | 
			
		||||
                    contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text("Bearbeiten", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        onDeleteNote(note)
 | 
			
		||||
                    },
 | 
			
		||||
                    colors = ButtonDefaults.outlinedButtonColors(
 | 
			
		||||
                        contentColor = MaterialTheme.colorScheme.error
 | 
			
		||||
                    ),
 | 
			
		||||
                    contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text("Löschen", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Wenn der Bildschirm breiter als 360 dp ist, arrangiere die Elemente nebeneinander
 | 
			
		||||
            Row(modifier = Modifier.padding(16.dp)) {
 | 
			
		||||
                // Linkes Vorschaubild
 | 
			
		||||
                AsyncImage(
 | 
			
		||||
                    model = note.imagePreview,
 | 
			
		||||
                    contentDescription = "Vorschaubild",
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .size(imageSize)
 | 
			
		||||
                        .clip(RoundedCornerShape(12.dp))
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                // Rechte Info-Spalte
 | 
			
		||||
                Column(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .weight(1f) // Damit die Spalte den verfügbaren Platz nutzt
 | 
			
		||||
                        .align(Alignment.CenterVertically)
 | 
			
		||||
                        .padding(start = 16.dp)
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        text = note.title,
 | 
			
		||||
                        style = MaterialTheme.typography.titleMedium
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    note.composer?.let {
 | 
			
		||||
                        Text("von $it", style = MaterialTheme.typography.labelMedium)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Spacer(modifier = Modifier.height(4.dp))
 | 
			
		||||
 | 
			
		||||
                    note.year?.let {
 | 
			
		||||
                        Text("Jahr: $it", style = MaterialTheme.typography.bodySmall)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    note.genre?.let {
 | 
			
		||||
                        Text("Genre: $it", style = MaterialTheme.typography.bodySmall)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    note.description?.let {
 | 
			
		||||
                        Text("Beschreibung: $it", style = MaterialTheme.typography.bodySmall, maxLines = 2)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Spacer(modifier = Modifier.height(8.dp))
 | 
			
		||||
 | 
			
		||||
                    // Buttons in einer Row anordnen
 | 
			
		||||
                    Row(
 | 
			
		||||
                        horizontalArrangement = Arrangement.spacedBy(8.dp),
 | 
			
		||||
                        modifier = Modifier.fillMaxWidth() // Stellt sicher, dass die Row den gesamten verfügbaren Platz einnimmt
 | 
			
		||||
                    ) {
 | 
			
		||||
                        OutlinedButton(
 | 
			
		||||
                            onClick = {
 | 
			
		||||
                                val uris = ArrayList<Uri>()
 | 
			
		||||
                                note.images.forEach { uris.add(it.toUri()) }
 | 
			
		||||
 | 
			
		||||
                                val intent = Intent(context, FullscreenImageViewerActivity::class.java).apply {
 | 
			
		||||
                                    putParcelableArrayListExtra("imageUris", ArrayList(uris))
 | 
			
		||||
                                }
 | 
			
		||||
                                context.startActivity(intent)
 | 
			
		||||
                            },
 | 
			
		||||
                            contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Text("Anzeigen", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        OutlinedButton(
 | 
			
		||||
                            onClick = {
 | 
			
		||||
                                onEditNote(note)
 | 
			
		||||
                            },
 | 
			
		||||
                            contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Text("Bearbeiten", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        OutlinedButton(
 | 
			
		||||
                            onClick = {
 | 
			
		||||
                                onDeleteNote(note)
 | 
			
		||||
                            },
 | 
			
		||||
                            colors = ButtonDefaults.outlinedButtonColors(
 | 
			
		||||
                                contentColor = MaterialTheme.colorScheme.error
 | 
			
		||||
                            ),
 | 
			
		||||
                            contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp)
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Text("Löschen", style = MaterialTheme.typography.labelLarge)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalMaterial3Api::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun MainScreen(
 | 
			
		||||
    onAddNoteClicked: () -> Unit, // Übergib hier deine Logik für den Import
 | 
			
		||||
    viewModel: NoteViewModel,
 | 
			
		||||
    onEditNote: (NoteEntity) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    val notes by viewModel.filteredNotes.collectAsState(initial = emptyList())
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        floatingActionButton = {
 | 
			
		||||
            FloatingActionButton(
 | 
			
		||||
                onClick = onAddNoteClicked
 | 
			
		||||
            ) {
 | 
			
		||||
                Icon(Icons.Default.Add, contentDescription = "Neue Noten hinzufügen")
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        floatingActionButtonPosition = FabPosition.End
 | 
			
		||||
    ) { innerPadding ->
 | 
			
		||||
        LazyColumn(
 | 
			
		||||
            contentPadding = innerPadding,
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .fillMaxSize()
 | 
			
		||||
                .padding(16.dp)
 | 
			
		||||
        ) {
 | 
			
		||||
            items(notes) { note ->
 | 
			
		||||
                NoteCard(note = note, onDeleteNote = { noteEntity ->
 | 
			
		||||
                    viewModel.deleteNote(noteEntity)
 | 
			
		||||
                }, onEditNote = onEditNote)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.screens
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.Spacer
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material3.Divider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.OutlinedButton
 | 
			
		||||
import androidx.compose.material3.Switch
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun NotesScreen() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,79 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.screens
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.Spacer
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material3.Divider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.OutlinedButton
 | 
			
		||||
import androidx.compose.material3.Switch
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun SettingsScreen() {
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .fillMaxSize()
 | 
			
		||||
            .padding(16.dp)
 | 
			
		||||
    ) {
 | 
			
		||||
        Text(
 | 
			
		||||
            text = "Einstellungen",
 | 
			
		||||
            style = MaterialTheme.typography.headlineMedium,
 | 
			
		||||
            modifier = Modifier.padding(bottom = 16.dp)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Divider()
 | 
			
		||||
 | 
			
		||||
        Spacer(modifier = Modifier.height(16.dp))
 | 
			
		||||
 | 
			
		||||
        // Beispielhafte Einstellung
 | 
			
		||||
        Row(
 | 
			
		||||
            verticalAlignment = Alignment.CenterVertically,
 | 
			
		||||
            modifier = Modifier.fillMaxWidth()
 | 
			
		||||
        ) {
 | 
			
		||||
            Text(
 | 
			
		||||
                text = "Dark Mode",
 | 
			
		||||
                modifier = Modifier.weight(1f),
 | 
			
		||||
                style = MaterialTheme.typography.bodyLarge
 | 
			
		||||
            )
 | 
			
		||||
            Switch(
 | 
			
		||||
                checked = false,
 | 
			
		||||
                onCheckedChange = { /* TODO: Dark Mode aktivieren */ }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Spacer(modifier = Modifier.height(16.dp))
 | 
			
		||||
 | 
			
		||||
        Row(
 | 
			
		||||
            verticalAlignment = Alignment.CenterVertically,
 | 
			
		||||
            modifier = Modifier.fillMaxWidth()
 | 
			
		||||
        ) {
 | 
			
		||||
            Text(
 | 
			
		||||
                text = "Benachrichtigungen",
 | 
			
		||||
                modifier = Modifier.weight(1f),
 | 
			
		||||
                style = MaterialTheme.typography.bodyLarge
 | 
			
		||||
            )
 | 
			
		||||
            Switch(
 | 
			
		||||
                checked = true,
 | 
			
		||||
                onCheckedChange = { /* TODO: Benachrichtigungseinstellungen */ }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Spacer(modifier = Modifier.height(32.dp))
 | 
			
		||||
 | 
			
		||||
        OutlinedButton(
 | 
			
		||||
            onClick = { /* TODO: Impressum anzeigen */ },
 | 
			
		||||
            modifier = Modifier.fillMaxWidth()
 | 
			
		||||
        ) {
 | 
			
		||||
            Text("Impressum")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.theme
 | 
			
		||||
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
 | 
			
		||||
val Purple80 = Color(0xFFD0BCFF)
 | 
			
		||||
val PurpleGrey80 = Color(0xFFCCC2DC)
 | 
			
		||||
val Pink80 = Color(0xFFEFB8C8)
 | 
			
		||||
 | 
			
		||||
val Purple40 = Color(0xFF6650a4)
 | 
			
		||||
val PurpleGrey40 = Color(0xFF625b71)
 | 
			
		||||
val Pink40 = Color(0xFF7D5260)
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.theme
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import androidx.compose.foundation.isSystemInDarkTheme
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.darkColorScheme
 | 
			
		||||
import androidx.compose.material3.dynamicDarkColorScheme
 | 
			
		||||
import androidx.compose.material3.dynamicLightColorScheme
 | 
			
		||||
import androidx.compose.material3.lightColorScheme
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
 | 
			
		||||
private val DarkColorScheme = darkColorScheme(
 | 
			
		||||
    primary = Purple80,
 | 
			
		||||
    secondary = PurpleGrey80,
 | 
			
		||||
    tertiary = Pink80
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
private val LightColorScheme = lightColorScheme(
 | 
			
		||||
    primary = Purple40,
 | 
			
		||||
    secondary = PurpleGrey40,
 | 
			
		||||
    tertiary = Pink40
 | 
			
		||||
 | 
			
		||||
    /* Other default colors to override
 | 
			
		||||
    background = Color(0xFFFFFBFE),
 | 
			
		||||
    surface = Color(0xFFFFFBFE),
 | 
			
		||||
    onPrimary = Color.White,
 | 
			
		||||
    onSecondary = Color.White,
 | 
			
		||||
    onTertiary = Color.White,
 | 
			
		||||
    onBackground = Color(0xFF1C1B1F),
 | 
			
		||||
    onSurface = Color(0xFF1C1B1F),
 | 
			
		||||
    */
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun NoteVaultTheme(
 | 
			
		||||
    darkTheme: Boolean = isSystemInDarkTheme(),
 | 
			
		||||
    // Dynamic color is available on Android 12+
 | 
			
		||||
    dynamicColor: Boolean = true,
 | 
			
		||||
    content: @Composable () -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    val colorScheme = when {
 | 
			
		||||
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
 | 
			
		||||
            val context = LocalContext.current
 | 
			
		||||
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        darkTheme -> DarkColorScheme
 | 
			
		||||
        else -> LightColorScheme
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MaterialTheme(
 | 
			
		||||
        colorScheme = colorScheme,
 | 
			
		||||
        typography = Typography,
 | 
			
		||||
        content = content
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.theme
 | 
			
		||||
 | 
			
		||||
import androidx.compose.material3.Typography
 | 
			
		||||
import androidx.compose.ui.text.TextStyle
 | 
			
		||||
import androidx.compose.ui.text.font.FontFamily
 | 
			
		||||
import androidx.compose.ui.text.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
 | 
			
		||||
// Set of Material typography styles to start with
 | 
			
		||||
val Typography = Typography(
 | 
			
		||||
    bodyLarge = TextStyle(
 | 
			
		||||
        fontFamily = FontFamily.Default,
 | 
			
		||||
        fontWeight = FontWeight.Normal,
 | 
			
		||||
        fontSize = 16.sp,
 | 
			
		||||
        lineHeight = 24.sp,
 | 
			
		||||
        letterSpacing = 0.5.sp
 | 
			
		||||
    )
 | 
			
		||||
    /* Other default text styles to override
 | 
			
		||||
    titleLarge = TextStyle(
 | 
			
		||||
        fontFamily = FontFamily.Default,
 | 
			
		||||
        fontWeight = FontWeight.Normal,
 | 
			
		||||
        fontSize = 22.sp,
 | 
			
		||||
        lineHeight = 28.sp,
 | 
			
		||||
        letterSpacing = 0.sp
 | 
			
		||||
    ),
 | 
			
		||||
    labelSmall = TextStyle(
 | 
			
		||||
        fontFamily = FontFamily.Default,
 | 
			
		||||
        fontWeight = FontWeight.Medium,
 | 
			
		||||
        fontSize = 11.sp,
 | 
			
		||||
        lineHeight = 16.sp,
 | 
			
		||||
        letterSpacing = 0.5.sp
 | 
			
		||||
    )
 | 
			
		||||
    */
 | 
			
		||||
)
 | 
			
		||||
@ -1,134 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.viewmodel
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.Bitmap
 | 
			
		||||
import android.graphics.BitmapFactory
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.webkit.MimeTypeMap
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.asLiveData
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import come.stormborntales.notevault.data.local.entity.NoteEntity
 | 
			
		||||
import come.stormborntales.notevault.data.repository.NoteRepository
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import java.io.File
 | 
			
		||||
import androidx.core.graphics.scale
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kotlinx.coroutines.flow.MutableStateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.SharingStarted
 | 
			
		||||
import kotlinx.coroutines.flow.StateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.combine
 | 
			
		||||
import kotlinx.coroutines.flow.stateIn
 | 
			
		||||
 | 
			
		||||
class NoteViewModel(
 | 
			
		||||
    private val repository: NoteRepository,
 | 
			
		||||
) : ViewModel() {
 | 
			
		||||
    // Sucheingabe als StateFlow
 | 
			
		||||
    val searchQuery = MutableStateFlow("")
 | 
			
		||||
 | 
			
		||||
    // Alle Notizen als Flow aus der Datenbank (NICHT blockierend!)
 | 
			
		||||
    private val allNotes: Flow<List<NoteEntity>> = repository.allNotes
 | 
			
		||||
 | 
			
		||||
    // Gefilterte Notizen basierend auf Sucheingabe
 | 
			
		||||
    val filteredNotes: StateFlow<List<NoteEntity>> = combine(searchQuery, allNotes) { query, notes ->
 | 
			
		||||
        if (query.isBlank()) {
 | 
			
		||||
            notes
 | 
			
		||||
        } else {
 | 
			
		||||
            notes.filter {
 | 
			
		||||
                it.title.contains(query, ignoreCase = true) ||
 | 
			
		||||
                        it.description?.contains(query, ignoreCase = true) == true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun createPreviewImage(context: Context, uri: Uri): File? {
 | 
			
		||||
       return try {
 | 
			
		||||
           val inputStream = context.contentResolver.openInputStream(uri)
 | 
			
		||||
           val originalBitmap = BitmapFactory.decodeStream(inputStream) ?: return null
 | 
			
		||||
 | 
			
		||||
           val previewBitmap = originalBitmap.scale(128, 128, false)
 | 
			
		||||
           val previewFile = File(context.filesDir, "preview_${System.currentTimeMillis()}.jpg")
 | 
			
		||||
           previewFile.outputStream().use { out ->
 | 
			
		||||
               previewBitmap.compress(Bitmap.CompressFormat.JPEG, 75, out)
 | 
			
		||||
           }
 | 
			
		||||
           previewFile
 | 
			
		||||
       } catch (e: Exception) {
 | 
			
		||||
           e.printStackTrace()
 | 
			
		||||
           null
 | 
			
		||||
       }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addNote(context: Context, title: String, composer: String?, year: Int?, genre: String?, description: String?, selectedUris: List<Uri>, onDone:() -> Unit) {
 | 
			
		||||
        viewModelScope.launch(Dispatchers.IO) {
 | 
			
		||||
            val copiedUris = selectedUris.mapNotNull { uri ->
 | 
			
		||||
                try {
 | 
			
		||||
                    val inputStream = context.contentResolver.openInputStream(uri)
 | 
			
		||||
                    val extension = MimeTypeMap.getSingleton()
 | 
			
		||||
                        .getExtensionFromMimeType(context.contentResolver.getType(uri)) ?: "jpg"
 | 
			
		||||
 | 
			
		||||
                    val outputFile = File(context.filesDir, "note_${System.currentTimeMillis()}.$extension")
 | 
			
		||||
                    inputStream?.use { input ->
 | 
			
		||||
                        outputFile.outputStream().use { output ->
 | 
			
		||||
                            input.copyTo(output)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Log.d("NoteViewModel", "NoteEntityFile" + outputFile.absolutePath)
 | 
			
		||||
                    Uri.fromFile(outputFile).toString() // speichern als String
 | 
			
		||||
                } catch (e: Exception) {
 | 
			
		||||
                    e.printStackTrace()
 | 
			
		||||
                    null
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (copiedUris.isNotEmpty()) {
 | 
			
		||||
                val preview_image_path = createPreviewImage(context, uri = selectedUris[0])
 | 
			
		||||
 | 
			
		||||
                val note = NoteEntity(
 | 
			
		||||
                    title = title,
 | 
			
		||||
                    images = copiedUris, // muss als List<String> gespeichert sein
 | 
			
		||||
                    composer = composer,
 | 
			
		||||
                    year = year,
 | 
			
		||||
                    genre = genre,
 | 
			
		||||
                    description = description,
 | 
			
		||||
                    imagePreview = preview_image_path.toString(),
 | 
			
		||||
                    collectionId = null
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                repository.insert(note)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            onDone()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun deleteNote(note: NoteEntity) {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            repository.delete(note)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateNote(
 | 
			
		||||
        editedNote: NoteEntity,
 | 
			
		||||
        updatedTitle: String,
 | 
			
		||||
        updatedComposer: String?,
 | 
			
		||||
        updatedYear: Int?,
 | 
			
		||||
        updatedGenre: String?,
 | 
			
		||||
        updatedDescription: String?,
 | 
			
		||||
        onDone: () -> Unit
 | 
			
		||||
    ) {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            editedNote.title = updatedTitle
 | 
			
		||||
            editedNote.year = updatedYear;
 | 
			
		||||
            editedNote.composer = updatedComposer
 | 
			
		||||
            editedNote.genre = updatedGenre
 | 
			
		||||
            editedNote.description = updatedDescription
 | 
			
		||||
 | 
			
		||||
            repository.update(editedNote)
 | 
			
		||||
 | 
			
		||||
            onDone()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package come.stormborntales.notevault.ui.viewmodel
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider
 | 
			
		||||
import come.stormborntales.notevault.data.repository.NoteRepository
 | 
			
		||||
 | 
			
		||||
class NoteViewModelFactory(
 | 
			
		||||
    private val repository: NoteRepository
 | 
			
		||||
) : ViewModelProvider.Factory {
 | 
			
		||||
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
 | 
			
		||||
        if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
 | 
			
		||||
            @Suppress("UNCHECKED_CAST")
 | 
			
		||||
            return NoteViewModel(repository) as T
 | 
			
		||||
        }
 | 
			
		||||
        throw IllegalArgumentException("Unknown ViewModel class")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								app/src/main/java/core/notevault/MainActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,72 @@
 | 
			
		||||
package core.notevault;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar;
 | 
			
		||||
import com.google.android.material.navigation.NavigationView;
 | 
			
		||||
import androidx.navigation.NavController;
 | 
			
		||||
import androidx.navigation.Navigation;
 | 
			
		||||
import androidx.navigation.ui.AppBarConfiguration;
 | 
			
		||||
import androidx.navigation.ui.NavigationUI;
 | 
			
		||||
import androidx.drawerlayout.widget.DrawerLayout;
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.databinding.ActivityMainBinding;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
public class MainActivity extends AppCompatActivity implements MetaDataDialog.OnMetadataListener {
 | 
			
		||||
 | 
			
		||||
    private AppBarConfiguration mAppBarConfiguration;
 | 
			
		||||
    private ActivityMainBinding binding;
 | 
			
		||||
 | 
			
		||||
    private MusicDatabase musicDB;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        binding = ActivityMainBinding.inflate(getLayoutInflater());
 | 
			
		||||
        setContentView(binding.getRoot());
 | 
			
		||||
 | 
			
		||||
        setSupportActionBar(binding.appBarMain.toolbar);
 | 
			
		||||
        DrawerLayout drawer = binding.drawerLayout;
 | 
			
		||||
        NavigationView navigationView = binding.navView;
 | 
			
		||||
        // Passing each menu ID as a set of Ids because each
 | 
			
		||||
        // menu should be considered as top level destinations.
 | 
			
		||||
        mAppBarConfiguration = new AppBarConfiguration.Builder(
 | 
			
		||||
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
 | 
			
		||||
                .setOpenableLayout(drawer)
 | 
			
		||||
                .build();
 | 
			
		||||
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
 | 
			
		||||
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
 | 
			
		||||
        NavigationUI.setupWithNavController(navigationView, navController);
 | 
			
		||||
 | 
			
		||||
        musicDB = MusicDatabase.getDatabase(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
			
		||||
        // Inflate the menu; this adds items to the action bar if it is present.
 | 
			
		||||
        getMenuInflater().inflate(R.menu.main, menu);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onSupportNavigateUp() {
 | 
			
		||||
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
 | 
			
		||||
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
 | 
			
		||||
                || super.onSupportNavigateUp();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMetadataEntered(String title, String composer, int year, String genre) {
 | 
			
		||||
        MusicNote musicNote = new MusicNote(title, null, composer, year, genre);
 | 
			
		||||
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            musicDB.musicNoteDao().insert(musicNote);
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								app/src/main/java/core/notevault/data/MusicDatabase.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,26 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import androidx.room.Room;
 | 
			
		||||
import androidx.room.RoomDatabase;
 | 
			
		||||
import androidx.room.Database;
 | 
			
		||||
 | 
			
		||||
@Database(entities = {MusicNote.class}, version = 1, exportSchema = false)
 | 
			
		||||
public abstract class MusicDatabase extends RoomDatabase {
 | 
			
		||||
    public abstract MusicNoteDAO musicNoteDao();
 | 
			
		||||
 | 
			
		||||
    private static MusicDatabase INSTANCE;
 | 
			
		||||
 | 
			
		||||
    public static MusicDatabase getDatabase(final Context context) {
 | 
			
		||||
        if (INSTANCE == null) {
 | 
			
		||||
            synchronized (MusicDatabase.class) {
 | 
			
		||||
                if (INSTANCE == null) {
 | 
			
		||||
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
 | 
			
		||||
                                    MusicDatabase.class, "music_database")
 | 
			
		||||
                            .build();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return INSTANCE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								app/src/main/java/core/notevault/data/MusicNote.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,75 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity;
 | 
			
		||||
import androidx.room.PrimaryKey;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "music_notes")
 | 
			
		||||
public class MusicNote {
 | 
			
		||||
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private int id;
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String filePath;
 | 
			
		||||
    private String composer;
 | 
			
		||||
    private int year;
 | 
			
		||||
    private String genre;
 | 
			
		||||
 | 
			
		||||
    public MusicNote(String title, String filePath, String composer, int year, String genre) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.filePath = filePath;
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
        this.year = year;
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MusicNote() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setId(int id) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTitle(String title) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getFilePath() {
 | 
			
		||||
        return filePath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFilePath(String filePath) {
 | 
			
		||||
        this.filePath = filePath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getComposer() {
 | 
			
		||||
        return composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setComposer(String composer) {
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getGenre() {
 | 
			
		||||
        return genre;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setGenre(String genre) {
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getYear() {
 | 
			
		||||
        return year;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setYear(int year) {
 | 
			
		||||
        this.year = year;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								app/src/main/java/core/notevault/data/MusicNoteDAO.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,17 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Dao;
 | 
			
		||||
import androidx.room.Insert;
 | 
			
		||||
import androidx.room.Query;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
public interface MusicNoteDAO {
 | 
			
		||||
 | 
			
		||||
    @Insert
 | 
			
		||||
    void insert(MusicNote musicNote);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM music_notes")
 | 
			
		||||
    List<MusicNote> getAllNotes();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
package core.notevault.ui.gallery;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import core.notevault.databinding.FragmentGalleryBinding;
 | 
			
		||||
 | 
			
		||||
public class GalleryFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    private FragmentGalleryBinding binding;
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        GalleryViewModel galleryViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(GalleryViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentGalleryBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        final TextView textView = binding.textGallery;
 | 
			
		||||
        galleryViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
package core.notevault.ui.gallery;
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
 | 
			
		||||
public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<String> mText;
 | 
			
		||||
 | 
			
		||||
    public GalleryViewModel() {
 | 
			
		||||
        mText = new MutableLiveData<>();
 | 
			
		||||
        mText.setValue("This is gallery fragment");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<String> getText() {
 | 
			
		||||
        return mText;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.widget.ImageView;
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
 | 
			
		||||
public class FullScreenImageActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        setContentView(R.layout.activity_full_screen_image); // Erstelle eine Layout-Datei
 | 
			
		||||
 | 
			
		||||
        ImageView imageView = findViewById(R.id.fullscreen_image_view); // Angenommen, du hast ein ImageView
 | 
			
		||||
 | 
			
		||||
        // Die URI aus dem Intent erhalten
 | 
			
		||||
        Intent intent = getIntent();
 | 
			
		||||
        String imageUriString = intent.getStringExtra("imageUri");
 | 
			
		||||
        if (imageUriString != null) {
 | 
			
		||||
            Uri imageUri = Uri.parse(imageUriString);
 | 
			
		||||
            imageView.setImageURI(imageUri); // Setze die URI in das ImageView
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								app/src/main/java/core/notevault/ui/home/HomeFragment.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,113 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.provider.OpenableColumns;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.databinding.FragmentHomeBinding;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class HomeFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    private NoteSongAdapter noteSongAdapter;
 | 
			
		||||
 | 
			
		||||
    private static final int PICK_FILE_REQUEST_CODE = 1;
 | 
			
		||||
    private FragmentHomeBinding binding;
 | 
			
		||||
    private HomeViewModel homeViewModel;
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
         homeViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(HomeViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentHomeBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        FloatingActionButton importBtn = root.findViewById(R.id.importMusicNotesBtn);
 | 
			
		||||
        importBtn.setOnClickListener(v -> openFileChooser());
 | 
			
		||||
 | 
			
		||||
        RecyclerView recyclerView = root.findViewById(R.id.note_recycler_view);
 | 
			
		||||
        noteSongAdapter = new NoteSongAdapter();
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
 | 
			
		||||
        new LoadSongTitlesTask().execute();
 | 
			
		||||
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class LoadSongTitlesTask extends AsyncTask<Void, Void, List<MusicNote>> {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected List<MusicNote> doInBackground(Void... voids) {
 | 
			
		||||
            MusicDatabase db = MusicDatabase.getDatabase(getContext());
 | 
			
		||||
            MusicNoteDAO musicNoteDAO = db.musicNoteDao();
 | 
			
		||||
            return  musicNoteDAO.getAllNotes();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void onPostExecute(List<MusicNote> songTitles) {
 | 
			
		||||
            noteSongAdapter.updateSongTitles(songTitles); // Aktualisiere den Adapter mit den Titeln
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
 | 
			
		||||
        super.onActivityResult(requestCode, resultCode, data);
 | 
			
		||||
        if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == getActivity().RESULT_OK && data != null) {
 | 
			
		||||
            Uri uri = data.getData();
 | 
			
		||||
            if (uri != null) {
 | 
			
		||||
                handleFile(uri);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void handleFile(Uri uri) {
 | 
			
		||||
        // Hier kannst du die Logik zum Speichern oder Anzeigen der Datei implementieren
 | 
			
		||||
        MetaDataDialog metaDataDialog = new MetaDataDialog();
 | 
			
		||||
        metaDataDialog.setFileUri(uri);
 | 
			
		||||
        metaDataDialog.show(getParentFragmentManager(), MetaDataDialog.TAG);
 | 
			
		||||
 | 
			
		||||
        homeViewModel.addNote(uri); // Speichere die URI im ViewModel
 | 
			
		||||
        Toast.makeText(getActivity(), "Datei ausgewählt: " + uri.getPath(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void openFileChooser() {
 | 
			
		||||
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
 | 
			
		||||
        intent.setType("*/*"); // Alle Dateitypen
 | 
			
		||||
 | 
			
		||||
        String[] mimeTypes = {"application/pdf", "image/png", "image/jpeg"};
 | 
			
		||||
        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
 | 
			
		||||
 | 
			
		||||
        intent.addCategory(Intent.CATEGORY_OPENABLE);
 | 
			
		||||
        startActivityForResult(intent, PICK_FILE_REQUEST_CODE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								app/src/main/java/core/notevault/ui/home/HomeViewModel.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,33 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
import core.notevault.MainActivity;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class HomeViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<List<String>> noteTitles;
 | 
			
		||||
 | 
			
		||||
    public HomeViewModel() {
 | 
			
		||||
        noteTitles = new MutableLiveData<>(new ArrayList<>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<List<String>> getNoteTitles() {
 | 
			
		||||
        return noteTitles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNoteTitles(ArrayList<String> noteTitles) {
 | 
			
		||||
        this.noteTitles.setValue(noteTitles);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addNote(Uri uri) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,71 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class NoteSongAdapter extends RecyclerView.Adapter<NoteSongAdapter.NoteViewHolder> {
 | 
			
		||||
 | 
			
		||||
    private List<MusicNote> noteTitles;
 | 
			
		||||
 | 
			
		||||
    public NoteSongAdapter(List<MusicNote> noteTitles) {
 | 
			
		||||
        this.noteTitles = noteTitles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NoteSongAdapter() {
 | 
			
		||||
        this.noteTitles = new ArrayList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(parent.getContext())
 | 
			
		||||
                .inflate(R.layout.item_song, parent, false);
 | 
			
		||||
        return new NoteViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull NoteViewHolder holder, int position) {
 | 
			
		||||
        holder.titleTextView.setText(noteTitles.get(position).getTitle());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return noteTitles.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateSongTitles(List<MusicNote> songTitles) {
 | 
			
		||||
        this.noteTitles.clear();
 | 
			
		||||
        this.noteTitles.addAll(songTitles);
 | 
			
		||||
        notifyDataSetChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NoteViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView titleTextView;
 | 
			
		||||
 | 
			
		||||
        public NoteViewHolder(View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            titleTextView = itemView.findViewById(R.id.note_title);
 | 
			
		||||
 | 
			
		||||
            titleTextView.setOnClickListener(v -> {
 | 
			
		||||
                int position = getAdapterPosition();
 | 
			
		||||
                if(position != RecyclerView.NO_POSITION) {
 | 
			
		||||
                    MusicNote song = noteTitles.get(position);
 | 
			
		||||
 | 
			
		||||
                    Intent intent = new Intent(itemView.getContext(), FullScreenImageActivity.class);
 | 
			
		||||
                    intent.putExtra("imageUri", song.getFilePath());
 | 
			
		||||
                    itemView.getContext().startActivity(intent);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,108 @@
 | 
			
		||||
package core.notevault.ui.metadatadialog;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.provider.OpenableColumns;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.EditText;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.fragment.app.DialogFragment;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
 | 
			
		||||
public class MetaDataDialog extends DialogFragment {
 | 
			
		||||
    private Uri fileUri;
 | 
			
		||||
 | 
			
		||||
    public interface OnMetadataListener {
 | 
			
		||||
        void onMetadataEntered(String title, String composer, int year, String genre);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private OnMetadataListener listener;
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 | 
			
		||||
        LayoutInflater inflater = requireActivity().getLayoutInflater();
 | 
			
		||||
        View dialogView = inflater.inflate(R.layout.fragment_metadata_dialog, null); // Ersetze 'your_dialog_layout' durch deinen Dateinamen
 | 
			
		||||
 | 
			
		||||
        EditText title_input = dialogView.findViewById(R.id.title_input);
 | 
			
		||||
        title_input.setText(this.extraxtTitleFromFilePath());
 | 
			
		||||
        EditText composer_input = dialogView.findViewById(R.id.composer_input);
 | 
			
		||||
        EditText year_input = dialogView.findViewById(R.id.year_input);
 | 
			
		||||
        EditText genre_input = dialogView.findViewById(R.id.genre_input);
 | 
			
		||||
 | 
			
		||||
        return new AlertDialog.Builder(requireContext())
 | 
			
		||||
                .setView(dialogView)
 | 
			
		||||
                .setPositiveButton("Speichern", (dialog, which) -> {
 | 
			
		||||
                    String title = title_input.getText().toString();
 | 
			
		||||
                    String composer = composer_input.getText().toString();
 | 
			
		||||
 | 
			
		||||
                    String year_string = year_input.getText().toString();
 | 
			
		||||
                    int year = 0;
 | 
			
		||||
                    if(!year_string.isEmpty()) {
 | 
			
		||||
                        year = Integer.parseInt(year_input.getText().toString());
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    String genre = genre_input.getText().toString();
 | 
			
		||||
 | 
			
		||||
                    listener.onMetadataEntered(title, composer, year, genre);
 | 
			
		||||
                } )
 | 
			
		||||
                .setNegativeButton("Abbrechen", (dialog, which) -> {} )
 | 
			
		||||
                .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAttach(@NonNull Context context) {
 | 
			
		||||
        super.onAttach(context);
 | 
			
		||||
        if (context instanceof OnMetadataListener) {
 | 
			
		||||
            listener = (OnMetadataListener) context;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException(context.toString()
 | 
			
		||||
                    + " must implement OnMetadataListener");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Uri getFileUri() {
 | 
			
		||||
        return fileUri;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFileUri(Uri fileUri) {
 | 
			
		||||
        this.fileUri = fileUri;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String extraxtTitleFromFilePath() {
 | 
			
		||||
        String fileName = "";
 | 
			
		||||
 | 
			
		||||
        // Überprüfen, ob die Uri ein Content-Uri ist
 | 
			
		||||
        if (this.fileUri.getScheme().equals("content")) {
 | 
			
		||||
            // ContentResolver verwenden, um die Datei zu finden
 | 
			
		||||
            Cursor cursor = requireContext().getContentResolver().query(this.fileUri, null, null, null, null);
 | 
			
		||||
            if (cursor != null) {
 | 
			
		||||
                int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
 | 
			
		||||
                if (cursor.moveToFirst()) {
 | 
			
		||||
                    // Den Dateinamen aus dem Cursor abfragen
 | 
			
		||||
                    fileName = cursor.getString(nameIndex);
 | 
			
		||||
                }
 | 
			
		||||
                cursor.close();
 | 
			
		||||
            }
 | 
			
		||||
        } else if (this.fileUri.getScheme().equals("file")) {
 | 
			
		||||
            // Bei einer Datei-Uri einfach den letzten Pfadsegment verwenden
 | 
			
		||||
            fileName = this.fileUri.getLastPathSegment();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(fileName.contains(".")) {
 | 
			
		||||
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
 | 
			
		||||
            fileName = fileName.replace("_", " ");
 | 
			
		||||
            fileName = fileName.replace("-", "");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return fileName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String TAG = "MetaDataDialog";
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
package core.notevault.ui.slideshow;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import core.notevault.databinding.FragmentSlideshowBinding;
 | 
			
		||||
 | 
			
		||||
public class SlideshowFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    private FragmentSlideshowBinding binding;
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        SlideshowViewModel slideshowViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(SlideshowViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentSlideshowBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        final TextView textView = binding.textSlideshow;
 | 
			
		||||
        slideshowViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
package core.notevault.ui.slideshow;
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
 | 
			
		||||
public class SlideshowViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<String> mText;
 | 
			
		||||
 | 
			
		||||
    public SlideshowViewModel() {
 | 
			
		||||
        mText = new MutableLiveData<>();
 | 
			
		||||
        mText.setValue("This is slideshow fragment");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<String> getText() {
 | 
			
		||||
        return mText;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:width="24dp"
 | 
			
		||||
    android:height="24dp"
 | 
			
		||||
    android:viewportWidth="960"
 | 
			
		||||
    android:viewportHeight="960">
 | 
			
		||||
  <path
 | 
			
		||||
      android:pathData="M440,520L200,520v-80h240v-240h80v240h240v80L520,520v240h-80v-240Z"
 | 
			
		||||
      android:fillColor="#e8eaed"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										12
									
								
								app/src/main/res/drawable/ic_menu_camera.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,12 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
            android:fillColor="#FF000000"
 | 
			
		||||
            android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
 | 
			
		||||
    <path
 | 
			
		||||
            android:fillColor="#FF000000"
 | 
			
		||||
            android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_menu_gallery.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
            android:fillColor="#FF000000"
 | 
			
		||||
            android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_menu_slideshow.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
            android:fillColor="#FF000000"
 | 
			
		||||
            android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 182 B  | 
							
								
								
									
										9
									
								
								app/src/main/res/drawable/side_nav_bar.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,9 @@
 | 
			
		||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
       android:shape="rectangle">
 | 
			
		||||
    <gradient
 | 
			
		||||
            android:angle="135"
 | 
			
		||||
            android:centerColor="#009688"
 | 
			
		||||
            android:endColor="#00695C"
 | 
			
		||||
            android:startColor="#4DB6AC"
 | 
			
		||||
            android:type="linear"/>
 | 
			
		||||
</shape>
 | 
			
		||||
							
								
								
									
										12
									
								
								app/src/main/res/layout/activity_full_screen_image.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,12 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
            android:id="@+id/fullscreen_image_view"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:scaleType="fitCenter" /> <!-- Optional: fitCenter, centerCrop, etc. -->
 | 
			
		||||
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
							
								
								
									
										26
									
								
								app/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,26 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.drawerlayout.widget.DrawerLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:id="@+id/drawer_layout"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:fitsSystemWindows="true"
 | 
			
		||||
        tools:openDrawer="start">
 | 
			
		||||
 | 
			
		||||
    <include
 | 
			
		||||
            android:id="@+id/app_bar_main"
 | 
			
		||||
            layout="@layout/app_bar_main"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"/>
 | 
			
		||||
 | 
			
		||||
    <com.google.android.material.navigation.NavigationView
 | 
			
		||||
            android:id="@+id/nav_view"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:layout_gravity="start"
 | 
			
		||||
            android:fitsSystemWindows="true"
 | 
			
		||||
            app:headerLayout="@layout/nav_header_main"
 | 
			
		||||
            app:menu="@menu/activity_main_drawer"/>
 | 
			
		||||
</androidx.drawerlayout.widget.DrawerLayout>
 | 
			
		||||
							
								
								
									
										26
									
								
								app/src/main/res/layout/app_bar_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,26 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".MainActivity">
 | 
			
		||||
 | 
			
		||||
    <com.google.android.material.appbar.AppBarLayout
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:theme="@style/Theme.NoteVault.AppBarOverlay">
 | 
			
		||||
 | 
			
		||||
        <androidx.appcompat.widget.Toolbar
 | 
			
		||||
                android:id="@+id/toolbar"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:background="?attr/colorPrimary"
 | 
			
		||||
                app:popupTheme="@style/Theme.NoteVault.PopupOverlay"
 | 
			
		||||
                android:layout_height="?attr/actionBarSize"/>
 | 
			
		||||
 | 
			
		||||
    </com.google.android.material.appbar.AppBarLayout>
 | 
			
		||||
 | 
			
		||||
    <include layout="@layout/content_main"/>
 | 
			
		||||
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
							
								
								
									
										22
									
								
								app/src/main/res/layout/content_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,22 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
 | 
			
		||||
        tools:showIn="@layout/app_bar_main">
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
            android:id="@+id/nav_host_fragment_content_main"
 | 
			
		||||
            android:name="androidx.navigation.fragment.NavHostFragment"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            app:layout_constraintLeft_toLeftOf="parent"
 | 
			
		||||
            app:layout_constraintRight_toRightOf="parent"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
            app:defaultNavHost="true"
 | 
			
		||||
            app:navGraph="@navigation/mobile_navigation"
 | 
			
		||||
    />
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
							
								
								
									
										23
									
								
								app/src/main/res/layout/fragment_gallery.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,23 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.gallery.GalleryFragment">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/text_gallery"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginStart="8dp"
 | 
			
		||||
            android:layout_marginTop="8dp"
 | 
			
		||||
            android:layout_marginEnd="8dp"
 | 
			
		||||
            android:textAlignment="center"
 | 
			
		||||
            android:textSize="20sp"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
							
								
								
									
										28
									
								
								app/src/main/res/layout/fragment_home.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,28 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.home.HomeFragment">
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/note_recycler_view"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:layout_above="@+id/importMusicNotesBtn"/>
 | 
			
		||||
 | 
			
		||||
    <com.google.android.material.floatingactionbutton.FloatingActionButton
 | 
			
		||||
            android:src="@drawable/add_24dp_e8eaed_fill0_wght400_grad0_opsz24"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:clickable="true"
 | 
			
		||||
            android:id="@+id/importMusicNotesBtn"
 | 
			
		||||
            android:layout_marginEnd="16dp"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
            android:layout_marginBottom="16dp"
 | 
			
		||||
            app:backgroundTint="@color/teal_200"
 | 
			
		||||
            android:contentDescription="Add Music Notes"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
							
								
								
									
										126
									
								
								app/src/main/res/layout/fragment_metadata_dialog.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,126 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:padding="16dp"
 | 
			
		||||
        android:id="@+id/metadata_dialog">
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:orientation="vertical"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="Import-Einstellungen"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:id="@+id/dialog_title"
 | 
			
		||||
                android:textStyle="bold"
 | 
			
		||||
                android:textSize="18sp"/>
 | 
			
		||||
 | 
			
		||||
        <TableLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
            <TableRow
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:text="Titel: "
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:id="@+id/title_label"/>
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:layout_weight="1"
 | 
			
		||||
                        android:inputType="text"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/title_input"
 | 
			
		||||
                        android:hint="Titel eingeben"
 | 
			
		||||
                        android:foregroundTint="#000000"
 | 
			
		||||
                        android:minHeight="48dp"
 | 
			
		||||
                        android:padding="16dp"
 | 
			
		||||
                        android:minWidth="48dp"/>
 | 
			
		||||
 | 
			
		||||
            </TableRow>
 | 
			
		||||
 | 
			
		||||
            <TableRow
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:text="Komponisten: "
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:id="@+id/composer_label"/>
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:inputType="text"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/composer_input"
 | 
			
		||||
                        android:hint="Komponisten eingeben"
 | 
			
		||||
                        android:layout_weight="1"
 | 
			
		||||
                        android:minWidth="48dp"
 | 
			
		||||
                        android:minHeight="48dp"
 | 
			
		||||
                        android:padding="16dp"/>
 | 
			
		||||
 | 
			
		||||
            </TableRow>
 | 
			
		||||
 | 
			
		||||
            <TableRow
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:text="Jahr: "
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:id="@+id/year_label"/>
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:inputType="numberSigned"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/year_input"
 | 
			
		||||
                        android:hint="Erscheinungsjahr eingeben"
 | 
			
		||||
                        android:padding="16dp"
 | 
			
		||||
                        android:minWidth="48dp"
 | 
			
		||||
                        android:minHeight="48dp"
 | 
			
		||||
                        android:layout_weight="1"/>
 | 
			
		||||
 | 
			
		||||
            </TableRow>
 | 
			
		||||
 | 
			
		||||
            <TableRow
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:text="Genre: "
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:id="@+id/genre_label"/>
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:inputType="text"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/genre_input"
 | 
			
		||||
                        android:hint="Genre eingeben"
 | 
			
		||||
                        android:minWidth="48dp"
 | 
			
		||||
                        android:minHeight="48dp"
 | 
			
		||||
                        android:padding="16dp"
 | 
			
		||||
                        android:layout_weight="1"/>
 | 
			
		||||
 | 
			
		||||
            </TableRow>
 | 
			
		||||
        </TableLayout>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
							
								
								
									
										23
									
								
								app/src/main/res/layout/fragment_slideshow.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,23 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.slideshow.SlideshowFragment">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/text_slideshow"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_marginStart="8dp"
 | 
			
		||||
            android:layout_marginTop="8dp"
 | 
			
		||||
            android:layout_marginEnd="8dp"
 | 
			
		||||
            android:textAlignment="center"
 | 
			
		||||
            android:textSize="20sp"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
							
								
								
									
										13
									
								
								app/src/main/res/layout/item_song.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,13 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="wrap_content"
 | 
			
		||||
              android:orientation="vertical"
 | 
			
		||||
              android:padding="16dp">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/note_title"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:textSize="18sp" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
							
								
								
									
										36
									
								
								app/src/main/res/layout/nav_header_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,36 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="@dimen/nav_header_height"
 | 
			
		||||
        android:background="@drawable/side_nav_bar"
 | 
			
		||||
        android:paddingBottom="@dimen/activity_vertical_margin"
 | 
			
		||||
        android:paddingLeft="@dimen/activity_horizontal_margin"
 | 
			
		||||
        android:paddingRight="@dimen/activity_horizontal_margin"
 | 
			
		||||
        android:paddingTop="@dimen/activity_vertical_margin"
 | 
			
		||||
        android:theme="@style/ThemeOverlay.AppCompat.Dark"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:gravity="bottom">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:paddingTop="@dimen/nav_header_vertical_spacing"
 | 
			
		||||
            app:srcCompat="@mipmap/ic_launcher_round"
 | 
			
		||||
            android:contentDescription="@string/nav_header_desc"
 | 
			
		||||
            android:id="@+id/imageView"/>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:paddingTop="@dimen/nav_header_vertical_spacing"
 | 
			
		||||
            android:text="@string/nav_header_title"
 | 
			
		||||
            android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="@string/nav_header_subtitle"
 | 
			
		||||
            android:id="@+id/textView"/>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
							
								
								
									
										20
									
								
								app/src/main/res/menu/activity_main_drawer.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,20 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
      xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
      tools:showIn="navigation_view">
 | 
			
		||||
 | 
			
		||||
    <group android:checkableBehavior="single">
 | 
			
		||||
        <item
 | 
			
		||||
                android:id="@+id/nav_home"
 | 
			
		||||
                android:icon="@drawable/ic_menu_camera"
 | 
			
		||||
                android:title="@string/menu_home"/>
 | 
			
		||||
        <item
 | 
			
		||||
                android:id="@+id/nav_gallery"
 | 
			
		||||
                android:icon="@drawable/ic_menu_gallery"
 | 
			
		||||
                android:title="@string/menu_gallery"/>
 | 
			
		||||
        <item
 | 
			
		||||
                android:id="@+id/nav_slideshow"
 | 
			
		||||
                android:icon="@drawable/ic_menu_slideshow"
 | 
			
		||||
                android:title="@string/menu_slideshow"/>
 | 
			
		||||
    </group>
 | 
			
		||||
</menu>
 | 
			
		||||
							
								
								
									
										8
									
								
								app/src/main/res/menu/main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,8 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
      xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
			
		||||
    <item android:id="@+id/action_settings"
 | 
			
		||||
          android:title="@string/action_settings"
 | 
			
		||||
          android:orderInCategory="101"
 | 
			
		||||
          app:showAsAction="never"/>
 | 
			
		||||
</menu>
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <background android:drawable="@mipmap/ic_launcher_background"/>
 | 
			
		||||
    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <background android:drawable="@mipmap/ic_launcher_background"/>
 | 
			
		||||
    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
							
								
								
									
										6
									
								
								app/src/main/res/mipmap-anydpi/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,6 @@
 | 
			
		||||
<?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"/>
 | 
			
		||||
    <monochrome android:drawable="@drawable/ic_launcher_foreground"/>
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
							
								
								
									
										6
									
								
								app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,6 @@
 | 
			
		||||
<?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"/>
 | 
			
		||||
    <monochrome android:drawable="@drawable/ic_launcher_foreground"/>
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.4 KiB  | 
| 
		 Before Width: | Height: | Size: 44 B  | 
| 
		 Before Width: | Height: | Size: 8.6 KiB  | 
| 
		 Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 982 B  | 
| 
		 Before Width: | Height: | Size: 44 B  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.7 KiB  | 
| 
		 Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 46 B  | 
| 
		 Before Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 52 B  | 
| 
		 Before Width: | Height: | Size: 28 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.8 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 52 B  | 
| 
		 Before Width: | Height: | Size: 50 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 7.6 KiB  | 
							
								
								
									
										25
									
								
								app/src/main/res/navigation/mobile_navigation.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,25 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            android:id="@+id/mobile_navigation"
 | 
			
		||||
            app:startDestination="@+id/nav_home">
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
            android:id="@+id/nav_home"
 | 
			
		||||
            android:name="core.notevault.ui.home.HomeFragment"
 | 
			
		||||
            android:label="@string/menu_home"
 | 
			
		||||
            tools:layout="@layout/fragment_home"/>
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
            android:id="@+id/nav_gallery"
 | 
			
		||||
            android:name="core.notevault.ui.gallery.GalleryFragment"
 | 
			
		||||
            android:label="@string/menu_gallery"
 | 
			
		||||
            tools:layout="@layout/fragment_gallery"/>
 | 
			
		||||
 | 
			
		||||
    <fragment
 | 
			
		||||
            android:id="@+id/nav_slideshow"
 | 
			
		||||
            android:name="core.notevault.ui.slideshow.SlideshowFragment"
 | 
			
		||||
            android:label="@string/menu_slideshow"
 | 
			
		||||
            tools:layout="@layout/fragment_slideshow"/>
 | 
			
		||||
</navigation>
 | 
			
		||||
							
								
								
									
										3
									
								
								app/src/main/res/values-land/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
			
		||||
<resources>
 | 
			
		||||
    <dimen name="fab_margin">48dp</dimen>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										16
									
								
								app/src/main/res/values-night/themes.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,16 @@
 | 
			
		||||
<resources xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
    <!-- Base application theme. -->
 | 
			
		||||
    <style name="Theme.NoteVault" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
 | 
			
		||||
        <!-- Primary brand color. -->
 | 
			
		||||
        <item name="colorPrimary">@color/purple_200</item>
 | 
			
		||||
        <item name="colorPrimaryVariant">@color/purple_700</item>
 | 
			
		||||
        <item name="colorOnPrimary">@color/black</item>
 | 
			
		||||
        <!-- Secondary brand color. -->
 | 
			
		||||
        <item name="colorSecondary">@color/teal_200</item>
 | 
			
		||||
        <item name="colorSecondaryVariant">@color/teal_200</item>
 | 
			
		||||
        <item name="colorOnSecondary">@color/black</item>
 | 
			
		||||
        <!-- Status bar color. -->
 | 
			
		||||
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
 | 
			
		||||
        <!-- Customize your theme here. -->
 | 
			
		||||
    </style>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										3
									
								
								app/src/main/res/values-w1240dp/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
			
		||||
<resources>
 | 
			
		||||
    <dimen name="fab_margin">200dp</dimen>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										3
									
								
								app/src/main/res/values-w600dp/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
			
		||||
<resources>
 | 
			
		||||
    <dimen name="fab_margin">48dp</dimen>
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										8
									
								
								app/src/main/res/values/dimens.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,8 @@
 | 
			
		||||
<resources>
 | 
			
		||||
    <!-- Default screen margins, per the Android Design guidelines. -->
 | 
			
		||||
    <dimen name="activity_horizontal_margin">16dp</dimen>
 | 
			
		||||
    <dimen name="activity_vertical_margin">16dp</dimen>
 | 
			
		||||
    <dimen name="nav_header_vertical_spacing">8dp</dimen>
 | 
			
		||||
    <dimen name="nav_header_height">176dp</dimen>
 | 
			
		||||
    <dimen name="fab_margin">16dp</dimen>
 | 
			
		||||
</resources>
 | 
			
		||||