Clear Project for Rewriting
This commit is contained in:
		
							parent
							
								
									68a8e23862
								
							
						
					
					
						commit
						193f8ee18c
					
				
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,8 +0,0 @@
 | 
			
		||||
# Default ignored files
 | 
			
		||||
/shelf/
 | 
			
		||||
/workspace.xml
 | 
			
		||||
# Editor-based HTTP Client requests
 | 
			
		||||
/httpRequests/
 | 
			
		||||
# Datasource local storage ignored files
 | 
			
		||||
/dataSources/
 | 
			
		||||
/dataSources.local.xml
 | 
			
		||||
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.idea/.name
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
NoteVault
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
<component name="ProjectCodeStyleConfiguration">
 | 
			
		||||
  <state>
 | 
			
		||||
    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
 | 
			
		||||
  </state>
 | 
			
		||||
</component>
 | 
			
		||||
@ -1,43 +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="7fd8322d-6535-44e0-a663-86c7b54f4fbd">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/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>
 | 
			
		||||
    </data-source>
 | 
			
		||||
    <data-source source="LOCAL" name="music_database [2]" uuid="6f801a54-4854-4db5-910c-ae63a8207d3e">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/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>
 | 
			
		||||
    </data-source>
 | 
			
		||||
    <data-source source="LOCAL" name="music_database [3]" uuid="3acbe0c9-6415-4726-8c75-c07350984fcc">
 | 
			
		||||
      <driver-ref>sqlite.xerial</driver-ref>
 | 
			
		||||
      <synchronize>true</synchronize>
 | 
			
		||||
      <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
 | 
			
		||||
      <jdbc-url>jdbc:sqlite:$USER_HOME$/.cache/JetBrains/IntelliJIdea2024.1/device-explorer/Pixel Tablet API 30/_/data/data/core.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>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -2,9 +2,6 @@
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="deploymentTargetDropDown">
 | 
			
		||||
    <value>
 | 
			
		||||
      <entry key="NoteVault">
 | 
			
		||||
        <State />
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry key="app">
 | 
			
		||||
        <State />
 | 
			
		||||
      </entry>
 | 
			
		||||
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="deploymentTargetSelector">
 | 
			
		||||
    <selectionStates>
 | 
			
		||||
      <SelectionState runConfigName="app">
 | 
			
		||||
        <option name="selectionMode" value="DROPDOWN" />
 | 
			
		||||
      </SelectionState>
 | 
			
		||||
    </selectionStates>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,12 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="ExternalStorageConfigurationManager" enabled="true" />
 | 
			
		||||
  <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">
 | 
			
		||||
    <output url="file://$PROJECT_DIR$/build/classes" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectType">
 | 
			
		||||
    <option name="id" value="Android" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK" />
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,124 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="Palette2">
 | 
			
		||||
    <group name="Swing">
 | 
			
		||||
      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
 | 
			
		||||
        <initial-values>
 | 
			
		||||
          <property name="text" value="Button" />
 | 
			
		||||
        </initial-values>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
 | 
			
		||||
        <initial-values>
 | 
			
		||||
          <property name="text" value="RadioButton" />
 | 
			
		||||
        </initial-values>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
 | 
			
		||||
        <initial-values>
 | 
			
		||||
          <property name="text" value="CheckBox" />
 | 
			
		||||
        </initial-values>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
 | 
			
		||||
        <initial-values>
 | 
			
		||||
          <property name="text" value="Label" />
 | 
			
		||||
        </initial-values>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
 | 
			
		||||
          <preferred-size width="150" height="-1" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
 | 
			
		||||
          <preferred-size width="150" height="-1" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
 | 
			
		||||
          <preferred-size width="150" height="-1" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="150" height="50" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="200" height="200" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
 | 
			
		||||
          <preferred-size width="200" height="200" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
 | 
			
		||||
          <preferred-size width="-1" height="20" />
 | 
			
		||||
        </default-constraints>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
 | 
			
		||||
      </item>
 | 
			
		||||
      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
 | 
			
		||||
        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
 | 
			
		||||
      </item>
 | 
			
		||||
    </group>
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="VcsDirectoryMappings">
 | 
			
		||||
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
 | 
			
		||||
    <mapping directory="" vcs="Git" />
 | 
			
		||||
  </component>
 | 
			
		||||
</project>
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    alias(libs.plugins.android.application)
 | 
			
		||||
 | 
			
		||||
    id("com.android.application")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    namespace = "core.notevault"
 | 
			
		||||
    compileSdk = 35
 | 
			
		||||
    namespace = "com.stormtales.notevault"
 | 
			
		||||
    compileSdk = 34
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId = "core.notevault"
 | 
			
		||||
        minSdk = 28
 | 
			
		||||
        targetSdk = 35
 | 
			
		||||
        applicationId = "com.stormtales.notevault"
 | 
			
		||||
        minSdk = 29
 | 
			
		||||
        targetSdk = 34
 | 
			
		||||
        versionCode = 1
 | 
			
		||||
        versionName = "1.0"
 | 
			
		||||
 | 
			
		||||
@ -22,10 +21,6 @@ android {
 | 
			
		||||
            isMinifyEnabled = false
 | 
			
		||||
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
 | 
			
		||||
        }
 | 
			
		||||
        debug {
 | 
			
		||||
            // Setzt den Manifest-Platzhalter nur für den Debug-Build auf true
 | 
			
		||||
            manifestPlaceholders["usesCleartextTraffic"] = "true"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
@ -38,32 +33,14 @@ android {
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
 | 
			
		||||
    implementation(libs.appcompat)
 | 
			
		||||
    implementation(libs.material)
 | 
			
		||||
    implementation(libs.constraintlayout)
 | 
			
		||||
    implementation(libs.lifecycle.livedata.ktx)
 | 
			
		||||
    implementation(libs.lifecycle.viewmodel.ktx)
 | 
			
		||||
    implementation(libs.navigation.fragment)
 | 
			
		||||
    implementation(libs.navigation.ui)
 | 
			
		||||
    implementation(libs.room.common)
 | 
			
		||||
    implementation("androidx.recyclerview:recyclerview:1.3.2")
 | 
			
		||||
    implementation("com.github.chrisbanes:PhotoView:2.3.0")
 | 
			
		||||
    implementation(libs.car.ui.lib)
 | 
			
		||||
    testImplementation(libs.junit)
 | 
			
		||||
    androidTestImplementation(libs.ext.junit)
 | 
			
		||||
    androidTestImplementation(libs.espresso.core)
 | 
			
		||||
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
 | 
			
		||||
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
 | 
			
		||||
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    implementation("androidx.work:work-runtime:2.10.0")
 | 
			
		||||
    implementation("androidx.appcompat:appcompat:1.7.0")
 | 
			
		||||
    implementation("com.google.android.material:material:1.12.0")
 | 
			
		||||
    implementation("androidx.constraintlayout:constraintlayout:2.2.0")
 | 
			
		||||
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")
 | 
			
		||||
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
 | 
			
		||||
    implementation("androidx.navigation:navigation-fragment:2.8.3")
 | 
			
		||||
    implementation("androidx.navigation:navigation-ui:2.8.3")
 | 
			
		||||
    testImplementation("junit:junit:4.13.2")
 | 
			
		||||
    androidTestImplementation("androidx.test.ext:junit:1.2.1")
 | 
			
		||||
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package core.notevault;
 | 
			
		||||
package com.stormtales.notevault;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import androidx.test.platform.app.InstrumentationRegistry;
 | 
			
		||||
@ -20,6 +20,6 @@ public class ExampleInstrumentedTest {
 | 
			
		||||
    public void useAppContext() {
 | 
			
		||||
        // Context of the app under test.
 | 
			
		||||
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 | 
			
		||||
        assertEquals("core.notevault", appContext.getPackageName());
 | 
			
		||||
        assertEquals("com.stormtales.notevault", appContext.getPackageName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +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" />
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
            android:allowBackup="true"
 | 
			
		||||
            android:dataExtractionRules="@xml/data_extraction_rules"
 | 
			
		||||
@ -12,7 +11,6 @@
 | 
			
		||||
            android:roundIcon="@mipmap/ic_launcher_round"
 | 
			
		||||
            android:supportsRtl="true"
 | 
			
		||||
            android:theme="@style/Theme.NoteVault"
 | 
			
		||||
            android:usesCleartextTraffic="true"
 | 
			
		||||
            tools:targetApi="31">
 | 
			
		||||
        <activity
 | 
			
		||||
                android:name=".MainActivity"
 | 
			
		||||
@ -25,12 +23,6 @@
 | 
			
		||||
                <category android:name="android.intent.category.LAUNCHER"/>
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
 | 
			
		||||
        <activity android:name=".ui.home.FullScreenImageActivity"
 | 
			
		||||
                  android:theme="@style/Theme.AppCompat.NoActionBar">
 | 
			
		||||
            <!-- Intent Filter hinzufügen, wenn Activity vom Launcher oder externen Apps aufgerufen werden soll -->
 | 
			
		||||
        </activity>
 | 
			
		||||
 | 
			
		||||
    </application>
 | 
			
		||||
 | 
			
		||||
</manifest>
 | 
			
		||||
							
								
								
									
										62
									
								
								app/src/main/java/com/stormtales/notevault/MainActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/src/main/java/com/stormtales/notevault/MainActivity.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
package com.stormtales.notevault;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
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 com.stormtales.notevault.databinding.ActivityMainBinding;
 | 
			
		||||
 | 
			
		||||
public class MainActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
    private AppBarConfiguration mAppBarConfiguration;
 | 
			
		||||
    private ActivityMainBinding binding;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        binding = ActivityMainBinding.inflate(getLayoutInflater());
 | 
			
		||||
        setContentView(binding.getRoot());
 | 
			
		||||
 | 
			
		||||
        setSupportActionBar(binding.appBarMain.toolbar);
 | 
			
		||||
        binding.appBarMain.fab.setOnClickListener(new View.OnClickListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onClick(View view) {
 | 
			
		||||
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
 | 
			
		||||
                        .setAction("Action", null).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
package com.stormtales.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 com.stormtales.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 com.stormtales.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,35 @@
 | 
			
		||||
package com.stormtales.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
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 com.stormtales.notevault.databinding.FragmentHomeBinding;
 | 
			
		||||
 | 
			
		||||
public class HomeFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    private FragmentHomeBinding binding;
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        HomeViewModel homeViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(HomeViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentHomeBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        final TextView textView = binding.textHome;
 | 
			
		||||
        homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
package com.stormtales.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
 | 
			
		||||
public class HomeViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<String> mText;
 | 
			
		||||
 | 
			
		||||
    public HomeViewModel() {
 | 
			
		||||
        mText = new MutableLiveData<>();
 | 
			
		||||
        mText.setValue("This is home fragment");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<String> getText() {
 | 
			
		||||
        return mText;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package core.notevault.ui.slideshow;
 | 
			
		||||
package com.stormtales.notevault.ui.slideshow;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
@ -8,7 +8,7 @@ import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import core.notevault.databinding.FragmentSlideshowBinding;
 | 
			
		||||
import com.stormtales.notevault.databinding.FragmentSlideshowBinding;
 | 
			
		||||
 | 
			
		||||
public class SlideshowFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
package core.notevault.ui.slideshow;
 | 
			
		||||
package com.stormtales.notevault.ui.slideshow;
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
@ -1,308 +0,0 @@
 | 
			
		||||
package core.notevault;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.text.TextUtils;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.fragment.app.FragmentManager;
 | 
			
		||||
import androidx.navigation.fragment.NavHostFragment;
 | 
			
		||||
import androidx.work.OneTimeWorkRequest;
 | 
			
		||||
import androidx.work.WorkManager;
 | 
			
		||||
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.*;
 | 
			
		||||
import core.notevault.databinding.ActivityMainBinding;
 | 
			
		||||
import core.notevault.sync.SyncWorker;
 | 
			
		||||
import core.notevault.sync.auth.AuthRepository;
 | 
			
		||||
import core.notevault.sync.auth.LoginCallback;
 | 
			
		||||
import core.notevault.ui.gallery.GalleryFragment;
 | 
			
		||||
import core.notevault.ui.gallery.detail.ConcertSongSelector;
 | 
			
		||||
import core.notevault.ui.gallery.editor.ConcertEditorDialog;
 | 
			
		||||
import core.notevault.ui.home.HomeFragment;
 | 
			
		||||
import core.notevault.ui.login.LoginCallBackImpl;
 | 
			
		||||
import core.notevault.ui.login.LoginDialogFragment;
 | 
			
		||||
import core.notevault.ui.login.RegisterCallback;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
import core.notevault.ui.metadatadialog.SongEditDialog;
 | 
			
		||||
import core.notevault.util.NoteSheetsUtil;
 | 
			
		||||
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
public class MainActivity extends AppCompatActivity implements MetaDataDialog.OnMetadataListener,
 | 
			
		||||
        ConcertEditorDialog.OnConcertEditorListener, ConcertSongSelector.OnSongSelectedListener, LoginCallback, SongEditDialog.SongEditorListener {
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
        setupLoginButton();
 | 
			
		||||
        musicDB = MusicDatabase.getDatabase(this);
 | 
			
		||||
        scheduleSync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void scheduleSync() {
 | 
			
		||||
        // Setze eine Uhrzeit für die Synchronisation
 | 
			
		||||
        Calendar calendar = Calendar.getInstance();
 | 
			
		||||
        calendar.set(Calendar.HOUR_OF_DAY,11);
 | 
			
		||||
        calendar.set(Calendar.MINUTE, 32);
 | 
			
		||||
        calendar.set(Calendar.SECOND, 0);
 | 
			
		||||
 | 
			
		||||
        long triggerTime = calendar.getTimeInMillis(); // Zeitstempel für den Trigger
 | 
			
		||||
 | 
			
		||||
        // Erstelle die OneTimeWorkRequest für den SyncWorker
 | 
			
		||||
        OneTimeWorkRequest syncRequest = new OneTimeWorkRequest.Builder(SyncWorker.class)
 | 
			
		||||
                .setInitialDelay(triggerTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS) // Verzögerung bis zur Ausführung
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        // Planen des Workers mit WorkManager
 | 
			
		||||
        WorkManager.getInstance(getBaseContext()).enqueue(syncRequest);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onPrepareOptionsMenu(Menu menu) {
 | 
			
		||||
        MenuItem loginItem = menu.findItem(R.id.action_login);
 | 
			
		||||
        if (isLoggedIn()) {
 | 
			
		||||
            loginItem.setIcon(R.drawable.logout); // Setze das Logout-Symbol
 | 
			
		||||
        } else {
 | 
			
		||||
            loginItem.setIcon(R.drawable.login); // Setze das Login-Symbol
 | 
			
		||||
        }
 | 
			
		||||
        return super.onPrepareOptionsMenu(menu);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateLoginButton() {
 | 
			
		||||
        invalidateOptionsMenu(); // Menü neu zeichnen
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setupLoginButton() {
 | 
			
		||||
        binding.appBarMain.toolbar.setOnMenuItemClickListener(item -> {
 | 
			
		||||
            if (item.getItemId() == R.id.action_login) {
 | 
			
		||||
                if (isLoggedIn()) {
 | 
			
		||||
                    performLogout(); // Logout-Logik aufrufen
 | 
			
		||||
                } else {
 | 
			
		||||
                    showLoginDialog(); // Zeige das Login-Fenster an
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isLoggedIn() {
 | 
			
		||||
        AuthRepository authRepository = new AuthRepository(this);
 | 
			
		||||
        return !TextUtils.isEmpty(authRepository.getToken());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void showLoginDialog() {
 | 
			
		||||
        LoginDialogFragment loginDialogFragment = LoginDialogFragment.newInstance(new LoginCallBackImpl(this), new RegisterCallback(this));
 | 
			
		||||
        loginDialogFragment.show(getSupportFragmentManager(), "login");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void performLogout() {
 | 
			
		||||
        // Füge hier deine Logout-Logik hinzu
 | 
			
		||||
        AuthRepository authRepository = new AuthRepository(this);
 | 
			
		||||
 | 
			
		||||
        authRepository.logout(); // Implementiere die Token-Löschung
 | 
			
		||||
        updateLoginButton();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @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 onOptionsItemSelected(MenuItem item) {
 | 
			
		||||
        int id = item.getItemId();
 | 
			
		||||
        if(id == R.id.action_login) {
 | 
			
		||||
            openLoginDialog();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return super.onOptionsItemSelected(item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void openLoginDialog() {
 | 
			
		||||
        LoginDialogFragment loginDialogFragment = new LoginDialogFragment();
 | 
			
		||||
        loginDialogFragment.show(getSupportFragmentManager(), "LOGIN_TAG");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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(Uri[] uris, String title, String composer, int year, String genre) {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            MusicNote musicNote = new MusicNote(title, composer, year, genre);
 | 
			
		||||
            long musicNoteID = musicDB.musicNoteDao().insert(musicNote);
 | 
			
		||||
            musicNote.setMusicNoteId(musicNoteID);
 | 
			
		||||
 | 
			
		||||
            Log.d("MainActivity", "MusicNoteID of inserted song: " + musicNoteID);
 | 
			
		||||
            Log.d("MainActivity", "MusicNoteID of referenced song: " + musicNote.getMusicNoteId());
 | 
			
		||||
            for(Uri uri: uris) {
 | 
			
		||||
                String filePath = saveImageInternally(uri);
 | 
			
		||||
                NoteSheet noteSheet = new NoteSheet(musicNoteID, filePath);
 | 
			
		||||
                musicDB.musicNoteDao().insertNoteSheet(noteSheet);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            runOnUiThread(() -> {
 | 
			
		||||
                NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment_content_main);
 | 
			
		||||
                Fragment currentFragment = navHostFragment != null ? navHostFragment.getChildFragmentManager().getFragments().get(0) : null;
 | 
			
		||||
 | 
			
		||||
                if(currentFragment instanceof HomeFragment) {
 | 
			
		||||
                    HomeFragment homeFragment = (HomeFragment) currentFragment;
 | 
			
		||||
                    homeFragment.addSong(musicNote);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Speichere eine Kopie des Bilds im internen Speicher
 | 
			
		||||
    private String saveImageInternally(Uri uri) {
 | 
			
		||||
        try (InputStream inputStream = getContentResolver().openInputStream(uri)) {
 | 
			
		||||
            File imageFile = new File(getFilesDir(), "saved_image_" + System.currentTimeMillis() + ".jpg");
 | 
			
		||||
            try (OutputStream outputStream = Files.newOutputStream(imageFile.toPath())) {
 | 
			
		||||
                byte[] buffer = new byte[4096];
 | 
			
		||||
                int bytesRead;
 | 
			
		||||
                while ((bytesRead = inputStream.read(buffer)) != -1) {
 | 
			
		||||
                    outputStream.write(buffer, 0, bytesRead);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return imageFile.getAbsolutePath(); // Pfad speichern, um später darauf zuzugreifen
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onConcertEditorClosed(String concertTitle, String concertDate, int concertID) {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            if(concertID < 0) {
 | 
			
		||||
                Concert concert = new Concert(concertTitle, concertDate);
 | 
			
		||||
                Log.d("ConcertEditor", "Saved Concert: " + concertTitle + " on " + concertDate);
 | 
			
		||||
                musicDB.musicNoteDao().insertConcert(concert);
 | 
			
		||||
 | 
			
		||||
                runOnUiThread(() -> {
 | 
			
		||||
                    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment_content_main);
 | 
			
		||||
                    Fragment currentFragment = navHostFragment != null ? navHostFragment.getChildFragmentManager().getFragments().get(0) : null;
 | 
			
		||||
 | 
			
		||||
                    Log.d("MainActivity", "Test for GalleryFragment");
 | 
			
		||||
                    Log.d("MainActivity", "Current Fragment: " + currentFragment.getClass().getSimpleName());
 | 
			
		||||
                    if(currentFragment instanceof GalleryFragment) {
 | 
			
		||||
                        Log.d("MainActivity", "GalleryFragment Found");
 | 
			
		||||
                        GalleryFragment galleryFragment = (GalleryFragment) currentFragment;
 | 
			
		||||
                        galleryFragment.addConcert(concert);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Log.d("MainActivity", "GalleryFragment Not Found");
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                Concert concert = new Concert(concertID, concertTitle, concertDate);
 | 
			
		||||
                musicDB.musicNoteDao().updateConcert(concert);
 | 
			
		||||
                runOnUiThread(() -> {
 | 
			
		||||
                    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment_content_main);
 | 
			
		||||
                    Fragment currentFragment = navHostFragment != null ? navHostFragment.getChildFragmentManager().getFragments().get(0) : null;
 | 
			
		||||
 | 
			
		||||
                    Log.d("MainActivity", "Test for GalleryFragment");
 | 
			
		||||
                    Log.d("MainActivity", "Current Fragment: " + currentFragment.getClass().getSimpleName());
 | 
			
		||||
                    if(currentFragment instanceof GalleryFragment) {
 | 
			
		||||
                        Log.d("MainActivity", "GalleryFragment Found");
 | 
			
		||||
                        GalleryFragment galleryFragment = (GalleryFragment) currentFragment;
 | 
			
		||||
                        galleryFragment.updateConcert(concert);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Log.d("MainActivity", "GalleryFragment Not Found");
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSongsSelected(List<MusicNote> songs, int concertID) {
 | 
			
		||||
        Log.d("MainActivity", "Inserted Songs: " + songs.size());
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            for(MusicNote musicNote : songs) {
 | 
			
		||||
                ConcertSong concertSong = new ConcertSong(musicNote.getMusicNoteId(), concertID);
 | 
			
		||||
                musicDB.musicNoteDao().insertConcertSong(concertSong);
 | 
			
		||||
                Log.d("MainActivity", "Insert Song: " + musicNote.getTitle());
 | 
			
		||||
            }
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSuccess() {
 | 
			
		||||
        updateLoginButton();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onError(String error) {
 | 
			
		||||
        Toast.makeText(this, error, Toast.LENGTH_LONG).show();
 | 
			
		||||
        Log.d("LoginError", error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSongEdited(MusicNote updatedSong) {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            musicDB.musicNoteDao().updateSong(updatedSong);
 | 
			
		||||
            Log.d("MainActivity", "Updated Song: " + updatedSong.getTitle());
 | 
			
		||||
        }).start();
 | 
			
		||||
        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment_content_main);
 | 
			
		||||
        Fragment currentFragment = navHostFragment != null ? navHostFragment.getChildFragmentManager().getFragments().get(0) : null;
 | 
			
		||||
 | 
			
		||||
        if(currentFragment instanceof HomeFragment) {
 | 
			
		||||
            HomeFragment homeFragment = (HomeFragment) currentFragment;
 | 
			
		||||
            homeFragment.updateSong(updatedSong);
 | 
			
		||||
        } else if(currentFragment instanceof GalleryFragment) {
 | 
			
		||||
            GalleryFragment galleryFragment = (GalleryFragment) currentFragment;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,90 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.*;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
import core.notevault.data.sync.SyncStatusConverter;
 | 
			
		||||
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "concerts")
 | 
			
		||||
@TypeConverters(SyncStatusConverter.class)
 | 
			
		||||
public class Concert {
 | 
			
		||||
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private int id;
 | 
			
		||||
 | 
			
		||||
    private String serverSpecificConcertID;
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String concertDate;
 | 
			
		||||
    private SyncStatus syncStatus;
 | 
			
		||||
 | 
			
		||||
    private LocalDateTime lastModified;
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public Concert(String title, String concertDate) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.concertDate = concertDate;
 | 
			
		||||
        this.lastModified = LocalDateTime.now();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Concert() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public Concert(int id, String title, String concertDate) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.concertDate = concertDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 getConcertDate() {
 | 
			
		||||
        return concertDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setConcertDate(String concertDate) {
 | 
			
		||||
        this.concertDate = concertDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerSpecificConcertID() {
 | 
			
		||||
        return serverSpecificConcertID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerSpecificConcertID(String serverSpecificConcertID) {
 | 
			
		||||
        this.serverSpecificConcertID = serverSpecificConcertID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SyncStatus getSyncStatus() {
 | 
			
		||||
        return syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSyncStatus(SyncStatus syncStatus) {
 | 
			
		||||
        this.syncStatus = syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LocalDateTime getLastModified() {
 | 
			
		||||
        return lastModified;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLastModified(LocalDateTime lastModified) {
 | 
			
		||||
        this.lastModified = lastModified;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,55 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity;
 | 
			
		||||
import androidx.room.Ignore;
 | 
			
		||||
import androidx.room.PrimaryKey;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "concert_songs")
 | 
			
		||||
public class ConcertSong {
 | 
			
		||||
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private int id;
 | 
			
		||||
 | 
			
		||||
    private long musicNoteID;
 | 
			
		||||
    private int concertID;
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public ConcertSong(long musicNoteID, int concertID) {
 | 
			
		||||
        this.musicNoteID = musicNoteID;
 | 
			
		||||
        this.concertID = concertID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public ConcertSong(int id, long musicNoteID, int concertID) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.musicNoteID = musicNoteID;
 | 
			
		||||
        this.concertID = concertID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ConcertSong() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setId(int id) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public long getMusicNoteID() {
 | 
			
		||||
        return musicNoteID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMusicNoteID(long musicNoteID) {
 | 
			
		||||
        this.musicNoteID = musicNoteID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getConcertID() {
 | 
			
		||||
        return concertID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setConcertID(int concertID) {
 | 
			
		||||
        this.concertID = concertID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.TypeConverter;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
 | 
			
		||||
public class DateConverter {
 | 
			
		||||
    // Konvertiere LocalDateTime in String
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static String fromLocalDateTime(LocalDateTime localDateTime) {
 | 
			
		||||
        return localDateTime == null ? null : localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Konvertiere String zurück in LocalDateTime
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static LocalDateTime toLocalDateTime(String dateTimeString) {
 | 
			
		||||
        return dateTimeString == null ? null : LocalDateTime.parse(dateTimeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import androidx.room.*;
 | 
			
		||||
import core.notevault.data.sync.SyncDataObject;
 | 
			
		||||
import core.notevault.data.sync.SyncStatusConverter;
 | 
			
		||||
 | 
			
		||||
@Database(entities = {MusicNote.class, NoteSheet.class, Concert.class, ConcertSong.class, SyncDataObject.class}, version = 2, exportSchema = false)
 | 
			
		||||
@TypeConverters(DateConverter.class)
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,107 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity;
 | 
			
		||||
import androidx.room.Ignore;
 | 
			
		||||
import androidx.room.PrimaryKey;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "music_notes")
 | 
			
		||||
public class MusicNote {
 | 
			
		||||
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private long musicNoteId;
 | 
			
		||||
    private String serverID;
 | 
			
		||||
    private SyncStatus syncStatus;
 | 
			
		||||
    private LocalDateTime last_sync;
 | 
			
		||||
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String composer;
 | 
			
		||||
    private int year;
 | 
			
		||||
    private String genre;
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public MusicNote(String title,  String composer, int year, String genre) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
        this.year = year;
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
        this.syncStatus = SyncStatus.CREATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MusicNote(long musicNoteId, String title) {
 | 
			
		||||
        this.musicNoteId = musicNoteId;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.syncStatus = SyncStatus.CREATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public MusicNote() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public long getMusicNoteId() {
 | 
			
		||||
        return musicNoteId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMusicNoteId(long musicNoteId) {
 | 
			
		||||
        this.musicNoteId = musicNoteId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTitle(String title) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerID() {
 | 
			
		||||
        return serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerID(String serverID) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SyncStatus getSyncStatus() {
 | 
			
		||||
        return syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSyncStatus(SyncStatus syncStatus) {
 | 
			
		||||
        this.syncStatus = syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LocalDateTime getLast_sync() {
 | 
			
		||||
 | 
			
		||||
        return last_sync;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLast_sync(LocalDateTime last_sync) {
 | 
			
		||||
        this.last_sync = last_sync;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.*;
 | 
			
		||||
 | 
			
		||||
import core.notevault.data.sync.SyncDataObject;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationResponse;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
public interface MusicNoteDAO {
 | 
			
		||||
 | 
			
		||||
    @Insert
 | 
			
		||||
    long insert(MusicNote musicNote);
 | 
			
		||||
 | 
			
		||||
    @Insert
 | 
			
		||||
    void insertNoteSheet(NoteSheet noteSheet);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM music_notes WHERE syncStatus != 'DELETED'")
 | 
			
		||||
    List<MusicNote> getAllNotes();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM note_sheets WHERE musicNoteId = :musicNoteId")
 | 
			
		||||
    List<NoteSheet> getNoteSheetsForMusicSong(long musicNoteId);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM concerts WHERE syncStatus = :status")
 | 
			
		||||
    List<Concert> getConcertsWithSyncStatus(SyncStatus status);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM music_notes WHERE syncStatus = :status")
 | 
			
		||||
    List<MusicNote> getSongsWithSyncStatus(SyncStatus status);
 | 
			
		||||
 | 
			
		||||
    @Insert
 | 
			
		||||
    void insertConcert(Concert concert);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM concerts")
 | 
			
		||||
    List<Concert> getAllConcerts();
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    void deleteConcert(Concert concert);
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    void updateConcert(Concert concert);
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    void deleteSong(MusicNote musicNote);
 | 
			
		||||
 | 
			
		||||
    @Insert
 | 
			
		||||
    void insertConcertSong(ConcertSong concertSong);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT m.* FROM music_notes m JOIN concert_songs cs ON m.musicNoteId = cs.musicNoteID WHERE cs.id = :concertID")
 | 
			
		||||
    List<MusicNote> getAllMusicNotesOfConcert(long concertID);
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM concert_songs WHERE concertID = :concertID AND musicNoteID = :songID")
 | 
			
		||||
    void deleteConcertSong(long songID, int concertID);
 | 
			
		||||
 | 
			
		||||
    @Transaction
 | 
			
		||||
    default void storeSongSyncResponses(List<SongCreationResponse> songCreationResponses) {
 | 
			
		||||
        for (SongCreationResponse response : songCreationResponses) {
 | 
			
		||||
            storeSongSyncResponse(response.getLocalID(), SyncStatus.SYNCED, response.getServerID());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Query("UPDATE music_notes SET syncStatus = :status, serverID = :serverID WHERE musicNoteId = :localID")
 | 
			
		||||
    void storeSongSyncResponse(long localID, SyncStatus status, String serverID);
 | 
			
		||||
 | 
			
		||||
    @Query("UPDATE music_notes SET syncStatus = :status, last_sync = :currentTime WHERE serverID IN (:serverIDs)")
 | 
			
		||||
    void storeSongSyncModifyResponses(List<String> serverIDs, SyncStatus status, LocalDateTime currentTime);
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    void updateSong(MusicNote musicNote);
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM music_notes WHERE serverID IN (:serverIDs)")
 | 
			
		||||
    void deleteSongs(List<String> serverIDs);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM note_sheets ns WHERE ns.syncStatus = :status")
 | 
			
		||||
    List<NoteSheet> getNoteSheetsWithStatus(SyncStatus status);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT mn.serverID FROM music_notes mn WHERE mn.musicNoteId =:musicNoteId")
 | 
			
		||||
    Optional<String> getMusicNoteByLocalID(long musicNoteId);
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    void updateNoteSheet(NoteSheet noteSheet);
 | 
			
		||||
 | 
			
		||||
    @Transaction
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE) // oder andere Strategie je nach Bedarf
 | 
			
		||||
    void insertSyncDataObjects(List<SyncDataObject> syncDataObjects);
 | 
			
		||||
}
 | 
			
		||||
@ -1,56 +0,0 @@
 | 
			
		||||
package core.notevault.data;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity;
 | 
			
		||||
import androidx.room.PrimaryKey;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "note_sheets")
 | 
			
		||||
public class NoteSheet {
 | 
			
		||||
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private int id;
 | 
			
		||||
    private SyncStatus syncStatus;
 | 
			
		||||
    private long musicNoteId;
 | 
			
		||||
    private String filePath;
 | 
			
		||||
 | 
			
		||||
    public NoteSheet(long musicNoteID, String filePath) {
 | 
			
		||||
        this.musicNoteId = musicNoteID;
 | 
			
		||||
        this.filePath = filePath;
 | 
			
		||||
        this.syncStatus = SyncStatus.CREATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NoteSheet() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setId(int id) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public long getMusicNoteId() {
 | 
			
		||||
        return musicNoteId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setMusicNoteId(long musicNoteId) {
 | 
			
		||||
        this.musicNoteId = musicNoteId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getFilePath() {
 | 
			
		||||
        return filePath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFilePath(String filePath) {
 | 
			
		||||
        this.filePath = filePath;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SyncStatus getSyncStatus() {
 | 
			
		||||
        return syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSyncStatus(SyncStatus syncStatus) {
 | 
			
		||||
        this.syncStatus = syncStatus;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,49 +0,0 @@
 | 
			
		||||
package core.notevault.data.sync;
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity;
 | 
			
		||||
import androidx.room.Ignore;
 | 
			
		||||
import androidx.room.PrimaryKey;
 | 
			
		||||
import androidx.room.TypeConverters;
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "sync_data_objects")
 | 
			
		||||
@TypeConverters(SyncDataObjectTypeConverter.class)
 | 
			
		||||
public class SyncDataObject {
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    private int id;
 | 
			
		||||
 | 
			
		||||
    private String serverID;
 | 
			
		||||
    private SyncDataObjectType type;
 | 
			
		||||
 | 
			
		||||
    @Ignore
 | 
			
		||||
    public SyncDataObject(String serverID, SyncDataObjectType type) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
        this.type = type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SyncDataObject() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setId(int id) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerID() {
 | 
			
		||||
        return serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerID(String serverID) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SyncDataObjectType getType() {
 | 
			
		||||
        return type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setType(SyncDataObjectType type) {
 | 
			
		||||
        this.type = type;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
package core.notevault.data.sync;
 | 
			
		||||
 | 
			
		||||
public enum SyncDataObjectType {
 | 
			
		||||
    MUSIC_NOTE
 | 
			
		||||
}
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
package core.notevault.data.sync;
 | 
			
		||||
 | 
			
		||||
import androidx.room.TypeConverter;
 | 
			
		||||
 | 
			
		||||
public class SyncDataObjectTypeConverter {
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static SyncDataObjectType fromInt(int value) {
 | 
			
		||||
        return SyncDataObjectType.values()[value];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static int toInt(SyncDataObjectType objectType) {
 | 
			
		||||
        return objectType.ordinal();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
package core.notevault.data.sync;
 | 
			
		||||
 | 
			
		||||
public enum SyncStatus {
 | 
			
		||||
    CREATED,
 | 
			
		||||
    DELETED,
 | 
			
		||||
    MODIFIED,
 | 
			
		||||
    REMOTE_MODIFIED,
 | 
			
		||||
    SYNCED;
 | 
			
		||||
}
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
package core.notevault.data.sync;
 | 
			
		||||
 | 
			
		||||
import androidx.room.TypeConverter;
 | 
			
		||||
 | 
			
		||||
public class SyncStatusConverter {
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static SyncStatus fromInt(int value) {
 | 
			
		||||
        return SyncStatus.values()[value];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @TypeConverter
 | 
			
		||||
    public static int toInt(SyncStatus syncStatus) {
 | 
			
		||||
        return syncStatus.ordinal();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
package core.notevault.sync;
 | 
			
		||||
 | 
			
		||||
public interface APICallback {
 | 
			
		||||
 | 
			
		||||
    void onSuccess();
 | 
			
		||||
    void onError(String error);
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
package core.notevault.sync;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import core.notevault.sync.auth.AuthInterceptor;
 | 
			
		||||
import core.notevault.sync.auth.TokenManager;
 | 
			
		||||
import okhttp3.OkHttpClient;
 | 
			
		||||
import okhttp3.logging.HttpLoggingInterceptor;
 | 
			
		||||
import retrofit2.Retrofit;
 | 
			
		||||
import retrofit2.converter.gson.GsonConverterFactory;
 | 
			
		||||
 | 
			
		||||
public class ApiClient {
 | 
			
		||||
    private static Retrofit retrofit;
 | 
			
		||||
 | 
			
		||||
    public static Retrofit getRetrofitInstance(Context context) {
 | 
			
		||||
        if (retrofit == null) {
 | 
			
		||||
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
 | 
			
		||||
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
 | 
			
		||||
 | 
			
		||||
            TokenManager tokenManager = new TokenManager(context);
 | 
			
		||||
            OkHttpClient client = new OkHttpClient.Builder()
 | 
			
		||||
                    .addInterceptor(new AuthInterceptor(tokenManager))
 | 
			
		||||
                    .addInterceptor(loggingInterceptor)
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            retrofit = new Retrofit.Builder()
 | 
			
		||||
                    .baseUrl("http://192.168.178.30:8000/")
 | 
			
		||||
                    .client(client)
 | 
			
		||||
                    .addConverterFactory(GsonConverterFactory.create())
 | 
			
		||||
                    .build();
 | 
			
		||||
        }
 | 
			
		||||
        return retrofit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
package core.notevault.sync;
 | 
			
		||||
 | 
			
		||||
public class StatusResponse {
 | 
			
		||||
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    public String getStatus() {
 | 
			
		||||
        return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setStatus(String status) {
 | 
			
		||||
        this.status = status;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
package core.notevault.sync;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.work.Worker;
 | 
			
		||||
import androidx.work.WorkerParameters;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
 | 
			
		||||
import core.notevault.sync.synchronisation.*;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.SongSyncWorker;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class SyncWorker extends Worker{
 | 
			
		||||
    private SongSyncWorker songSyncWorker;
 | 
			
		||||
    public SyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
 | 
			
		||||
        super(context, workerParams);
 | 
			
		||||
        SyncService syncService = ApiClient.getRetrofitInstance(context).create(SyncService.class);
 | 
			
		||||
        MusicDatabase musicDatabase = MusicDatabase.getDatabase(context);
 | 
			
		||||
        this.songSyncWorker = new SongSyncWorker(syncService, musicDatabase.musicNoteDao(), context);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Result doWork() {
 | 
			
		||||
        try {
 | 
			
		||||
            songSyncWorker.syncSongCreations();
 | 
			
		||||
            songSyncWorker.syncSongModifications();
 | 
			
		||||
            songSyncWorker.syncSongDeletions();
 | 
			
		||||
            songSyncWorker.uploadNoteSheets();
 | 
			
		||||
            songSyncWorker.fetchModifiedSongs();
 | 
			
		||||
            return Result.success();
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return Result.failure();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,32 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth;
 | 
			
		||||
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import okhttp3.Interceptor;
 | 
			
		||||
import okhttp3.Request;
 | 
			
		||||
import okhttp3.Response;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public class AuthInterceptor implements Interceptor {
 | 
			
		||||
    private TokenManager tokenManager;
 | 
			
		||||
 | 
			
		||||
    public AuthInterceptor(TokenManager tokenManager) {
 | 
			
		||||
        this.tokenManager = tokenManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Response intercept(Chain chain) throws IOException {
 | 
			
		||||
        Request originalRequest = chain.request();
 | 
			
		||||
 | 
			
		||||
        String token = tokenManager.getToken();
 | 
			
		||||
        if (token == null) {
 | 
			
		||||
            return chain.proceed(originalRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Request authenticatedRequest = originalRequest.newBuilder()
 | 
			
		||||
                .header("Authorization", "Bearer " + token).build();
 | 
			
		||||
        return chain.proceed(authenticatedRequest);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,80 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import core.notevault.sync.APICallback;
 | 
			
		||||
import core.notevault.sync.ApiClient;
 | 
			
		||||
import core.notevault.sync.StatusResponse;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.LoginRequest;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.LoginResponse;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.RegisterRequest;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.RegisterResponse;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.Callback;
 | 
			
		||||
import retrofit2.Response;
 | 
			
		||||
 | 
			
		||||
public class AuthRepository {
 | 
			
		||||
    private final AuthService authService;
 | 
			
		||||
    private final TokenManager tokenManager;
 | 
			
		||||
 | 
			
		||||
    public AuthRepository(Context context) {
 | 
			
		||||
        this.authService = ApiClient.getRetrofitInstance(context).create(AuthService.class);
 | 
			
		||||
        this.tokenManager = new TokenManager(context);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void performLogin(String email, String password, APICallback callback) {
 | 
			
		||||
        LoginRequest loginRequest = new LoginRequest(email, password);
 | 
			
		||||
 | 
			
		||||
        authService.login(loginRequest).enqueue(new Callback<LoginResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
 | 
			
		||||
                if (response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    String token = response.body().getToken();
 | 
			
		||||
                    saveToken(token);
 | 
			
		||||
                    // Erfolgsrückmeldung an den Callback senden
 | 
			
		||||
                    callback.onSuccess();
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Fehlermeldung an den Callback senden
 | 
			
		||||
                    callback.onError("Login fehlgeschlagen. Überprüfe Benutzername und Passwort.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<LoginResponse> call, Throwable t) {
 | 
			
		||||
                // Netzwerkfehler an den Callback senden
 | 
			
		||||
                callback.onError("Netzwerkfehler: " + t.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void performRegistration(String email, String username, String password, APICallback callback) {
 | 
			
		||||
        RegisterRequest registerRequest = new RegisterRequest(username, password, email);
 | 
			
		||||
        authService.registration(registerRequest).enqueue(new Callback<StatusResponse>() {
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<StatusResponse> call, Response<StatusResponse> response) {
 | 
			
		||||
                if(response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    callback.onSuccess();
 | 
			
		||||
                } else {
 | 
			
		||||
                    callback.onError("Registration fehlgeschlagen. Überprüfe Benutzername und Passwort.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<StatusResponse> call, Throwable throwable) {
 | 
			
		||||
                callback.onError("Netzwerkfehler: " + throwable.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void saveToken(String token) {
 | 
			
		||||
        tokenManager.saveToken(token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getToken() {
 | 
			
		||||
        return tokenManager.getToken();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void logout() {
 | 
			
		||||
        tokenManager.clearToken();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth;
 | 
			
		||||
 | 
			
		||||
import core.notevault.sync.StatusResponse;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.LoginRequest;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.LoginResponse;
 | 
			
		||||
import core.notevault.sync.auth.apimodel.RegisterRequest;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.http.Body;
 | 
			
		||||
import retrofit2.http.Headers;
 | 
			
		||||
import retrofit2.http.POST;
 | 
			
		||||
 | 
			
		||||
public interface AuthService {
 | 
			
		||||
 | 
			
		||||
    @POST("/login/")
 | 
			
		||||
    Call<LoginResponse> login(@Body LoginRequest loginRequest);
 | 
			
		||||
 | 
			
		||||
    @POST("/register/")
 | 
			
		||||
    @Headers("Content-Type: application/json")
 | 
			
		||||
    Call<StatusResponse> registration(@Body RegisterRequest registerRequest);
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth;
 | 
			
		||||
 | 
			
		||||
public interface LoginCallback {
 | 
			
		||||
 | 
			
		||||
    void onSuccess();
 | 
			
		||||
    void onError(String error);
 | 
			
		||||
}
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
 | 
			
		||||
public class TokenManager {
 | 
			
		||||
    private static final String PREF_NAME = "app_preferences";
 | 
			
		||||
    private static final String KEY_TOKEN = "jwt_token";
 | 
			
		||||
 | 
			
		||||
    private SharedPreferences sharedPreferences;
 | 
			
		||||
 | 
			
		||||
    public TokenManager(Context context) {
 | 
			
		||||
        sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void saveToken(String token) {
 | 
			
		||||
        SharedPreferences.Editor editor = sharedPreferences.edit();
 | 
			
		||||
        editor.putString(KEY_TOKEN, token);
 | 
			
		||||
        editor.apply();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getToken() {
 | 
			
		||||
        return sharedPreferences.getString(KEY_TOKEN, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void clearToken() {
 | 
			
		||||
        SharedPreferences.Editor editor = sharedPreferences.edit();
 | 
			
		||||
        editor.remove(KEY_TOKEN);
 | 
			
		||||
        editor.apply();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth.apimodel;
 | 
			
		||||
 | 
			
		||||
public class LoginRequest {
 | 
			
		||||
    private String email;
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    public LoginRequest(String email, String password) {
 | 
			
		||||
        this.email = email;
 | 
			
		||||
        this.password = password;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,22 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth.apimodel;
 | 
			
		||||
 | 
			
		||||
public class LoginResponse {
 | 
			
		||||
    private String token;
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    public String getToken() {
 | 
			
		||||
        return token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setToken(String token) {
 | 
			
		||||
        this.token = token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getUsername() {
 | 
			
		||||
        return username;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsername(String username) {
 | 
			
		||||
        this.username = username;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth.apimodel;
 | 
			
		||||
 | 
			
		||||
public class RegisterRequest {
 | 
			
		||||
    private String username;
 | 
			
		||||
    private String email;
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    public RegisterRequest(String username, String password, String email) {
 | 
			
		||||
        this.username = username;
 | 
			
		||||
        this.password = password;
 | 
			
		||||
        this.email = email;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
package core.notevault.sync.auth.apimodel;
 | 
			
		||||
 | 
			
		||||
public class RegisterResponse {
 | 
			
		||||
 | 
			
		||||
    private String username;
 | 
			
		||||
    private String email;
 | 
			
		||||
 | 
			
		||||
    public RegisterResponse(String username, String email) {
 | 
			
		||||
        this.username = username;
 | 
			
		||||
        this.email = email;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public RegisterResponse() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getUsername() {
 | 
			
		||||
        return username;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUsername(String username) {
 | 
			
		||||
        this.username = username;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getEmail() {
 | 
			
		||||
        return email;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setEmail(String email) {
 | 
			
		||||
        this.email = email;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
public class FetchRequest {
 | 
			
		||||
    private LocalDateTime client_last_sync;
 | 
			
		||||
 | 
			
		||||
    public FetchRequest(LocalDateTime client_last_sync) {
 | 
			
		||||
        this.client_last_sync = client_last_sync;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LocalDateTime getClient_last_sync() {
 | 
			
		||||
        return client_last_sync;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setClient_last_sync(LocalDateTime client_last_sync) {
 | 
			
		||||
        this.client_last_sync = client_last_sync;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class FetchResponse {
 | 
			
		||||
    private List<String> serverIDs;
 | 
			
		||||
 | 
			
		||||
    public FetchResponse(List<String> serverIDs) {
 | 
			
		||||
        this.serverIDs = serverIDs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getServerIDs() {
 | 
			
		||||
        return serverIDs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerIDs(List<String> serverIDs) {
 | 
			
		||||
        this.serverIDs = serverIDs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,36 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.deletion.SongDeletionBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.deletion.SongDeletionBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.modification.SongModificationBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.modification.SongModificationBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.notesheets.UploadResponse;
 | 
			
		||||
import okhttp3.MultipartBody;
 | 
			
		||||
import okhttp3.RequestBody;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.http.*;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
public interface SyncService {
 | 
			
		||||
 | 
			
		||||
    @POST("/sync/songs/create")
 | 
			
		||||
    Call<SongCreationBatchResponse> performSongCreation(@Body SongCreationBatchRequest syncRequest);
 | 
			
		||||
 | 
			
		||||
    @POST("/sync/songs/modify")
 | 
			
		||||
    Call<SongModificationBatchResponse> performSongModification(@Body SongModificationBatchRequest syncRequest);
 | 
			
		||||
 | 
			
		||||
    @POST("/sync/songs/delete")
 | 
			
		||||
    Call<SongDeletionBatchResponse> performSongDeletion(@Body SongDeletionBatchRequest syncRequest);
 | 
			
		||||
 | 
			
		||||
    @Multipart
 | 
			
		||||
    @POST("/sync/songs/note_sheet/upload")
 | 
			
		||||
    Call<UploadResponse> uploadNoteSheet(@Part("serverID") RequestBody serverID, @Part("fileName") RequestBody fileName,
 | 
			
		||||
                                         @Part MultipartBody.Part image);
 | 
			
		||||
 | 
			
		||||
    @GET("/sync/songs/fetch")
 | 
			
		||||
    Call<FetchResponse> fetchModifiedSongs(@Query("last_client_sync") LocalDateTime last_client_sync);
 | 
			
		||||
}
 | 
			
		||||
@ -1,199 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.data.NoteSheet;
 | 
			
		||||
import core.notevault.data.sync.SyncDataObject;
 | 
			
		||||
import core.notevault.data.sync.SyncDataObjectType;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
import core.notevault.sync.synchronisation.FetchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.FetchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.SyncService;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.creation.SongCreationRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.deletion.SongDeletionBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.deletion.SongDeletionBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.modification.SongModificationBatchRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.modification.SongModificationBatchResponse;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.modification.SongModificationRequest;
 | 
			
		||||
import core.notevault.sync.synchronisation.songs.notesheets.UploadResponse;
 | 
			
		||||
import okhttp3.MediaType;
 | 
			
		||||
import okhttp3.MultipartBody;
 | 
			
		||||
import okhttp3.RequestBody;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.Callback;
 | 
			
		||||
import retrofit2.Response;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
public class SongSyncWorker {
 | 
			
		||||
    private SyncService syncService;
 | 
			
		||||
    private MusicNoteDAO database;
 | 
			
		||||
    private Context context;
 | 
			
		||||
    private ExecutorService executorService = Executors.newSingleThreadExecutor();
 | 
			
		||||
 | 
			
		||||
    public SongSyncWorker(SyncService syncService, MusicNoteDAO database, Context context) {
 | 
			
		||||
        this.syncService = syncService;
 | 
			
		||||
        this.database = database;
 | 
			
		||||
        this.context = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SongCreationBatchRequest buildCreationRequest() {
 | 
			
		||||
        List<MusicNote> created_songs = database.getSongsWithSyncStatus(SyncStatus.CREATED);
 | 
			
		||||
        List<SongCreationRequest> songCreationRequests = new ArrayList<>();
 | 
			
		||||
        for(MusicNote musicNote : created_songs) {
 | 
			
		||||
            songCreationRequests.add(new SongCreationRequest(musicNote.getMusicNoteId(), musicNote.getTitle(), musicNote.getComposer(), musicNote.getGenre(), musicNote.getYear()));
 | 
			
		||||
        }
 | 
			
		||||
        return new SongCreationBatchRequest(songCreationRequests);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void syncSongCreations() {
 | 
			
		||||
        SongCreationBatchRequest request = buildCreationRequest();
 | 
			
		||||
        syncService.performSongCreation(request).enqueue(new Callback<SongCreationBatchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<SongCreationBatchResponse> call, Response<SongCreationBatchResponse> response) {
 | 
			
		||||
                if(response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    executorService.execute(() -> {
 | 
			
		||||
                        database.storeSongSyncResponses(response.body().getSongs());
 | 
			
		||||
                    });
 | 
			
		||||
                } else {
 | 
			
		||||
                    Toast.makeText(context, "Song creation failed", Toast.LENGTH_LONG).show();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<SongCreationBatchResponse> call, Throwable throwable) {
 | 
			
		||||
                Toast.makeText(context, "Song creation failed", Toast.LENGTH_LONG).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SongModificationBatchRequest buildModificationRequest() {
 | 
			
		||||
        List<MusicNote> modified_songs = database.getSongsWithSyncStatus(SyncStatus.MODIFIED);
 | 
			
		||||
        List<SongModificationRequest> songModificationRequests = new ArrayList<>();
 | 
			
		||||
        for(MusicNote musicNote : modified_songs) {
 | 
			
		||||
            songModificationRequests.add(new SongModificationRequest(musicNote.getServerID(), musicNote.getTitle(), musicNote.getComposer(), musicNote.getGenre(), musicNote.getYear()));
 | 
			
		||||
        }
 | 
			
		||||
        return new SongModificationBatchRequest(songModificationRequests);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void syncSongModifications() {
 | 
			
		||||
        SongModificationBatchRequest request = buildModificationRequest();
 | 
			
		||||
        syncService.performSongModification(request).enqueue(new Callback<SongModificationBatchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<SongModificationBatchResponse> call, Response<SongModificationBatchResponse> response) {
 | 
			
		||||
                executorService.execute(() -> {
 | 
			
		||||
                    database.storeSongSyncModifyResponses(response.body().getUpdated_songs(), SyncStatus.SYNCED, LocalDateTime.now());
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<SongModificationBatchResponse> call, Throwable throwable) {
 | 
			
		||||
                Toast.makeText(context, "Sync of Modified Songs failed", Toast.LENGTH_LONG).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private SongDeletionBatchRequest buildDeletionBatchRequest() {
 | 
			
		||||
        List<MusicNote> deleted_songs = database.getSongsWithSyncStatus(SyncStatus.DELETED);
 | 
			
		||||
        List<String> deleted_song_ids = deleted_songs.stream().map(MusicNote::getServerID).collect(Collectors.toList());
 | 
			
		||||
        return new SongDeletionBatchRequest(deleted_song_ids);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void syncSongDeletions() {
 | 
			
		||||
        SongDeletionBatchRequest request = buildDeletionBatchRequest();
 | 
			
		||||
        syncService.performSongDeletion(request).enqueue(new Callback<SongDeletionBatchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<SongDeletionBatchResponse> call, Response<SongDeletionBatchResponse> response) {
 | 
			
		||||
                if(response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    executorService.execute(() -> {
 | 
			
		||||
                        database.deleteSongs(response.body().getDeletedSongs());
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<SongDeletionBatchResponse> call, Throwable throwable) {
 | 
			
		||||
                Toast.makeText(context, "Sync of Deleted Songs failed", Toast.LENGTH_LONG).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void uploadNoteSheets() {
 | 
			
		||||
        List<NoteSheet> noteSheets = database.getNoteSheetsWithStatus(SyncStatus.CREATED);
 | 
			
		||||
        for(NoteSheet noteSheet : noteSheets) {
 | 
			
		||||
            Optional<String> serverID = database.getMusicNoteByLocalID(noteSheet.getMusicNoteId());
 | 
			
		||||
 | 
			
		||||
            if(serverID.isPresent()) {
 | 
			
		||||
                File imageFile = new File(noteSheet.getFilePath());
 | 
			
		||||
                // Erstelle Request-Bodies für serverID und fileName
 | 
			
		||||
                RequestBody serverIDBody = RequestBody.create(MediaType.parse("text/plain"), serverID.get());
 | 
			
		||||
                RequestBody fileNameBody = RequestBody.create(MediaType.parse("text/plain"), imageFile.getName());
 | 
			
		||||
 | 
			
		||||
                // Erstelle den Multipart-Body für die Bilddatei
 | 
			
		||||
                RequestBody imageRequestBody = RequestBody.create(MediaType.parse("image/*"), imageFile);
 | 
			
		||||
                MultipartBody.Part imagePart = MultipartBody.Part.createFormData("image", imageFile.getName(), imageRequestBody);
 | 
			
		||||
 | 
			
		||||
                syncService.uploadNoteSheet(serverIDBody, fileNameBody, imagePart).enqueue(new Callback<UploadResponse>() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onResponse(Call<UploadResponse> call, Response<UploadResponse> response) {
 | 
			
		||||
                        if (response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                            // Erfolg: Antwort verarbeiten
 | 
			
		||||
                            Toast.makeText(context, "Upload erfolgreich", Toast.LENGTH_LONG).show();
 | 
			
		||||
                            executorService.execute(() -> {
 | 
			
		||||
                                noteSheet.setSyncStatus(SyncStatus.SYNCED);
 | 
			
		||||
                                database.updateNoteSheet(noteSheet);
 | 
			
		||||
                            });
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Fehler: Antwort prüfen
 | 
			
		||||
                            Toast.makeText(context, "Fehler beim Upload: " + response.code(), Toast.LENGTH_LONG).show();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onFailure(Call<UploadResponse> call, Throwable throwable) {
 | 
			
		||||
                        Toast.makeText(context, "Fehler beim Upload: " + throwable.toString(), Toast.LENGTH_LONG).show();
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void fetchModifiedSongs() {
 | 
			
		||||
        FetchRequest request = new FetchRequest(LocalDateTime.MIN);
 | 
			
		||||
 | 
			
		||||
        syncService.fetchModifiedSongs(LocalDateTime.MIN).enqueue(new Callback<FetchResponse>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onResponse(Call<FetchResponse> call, Response<FetchResponse> response) {
 | 
			
		||||
                if(response.isSuccessful() && response.body() != null) {
 | 
			
		||||
                    executorService.execute(() -> {
 | 
			
		||||
                        List<SyncDataObject> syncDataObjects = new ArrayList<>();
 | 
			
		||||
                        for(String serverID: response.body().getServerIDs()) {
 | 
			
		||||
                            syncDataObjects.add(new SyncDataObject(serverID, SyncDataObjectType.MUSIC_NOTE));
 | 
			
		||||
                        }
 | 
			
		||||
                        database.insertSyncDataObjects(syncDataObjects);
 | 
			
		||||
                    });
 | 
			
		||||
                } else {
 | 
			
		||||
                    Toast.makeText(context, "Fehler beim Fetch: " + response.code(), Toast.LENGTH_LONG).show();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Call<FetchResponse> call, Throwable throwable) {
 | 
			
		||||
                Toast.makeText(context, "Fehler beim Fetch: " + throwable.getMessage(), Toast.LENGTH_LONG).show();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.creation;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongCreationBatchRequest {
 | 
			
		||||
    private List<SongCreationRequest> songs;
 | 
			
		||||
 | 
			
		||||
    public SongCreationBatchRequest(List<SongCreationRequest> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.creation;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongCreationBatchResponse {
 | 
			
		||||
    private List<SongCreationResponse> songs;
 | 
			
		||||
 | 
			
		||||
    public SongCreationBatchResponse(List<SongCreationResponse> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<SongCreationResponse> getSongs() {
 | 
			
		||||
        return songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSongs(List<SongCreationResponse> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.creation;
 | 
			
		||||
 | 
			
		||||
public class SongCreationRequest {
 | 
			
		||||
    private long localID;
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String composer;
 | 
			
		||||
    private String genre;
 | 
			
		||||
    private int year;
 | 
			
		||||
 | 
			
		||||
    public SongCreationRequest(long localID, String title, String composer, String genre, int year) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
        this.year = year;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.creation;
 | 
			
		||||
 | 
			
		||||
public class SongCreationResponse {
 | 
			
		||||
    private int localID;
 | 
			
		||||
    private String serverID;
 | 
			
		||||
 | 
			
		||||
    public SongCreationResponse(int localID, String serverID) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getLocalID() {
 | 
			
		||||
        return localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLocalID(int localID) {
 | 
			
		||||
        this.localID = localID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerID() {
 | 
			
		||||
        return serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerID(String serverID) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.deletion;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongDeletionBatchRequest {
 | 
			
		||||
    private List<String> songs;
 | 
			
		||||
 | 
			
		||||
    public SongDeletionBatchRequest(List<String> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getSongs() {
 | 
			
		||||
        return songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSongs(List<String> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.deletion;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongDeletionBatchResponse {
 | 
			
		||||
    private List<String> deletedSongs;
 | 
			
		||||
 | 
			
		||||
    public SongDeletionBatchResponse(List<String> deletedSongs) {
 | 
			
		||||
        this.deletedSongs = deletedSongs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getDeletedSongs() {
 | 
			
		||||
        return deletedSongs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setDeletedSongs(List<String> deletedSongs) {
 | 
			
		||||
        this.deletedSongs = deletedSongs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.modification;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongModificationBatchRequest {
 | 
			
		||||
    private List<SongModificationRequest> songs;
 | 
			
		||||
 | 
			
		||||
    public SongModificationBatchRequest(List<SongModificationRequest> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.modification;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SongModificationBatchResponse {
 | 
			
		||||
    private List<String> songs;
 | 
			
		||||
 | 
			
		||||
    public SongModificationBatchResponse(List<String> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getUpdated_songs() {
 | 
			
		||||
        return songs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUpdated_songs(List<String> updated_songs) {
 | 
			
		||||
        this.songs = updated_songs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,57 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.modification;
 | 
			
		||||
 | 
			
		||||
public class SongModificationRequest {
 | 
			
		||||
    private String serverID;
 | 
			
		||||
    private String title;
 | 
			
		||||
    private String composer;
 | 
			
		||||
    private String genre;
 | 
			
		||||
    private int year;
 | 
			
		||||
 | 
			
		||||
    public SongModificationRequest(String serverID, String title, String composer, String genre, int year) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
        this.title = title;
 | 
			
		||||
        this.composer = composer;
 | 
			
		||||
        this.genre = genre;
 | 
			
		||||
        this.year = year;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getServerID() {
 | 
			
		||||
        return serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setServerID(String serverID) {
 | 
			
		||||
        this.serverID = serverID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTitle() {
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTitle(String title) {
 | 
			
		||||
        this.title = title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
package core.notevault.sync.synchronisation.songs.notesheets;
 | 
			
		||||
 | 
			
		||||
public class UploadResponse {
 | 
			
		||||
    private String serverID;
 | 
			
		||||
}
 | 
			
		||||
@ -1,86 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.ImageButton;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.Concert;
 | 
			
		||||
import core.notevault.ui.home.NoteSongAdapter;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ConcertAdapter extends RecyclerView.Adapter<ConcertAdapter.ConcertViewHolder> {
 | 
			
		||||
 | 
			
		||||
    private final List<Concert> concertList;
 | 
			
		||||
    private final OnConcertClickListener concertClickListener;
 | 
			
		||||
 | 
			
		||||
    public interface OnConcertClickListener {
 | 
			
		||||
        void onDeleteConcert(Concert concert);
 | 
			
		||||
        void onOpenConcertEditor(Concert concert);
 | 
			
		||||
        void onConcertClick(Concert concert);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public ConcertAdapter(List<Concert> concertList, OnConcertClickListener concertClickListener) {
 | 
			
		||||
        this.concertList = concertList;
 | 
			
		||||
        this.concertClickListener = concertClickListener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ConcertAdapter(OnConcertClickListener onConcertClickListener) {
 | 
			
		||||
        this.concertClickListener = onConcertClickListener;
 | 
			
		||||
        this.concertList = new ArrayList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull ConcertViewHolder holder, int position) {
 | 
			
		||||
        holder.concertTitleView.setText(concertList.get(position).getTitle());
 | 
			
		||||
        holder.dateHolder.setText(concertList.get(position).getConcertDate());
 | 
			
		||||
 | 
			
		||||
        holder.deleteButton.setOnClickListener(v -> concertClickListener.onDeleteConcert(concertList.get(position)));
 | 
			
		||||
        holder.editButton.setOnClickListener(v -> concertClickListener.onOpenConcertEditor(concertList.get(position)));
 | 
			
		||||
        holder.itemView.setOnClickListener(v -> concertClickListener.onConcertClick(concertList.get(position)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return concertList.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ConcertViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(parent.getContext())
 | 
			
		||||
                .inflate(R.layout.concert_item, parent, false);
 | 
			
		||||
        return new ConcertViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateConcerts(List<Concert> concerts) {
 | 
			
		||||
        Log.d("ConcertAdapter", "Update Concerts: " + this.concertList.size() + "vs new: " + concerts.size());
 | 
			
		||||
        this.concertList.clear();
 | 
			
		||||
        this.concertList.addAll(concerts);
 | 
			
		||||
        notifyDataSetChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ConcertViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView concertTitleView;
 | 
			
		||||
        TextView dateHolder;
 | 
			
		||||
 | 
			
		||||
        ImageButton deleteButton;
 | 
			
		||||
        ImageButton editButton;
 | 
			
		||||
 | 
			
		||||
        public ConcertViewHolder(@NonNull @NotNull View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            concertTitleView = itemView.findViewById(R.id.concert_title);
 | 
			
		||||
            dateHolder = itemView.findViewById(R.id.concert_date);
 | 
			
		||||
            deleteButton = itemView.findViewById(R.id.delete_concert_button);
 | 
			
		||||
            editButton = itemView.findViewById(R.id.edit_concert_button);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,153 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery;
 | 
			
		||||
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.Looper;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
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 androidx.navigation.NavController;
 | 
			
		||||
import androidx.navigation.NavDirections;
 | 
			
		||||
import androidx.navigation.Navigation;
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration;
 | 
			
		||||
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.Concert;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.databinding.FragmentGalleryBinding;
 | 
			
		||||
import core.notevault.ui.gallery.editor.ConcertEditorDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class GalleryFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    private FragmentGalleryBinding binding;
 | 
			
		||||
    private ConcertAdapter concertAdapter;
 | 
			
		||||
    private GalleryViewModel galleryViewModel;
 | 
			
		||||
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater,
 | 
			
		||||
                             ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        galleryViewModel =
 | 
			
		||||
                new ViewModelProvider(this).get(GalleryViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentGalleryBinding.inflate(inflater, container, false);
 | 
			
		||||
        View root = binding.getRoot();
 | 
			
		||||
 | 
			
		||||
        RecyclerView recyclerView = root.findViewById(R.id.concert_recycler_view);
 | 
			
		||||
        concertAdapter = new ConcertAdapter(new ConcertAdapter.OnConcertClickListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onDeleteConcert(Concert concert) {
 | 
			
		||||
                deleteConcert(concert);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onOpenConcertEditor(Concert concert) {
 | 
			
		||||
                editConcert(concert);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onConcertClick(Concert concert) {
 | 
			
		||||
                Log.d("GalleryFragment", "Clicked on Concert: " + concert.getTitle());
 | 
			
		||||
                Bundle bundle = new Bundle();
 | 
			
		||||
                bundle.putInt("concertID", concert.getId());
 | 
			
		||||
                bundle.putString("concertTitle", concert.getTitle());
 | 
			
		||||
                bundle.putString("concertDate", concert.getConcertDate());
 | 
			
		||||
 | 
			
		||||
                NavController navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment_content_main);
 | 
			
		||||
                navController.navigate(R.id.concertDetailFragment, bundle);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        recyclerView.setAdapter(concertAdapter);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
 | 
			
		||||
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), LinearLayoutManager.VERTICAL);
 | 
			
		||||
        recyclerView.addItemDecoration(dividerItemDecoration);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        FloatingActionButton addConcertBtn = root.findViewById(R.id.add_concert_btn);
 | 
			
		||||
        addConcertBtn.setOnClickListener(v -> onCreateNewConcert());
 | 
			
		||||
 | 
			
		||||
        galleryViewModel.getConcerts().observe(getViewLifecycleOwner(), newConcerts -> {
 | 
			
		||||
            concertAdapter.updateConcerts(newConcerts);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        new LoadConcerts().execute();
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteConcert(Concert concert) {
 | 
			
		||||
        Log.d("GalleryFragment", "Delete Concert");
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            MusicDatabase musicDatabase = MusicDatabase.getDatabase(this.getContext());
 | 
			
		||||
            MusicNoteDAO musicNoteDAO = musicDatabase.musicNoteDao();
 | 
			
		||||
            musicNoteDAO.deleteConcert(concert);
 | 
			
		||||
 | 
			
		||||
            new Handler(Looper.getMainLooper()).post(() -> {
 | 
			
		||||
                galleryViewModel.deleteConcert(concert);
 | 
			
		||||
                Log.d("GalleryFragment", "Concert deleted successfully and ViewModel updated");
 | 
			
		||||
            });
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void editConcert(Concert concert) {
 | 
			
		||||
        ConcertEditorDialog concertEditorDialog = new ConcertEditorDialog();
 | 
			
		||||
 | 
			
		||||
        Bundle args = new Bundle();
 | 
			
		||||
        args.putString("concert_title", concert.getTitle());
 | 
			
		||||
        args.putString("concert_date", concert.getConcertDate());
 | 
			
		||||
        args.putInt("concertID", concert.getId());
 | 
			
		||||
 | 
			
		||||
        concertEditorDialog.setArguments(args);
 | 
			
		||||
 | 
			
		||||
        concertEditorDialog.show(getParentFragmentManager(), ConcertEditorDialog.TAG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateConcert(Concert concert) {
 | 
			
		||||
        galleryViewModel.updateConcert(concert);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class LoadConcerts extends AsyncTask<Void, Void, List<Concert>> {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected List<Concert> doInBackground(Void... voids) {
 | 
			
		||||
            MusicDatabase db = MusicDatabase.getDatabase(getContext());
 | 
			
		||||
            MusicNoteDAO musicNoteDAO = db.musicNoteDao();
 | 
			
		||||
            List<Concert> concerts =  musicNoteDAO.getAllConcerts();
 | 
			
		||||
            Log.d("GalleryFragment", "Fetching concerts: " + concerts.size());
 | 
			
		||||
            return concerts;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void onPostExecute(List<Concert> concerts) {
 | 
			
		||||
            Log.d("GalleryFragment", "Concerts size in onPostExecute: " + concerts.size());
 | 
			
		||||
            // concertAdapter.updateConcerts(concerts); // Aktualisiere den Adapter mit den Titeln
 | 
			
		||||
            galleryViewModel.setConcerts(concerts);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onCreateNewConcert() {
 | 
			
		||||
        ConcertEditorDialog concertEditorDialog = new ConcertEditorDialog();
 | 
			
		||||
        concertEditorDialog.show(getParentFragmentManager(), ConcertEditorDialog.TAG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addConcert(Concert concert) {
 | 
			
		||||
        this.galleryViewModel.addConcert(concert);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
import core.notevault.data.Concert;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class GalleryViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<List<Concert>> concerts;
 | 
			
		||||
 | 
			
		||||
    public GalleryViewModel() {
 | 
			
		||||
       this.concerts = new MutableLiveData<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public LiveData<List<Concert>> getConcerts() {
 | 
			
		||||
        return concerts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setConcerts(List<Concert> concerts) {
 | 
			
		||||
        this.concerts.setValue(concerts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addConcert(Concert concert) {
 | 
			
		||||
        List<Concert> currentConcerts = this.concerts.getValue();
 | 
			
		||||
        Log.d("GalleryViewModel", "Add Concert");
 | 
			
		||||
        if(currentConcerts != null) {
 | 
			
		||||
            currentConcerts.add(concert);
 | 
			
		||||
            concerts.setValue(currentConcerts);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteConcert(Concert concert) {
 | 
			
		||||
        List<Concert> currentConcerts = concerts.getValue();
 | 
			
		||||
        if(currentConcerts != null) {
 | 
			
		||||
            currentConcerts.remove(concert);
 | 
			
		||||
            concerts.setValue(currentConcerts);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateConcert(Concert concert) {
 | 
			
		||||
        List<Concert> currentConcerts = concerts.getValue();
 | 
			
		||||
        if(currentConcerts != null) {
 | 
			
		||||
            for(int i = 0; i < currentConcerts.size(); i++) {
 | 
			
		||||
                if(currentConcerts.get(i).getId() == concert.getId()) {
 | 
			
		||||
                    currentConcerts.get(i).setTitle(concert.getTitle());
 | 
			
		||||
                    currentConcerts.get(i).setConcertDate(concert.getConcertDate());
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            concerts.setValue(currentConcerts);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,119 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery.detail;
 | 
			
		||||
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.lifecycle.ViewModelProvider;
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import androidx.room.util.ViewInfo;
 | 
			
		||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
 | 
			
		||||
import core.notevault.data.Concert;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.databinding.FragmentConcertDetailBinding;
 | 
			
		||||
import core.notevault.ui.home.NoteSongAdapter;
 | 
			
		||||
import core.notevault.ui.metadatadialog.SongEditDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ConcertDetailFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    public interface OnConcertSongsLoadedListener {
 | 
			
		||||
        void onSongsLoaded(List<MusicNote> songs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private FragmentConcertDetailBinding binding;
 | 
			
		||||
    private Concert concert;
 | 
			
		||||
    private ConcertDetailViewModel concertDetailViewModel;
 | 
			
		||||
    private NoteSongAdapter noteSongAdapter;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 | 
			
		||||
        concertDetailViewModel = new ViewModelProvider(this).get(ConcertDetailViewModel.class);
 | 
			
		||||
 | 
			
		||||
        binding = FragmentConcertDetailBinding.inflate(inflater, container, false);
 | 
			
		||||
        int concertId = getArguments().getInt("concertID");
 | 
			
		||||
        String concertTitle = getArguments().getString("concertTitle");
 | 
			
		||||
        String concertDate = getArguments().getString("concertDate");
 | 
			
		||||
        concert = new Concert(concertId, concertTitle, concertDate);
 | 
			
		||||
 | 
			
		||||
        binding.textConcertDetailsTitle.setText(concertTitle);
 | 
			
		||||
        binding.textConcertDetailsDate.setText(concertDate);
 | 
			
		||||
 | 
			
		||||
        RecyclerView recyclerView = binding.noteRecyclerView;
 | 
			
		||||
        noteSongAdapter = new NoteSongAdapter(this::deleteSongFromConcert, this::editSongFromConcert);
 | 
			
		||||
        recyclerView.setAdapter(noteSongAdapter);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
 | 
			
		||||
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), LinearLayoutManager.VERTICAL);
 | 
			
		||||
        recyclerView.addItemDecoration(dividerItemDecoration);
 | 
			
		||||
 | 
			
		||||
        FloatingActionButton fab = binding.addSongConcert;
 | 
			
		||||
        fab.setOnClickListener(view -> {
 | 
			
		||||
            ConcertSongSelector concertSongSelector = new ConcertSongSelector();
 | 
			
		||||
 | 
			
		||||
            Bundle bundle = new Bundle();
 | 
			
		||||
            bundle.putString("concertTitle", concertTitle);
 | 
			
		||||
            bundle.putString("concertDate", concertDate);
 | 
			
		||||
            bundle.putInt("concertID", concertId);
 | 
			
		||||
 | 
			
		||||
            concertSongSelector.setArguments(bundle);
 | 
			
		||||
 | 
			
		||||
            concertSongSelector.show(getParentFragmentManager(), ConcertSongSelector.TAG);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        concertDetailViewModel.getConcertSongs().observe(getViewLifecycleOwner(), songs -> {
 | 
			
		||||
            noteSongAdapter.updateSongTitles(songs);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        new LoadConcertSongsTask(concertId, songs -> {
 | 
			
		||||
            this.concertDetailViewModel.setConcertSongs(songs);
 | 
			
		||||
        }).execute();
 | 
			
		||||
 | 
			
		||||
        return binding.getRoot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void deleteSongFromConcert(MusicNote musicNote) {
 | 
			
		||||
        this.concertDetailViewModel.deleteConcertSong(musicNote);
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            MusicNoteDAO musicNoteDAO = MusicDatabase.getDatabase(getContext()).musicNoteDao();
 | 
			
		||||
            musicNoteDAO.deleteConcertSong(musicNote.getMusicNoteId(), concert.getId());
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void editSongFromConcert(MusicNote musicNote) {
 | 
			
		||||
        SongEditDialog songEditDialog = new SongEditDialog();
 | 
			
		||||
        songEditDialog.setSong(musicNote);
 | 
			
		||||
        songEditDialog.show(getParentFragmentManager(), SongEditDialog.TAG);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class LoadConcertSongsTask extends AsyncTask<Void, Void, List<MusicNote>> {
 | 
			
		||||
        private final int concertID;
 | 
			
		||||
        private final OnConcertSongsLoadedListener listener;
 | 
			
		||||
 | 
			
		||||
        public LoadConcertSongsTask(int concertID, OnConcertSongsLoadedListener listener) {
 | 
			
		||||
            this.concertID = concertID;
 | 
			
		||||
            this.listener = listener;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected List<MusicNote> doInBackground(Void... voids) {
 | 
			
		||||
            MusicDatabase db = MusicDatabase.getDatabase(getContext());
 | 
			
		||||
            return db.musicNoteDao().getAllMusicNotesOfConcert(concertID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void onPostExecute(List<MusicNote> songs) {
 | 
			
		||||
            Log.d("ConcertDetailFragment", "Loaded Concertsongs: " + songs.size());
 | 
			
		||||
            listener.onSongsLoaded(songs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery.detail;
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData;
 | 
			
		||||
import androidx.lifecycle.MutableLiveData;
 | 
			
		||||
import androidx.lifecycle.ViewModel;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ConcertDetailViewModel extends ViewModel {
 | 
			
		||||
    private final MutableLiveData<List<MusicNote>> concertSongs;
 | 
			
		||||
 | 
			
		||||
    public ConcertDetailViewModel() {
 | 
			
		||||
        this.concertSongs = new MutableLiveData<>(new ArrayList<>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<List<MusicNote>> getConcertSongs() {
 | 
			
		||||
        return concertSongs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setConcertSongs(List<MusicNote> concertSongs) {
 | 
			
		||||
       this.concertSongs.setValue(concertSongs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteConcertSong(MusicNote note) {
 | 
			
		||||
        List<MusicNote> currentConcertSongs = concertSongs.getValue();
 | 
			
		||||
        if(currentConcertSongs != null) {
 | 
			
		||||
            currentConcertSongs.remove(note);
 | 
			
		||||
            this.concertSongs.setValue(currentConcertSongs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addConcertSongs(List<MusicNote> concertSongs) {
 | 
			
		||||
        List<MusicNote> currentConcertSongs = this.concertSongs.getValue();
 | 
			
		||||
        if(currentConcertSongs != null) {
 | 
			
		||||
            currentConcertSongs.addAll(concertSongs);
 | 
			
		||||
            this.concertSongs.setValue(currentConcertSongs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,116 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery.detail;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.SearchView;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.DialogFragment;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.ConcertSong;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ConcertSongSelector extends DialogFragment {
 | 
			
		||||
 | 
			
		||||
    private ConcertSongSelectorAdapter adapter;
 | 
			
		||||
    private OnSongSelectedListener listener;
 | 
			
		||||
    private int concertID;
 | 
			
		||||
 | 
			
		||||
    public interface OnSongSelectedListener {
 | 
			
		||||
        void onSongsSelected(List<MusicNote> songs, int concertID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(Bundle savedInstanceState) {
 | 
			
		||||
        LayoutInflater inflater = getActivity().getLayoutInflater();
 | 
			
		||||
        View dialogView = inflater.inflate(R.layout.dialog_concert_song_selector, null);
 | 
			
		||||
 | 
			
		||||
        String concertTitle = getArguments().getString("concertTitle");
 | 
			
		||||
        String concertDate = getArguments().getString("concertDate");
 | 
			
		||||
        concertID = getArguments().getInt("concertID");
 | 
			
		||||
 | 
			
		||||
        TextView dialogTitle = dialogView.findViewById(R.id.dialog_title_concert_song_selector);
 | 
			
		||||
        dialogTitle.setText("Wähle Stücke für das Konzert '" + concertTitle + "' am " + concertDate + " aus");
 | 
			
		||||
 | 
			
		||||
        RecyclerView recyclerView = dialogView.findViewById(R.id.concert_song_selector_recycler);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        adapter = new ConcertSongSelectorAdapter(new ArrayList<>());
 | 
			
		||||
        recyclerView.setAdapter(adapter);
 | 
			
		||||
 | 
			
		||||
        SearchView searchView = dialogView.findViewById(R.id.search_view);
 | 
			
		||||
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextSubmit(String s) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean onQueryTextChange(String s) {
 | 
			
		||||
                adapter.filter(s);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        fetchAllSongs();
 | 
			
		||||
 | 
			
		||||
        return new AlertDialog.Builder(requireContext())
 | 
			
		||||
                .setView(dialogView)
 | 
			
		||||
                .setPositiveButton("Speichern", (dialog, which) -> {
 | 
			
		||||
                    List<MusicNote> selectedSongs = adapter.getSelectedSongs();
 | 
			
		||||
                    listener.onSongsSelected(selectedSongs, concertID);
 | 
			
		||||
                })
 | 
			
		||||
                .setNegativeButton("Abbrechen", (dialog, which) -> {} )
 | 
			
		||||
                .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAttach(@NonNull Context context) {
 | 
			
		||||
        super.onAttach(context);
 | 
			
		||||
        if (context instanceof ConcertSongSelector.OnSongSelectedListener) {
 | 
			
		||||
            listener = (ConcertSongSelector.OnSongSelectedListener) context;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException(context.toString()
 | 
			
		||||
                    + " must implement OnMetadataListener");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void fetchAllSongs() {
 | 
			
		||||
        // Ersetze dies durch das Laden der Songs aus der Datenbank oder einer anderen Quelle
 | 
			
		||||
        new LoadSongTitlesTask().execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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> songs) {
 | 
			
		||||
            adapter.setSongs(songs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String TAG = "ConcertSongSelector";
 | 
			
		||||
}
 | 
			
		||||
@ -1,90 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery.detail;
 | 
			
		||||
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.CheckBox;
 | 
			
		||||
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 ConcertSongSelectorAdapter extends RecyclerView.Adapter<ConcertSongSelectorAdapter.ConcertSongSelectorViewHolder> {
 | 
			
		||||
    private List<MusicNote> songs;
 | 
			
		||||
    private List<MusicNote> selectedSongs = new ArrayList<>();
 | 
			
		||||
    private List<MusicNote> filteredSongs;
 | 
			
		||||
 | 
			
		||||
    public ConcertSongSelectorAdapter(List<MusicNote> songs) {
 | 
			
		||||
        this.songs = songs;
 | 
			
		||||
        this.filteredSongs = new ArrayList<>(songs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ConcertSongSelectorViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(parent.getContext())
 | 
			
		||||
                .inflate(R.layout.item_concert_song, parent, false);
 | 
			
		||||
        return new ConcertSongSelectorViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull ConcertSongSelectorViewHolder holder, int position) {
 | 
			
		||||
        MusicNote song = filteredSongs.get(position);
 | 
			
		||||
        holder.bind(song);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return filteredSongs.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<MusicNote> getSelectedSongs() {
 | 
			
		||||
        return selectedSongs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSongs(List<MusicNote> musicNotes) {
 | 
			
		||||
        songs = musicNotes;
 | 
			
		||||
        filteredSongs = new ArrayList<>(musicNotes);
 | 
			
		||||
        notifyDataSetChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void filter(String query) {
 | 
			
		||||
        filteredSongs.clear();
 | 
			
		||||
        if (query.isEmpty()) {
 | 
			
		||||
            filteredSongs.addAll(songs);
 | 
			
		||||
        } else {
 | 
			
		||||
            for (MusicNote song : songs) {
 | 
			
		||||
                if (song.getTitle().toLowerCase().contains(query.toLowerCase())) {
 | 
			
		||||
                    filteredSongs.add(song);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        notifyDataSetChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ConcertSongSelectorViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        private final TextView songTitle;
 | 
			
		||||
        private final CheckBox songCheckbox;
 | 
			
		||||
 | 
			
		||||
        ConcertSongSelectorViewHolder(View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            songTitle = itemView.findViewById(R.id.song_title);
 | 
			
		||||
            songCheckbox = itemView.findViewById(R.id.song_checkbox);
 | 
			
		||||
 | 
			
		||||
            songCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
 | 
			
		||||
                MusicNote musicNote = filteredSongs.get(getAbsoluteAdapterPosition());
 | 
			
		||||
                selectedSongs.add(musicNote);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void bind(MusicNote song) {
 | 
			
		||||
            songTitle.setText(song.getTitle());
 | 
			
		||||
            songCheckbox.setChecked(selectedSongs.contains(song));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,111 +0,0 @@
 | 
			
		||||
package core.notevault.ui.gallery.editor;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.DatePickerDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.EditText;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.DialogFragment;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.Concert;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
public class ConcertEditorDialog extends DialogFragment {
 | 
			
		||||
    private Concert concert;
 | 
			
		||||
 | 
			
		||||
    private EditText concert_date_input;
 | 
			
		||||
    private EditText concertTitleInput;
 | 
			
		||||
 | 
			
		||||
    private OnConcertEditorListener listener;
 | 
			
		||||
 | 
			
		||||
    private int concertID = -1;
 | 
			
		||||
 | 
			
		||||
    public void setConcert(Concert concert) {
 | 
			
		||||
        concert_date_input.setText(concert.getConcertDate());
 | 
			
		||||
        concertTitleInput.setText(concert.getTitle());
 | 
			
		||||
        this.concert = concert;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface OnConcertEditorListener {
 | 
			
		||||
        void onConcertEditorClosed(String concertTitle, String concertDate, int concertID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface OnConcertEditorEditListener {
 | 
			
		||||
        void onConcertEditorEditClosed(String concertTitle, String concertDate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(Bundle savedInstanceState) {
 | 
			
		||||
        LayoutInflater inflater = requireActivity().getLayoutInflater();
 | 
			
		||||
        View dialogView = inflater.inflate(R.layout.concert_editor, null);
 | 
			
		||||
 | 
			
		||||
        EditText title_input = dialogView.findViewById(R.id.concert_title_input);
 | 
			
		||||
        concert_date_input = dialogView.findViewById(R.id.concert_date_input);
 | 
			
		||||
 | 
			
		||||
        concert_date_input.setOnClickListener(v -> showDatePickerDialog());
 | 
			
		||||
 | 
			
		||||
        if(getArguments() != null) {
 | 
			
		||||
            String concertTitle = getArguments().getString("concert_title");
 | 
			
		||||
            String concertDate = getArguments().getString("concert_date");
 | 
			
		||||
            concertID = getArguments().getInt("concertID");
 | 
			
		||||
            title_input.setText(concertTitle);
 | 
			
		||||
            concert_date_input.setText(concertDate);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new AlertDialog.Builder(requireContext())
 | 
			
		||||
                .setView(dialogView)
 | 
			
		||||
                .setPositiveButton("Speichern", (dialog, which) -> {
 | 
			
		||||
                    String title = title_input.getText().toString();
 | 
			
		||||
                    String concertDate = concert_date_input.getText().toString();
 | 
			
		||||
                    Log.d("ConcertEditor", "ConcertDate: " + concertDate);
 | 
			
		||||
 | 
			
		||||
                    listener.onConcertEditorClosed(title, concertDate, concertID);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .setNegativeButton("Abbrechen", (dialog, which) -> {} )
 | 
			
		||||
                .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAttach(@NonNull Context context) {
 | 
			
		||||
        super.onAttach(context);
 | 
			
		||||
        if (context instanceof OnConcertEditorListener) {
 | 
			
		||||
            listener = (OnConcertEditorListener) context;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException(context.toString()
 | 
			
		||||
                    + " must implement OnMetadataListener");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void showDatePickerDialog() {
 | 
			
		||||
        // Erhalte das aktuelle Datum
 | 
			
		||||
        final Calendar calendar = Calendar.getInstance();
 | 
			
		||||
        int year = calendar.get(Calendar.YEAR);
 | 
			
		||||
        int month = calendar.get(Calendar.MONTH);
 | 
			
		||||
        int day = calendar.get(Calendar.DAY_OF_MONTH);
 | 
			
		||||
 | 
			
		||||
        // Erstelle den DatePickerDialog
 | 
			
		||||
        DatePickerDialog datePickerDialog = new DatePickerDialog(this.getContext(),
 | 
			
		||||
                (view, selectedYear, selectedMonth, selectedDay) -> {
 | 
			
		||||
                    // Setze das ausgewählte Datum in das EditText
 | 
			
		||||
                    concert_date_input.setText(selectedDay + "/" + (selectedMonth + 1) + "/" + selectedYear);
 | 
			
		||||
                }, year, month, day);
 | 
			
		||||
 | 
			
		||||
        // Zeige den Dialog an
 | 
			
		||||
        datePickerDialog.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static String TAG = "ConcertEditorDialog";
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
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 androidx.viewpager2.widget.ViewPager2;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.ui.noteviewer.ImagePagerAdapter;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class FullScreenImageActivity extends AppCompatActivity {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        setContentView(R.layout.activity_fullscreen_image); // Erstelle eine Layout-Datei
 | 
			
		||||
 | 
			
		||||
        ViewPager2 imageView = findViewById(R.id.viewPager); // Angenommen, du hast ein ImageView
 | 
			
		||||
 | 
			
		||||
        // Die URI aus dem Intent erhalten
 | 
			
		||||
        Intent intent = getIntent();
 | 
			
		||||
        String[] imageUris = intent.getStringArrayExtra("imageUris");
 | 
			
		||||
        if (imageUris != null) {
 | 
			
		||||
            List<String> uriList = Arrays.asList(imageUris);
 | 
			
		||||
            ImagePagerAdapter adapter = new ImagePagerAdapter(this, uriList);
 | 
			
		||||
            imageView.setAdapter(adapter); // Setze die URI in das ImageView
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new NullPointerException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,160 +0,0 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.Looper;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
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.DividerItemDecoration;
 | 
			
		||||
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.data.sync.SyncStatus;
 | 
			
		||||
import core.notevault.databinding.FragmentHomeBinding;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
import core.notevault.ui.metadatadialog.SongEditDialog;
 | 
			
		||||
import core.notevault.util.NoteSheetsUtil;
 | 
			
		||||
 | 
			
		||||
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.add_song_concert);
 | 
			
		||||
        importBtn.setOnClickListener(v -> openFileChooser());
 | 
			
		||||
 | 
			
		||||
        RecyclerView recyclerView = root.findViewById(R.id.note_recycler_view);
 | 
			
		||||
        noteSongAdapter = new NoteSongAdapter(this::deleteSong, this::editSong);
 | 
			
		||||
        recyclerView.setAdapter(noteSongAdapter);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
 | 
			
		||||
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), LinearLayoutManager.VERTICAL);
 | 
			
		||||
        recyclerView.addItemDecoration(dividerItemDecoration);
 | 
			
		||||
 | 
			
		||||
        homeViewModel.getNoteTitles().observe(getViewLifecycleOwner(), songs -> {
 | 
			
		||||
            noteSongAdapter.updateSongTitles(songs);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        new LoadSongTitlesTask().execute();
 | 
			
		||||
 | 
			
		||||
        return root;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void editSong(MusicNote musicNote) {
 | 
			
		||||
        //Open Dialog
 | 
			
		||||
        SongEditDialog songEditDialog = new SongEditDialog();
 | 
			
		||||
        songEditDialog.setSong(musicNote);
 | 
			
		||||
        songEditDialog.show(getParentFragmentManager(), SongEditDialog.TAG);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deleteSong(MusicNote musicNote) {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            MusicDatabase musicDatabase = MusicDatabase.getDatabase(getContext());
 | 
			
		||||
            MusicNoteDAO musicNoteDAO = musicDatabase.musicNoteDao();
 | 
			
		||||
            musicNote.setSyncStatus(SyncStatus.DELETED);
 | 
			
		||||
            musicNoteDAO.updateSong(musicNote);
 | 
			
		||||
            Log.d("HomeFragment", "Delete Song: " + musicNote.getTitle());
 | 
			
		||||
            new Handler(Looper.getMainLooper()).post(()-> {
 | 
			
		||||
               homeViewModel.deleteSong(musicNote);
 | 
			
		||||
            });
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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> songs) {
 | 
			
		||||
            homeViewModel.setNoteTitles(songs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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) {
 | 
			
		||||
            if(data.getClipData() != null) {
 | 
			
		||||
                int count = data.getClipData().getItemCount();
 | 
			
		||||
                Uri[] uris = new Uri[count];
 | 
			
		||||
                for(int i = 0; i < count; i++) {
 | 
			
		||||
                    uris[i] =  data.getClipData().getItemAt(i).getUri();
 | 
			
		||||
                }
 | 
			
		||||
                handleFile(uris);
 | 
			
		||||
            } else if(data.getData() != null) {
 | 
			
		||||
                Uri uri = data.getData();
 | 
			
		||||
                handleFile(uri);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void handleFile(Uri... uris) {
 | 
			
		||||
        // Hier kannst du die Logik zum Speichern oder Anzeigen der Datei implementieren
 | 
			
		||||
        NoteSheetsUtil.sortNoteSheetsByTimestamp(getContext(), uris);
 | 
			
		||||
 | 
			
		||||
        MetaDataDialog metaDataDialog = new MetaDataDialog();
 | 
			
		||||
        metaDataDialog.setFileUri(uris);
 | 
			
		||||
        metaDataDialog.show(getParentFragmentManager(), MetaDataDialog.TAG);
 | 
			
		||||
 | 
			
		||||
        Toast.makeText(getActivity(), "Datei ausgewählt: " + uris[0].getPath(), Toast.LENGTH_SHORT).show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void openFileChooser() {
 | 
			
		||||
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
 | 
			
		||||
        intent.setType("*/*"); // Alle Dateitypen
 | 
			
		||||
 | 
			
		||||
        String[] mimeTypes = {"application/pdf", "image/png", "image/jpeg"};
 | 
			
		||||
        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
 | 
			
		||||
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 | 
			
		||||
 | 
			
		||||
        intent.addCategory(Intent.CATEGORY_OPENABLE);
 | 
			
		||||
        startActivityForResult(intent, PICK_FILE_REQUEST_CODE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroyView() {
 | 
			
		||||
        super.onDestroyView();
 | 
			
		||||
        binding = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addSong(MusicNote musicNote) {
 | 
			
		||||
        this.homeViewModel.addSong(musicNote);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateSong(MusicNote song) {
 | 
			
		||||
        this.homeViewModel.updateSong(song);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,63 +0,0 @@
 | 
			
		||||
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.data.MusicNote;
 | 
			
		||||
import core.notevault.ui.metadatadialog.MetaDataDialog;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class HomeViewModel extends ViewModel {
 | 
			
		||||
 | 
			
		||||
    private final MutableLiveData<List<MusicNote>> noteTitles;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public HomeViewModel() {
 | 
			
		||||
        noteTitles = new MutableLiveData<>(new ArrayList<>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiveData<List<MusicNote>> getNoteTitles() {
 | 
			
		||||
        return noteTitles;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNoteTitles(List<MusicNote> noteTitles) {
 | 
			
		||||
        this.noteTitles.setValue(noteTitles);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   public void addSong(MusicNote song) {
 | 
			
		||||
        List<MusicNote> songs = noteTitles.getValue();
 | 
			
		||||
        if(songs != null) {
 | 
			
		||||
            songs.add(song);
 | 
			
		||||
            this.noteTitles.setValue(songs);
 | 
			
		||||
        }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
    public void deleteSong(MusicNote musicNote) {
 | 
			
		||||
        List<MusicNote> currentSongs = noteTitles.getValue();
 | 
			
		||||
        if(currentSongs != null) {
 | 
			
		||||
            currentSongs.remove(musicNote);
 | 
			
		||||
            noteTitles.setValue(currentSongs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateSong(MusicNote updatedSong) {
 | 
			
		||||
        List<MusicNote> currentSongs = noteTitles.getValue();
 | 
			
		||||
        if(currentSongs != null) {
 | 
			
		||||
            for(int i=0; i<currentSongs.size(); i++) {
 | 
			
		||||
                if(currentSongs.get(i).getMusicNoteId() == updatedSong.getMusicNoteId()) {
 | 
			
		||||
                    currentSongs.set(i, updatedSong);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            noteTitles.setValue(currentSongs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,157 +0,0 @@
 | 
			
		||||
package core.notevault.ui.home;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.AsyncTask;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.ImageButton;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.data.MusicDatabase;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.MusicNoteDAO;
 | 
			
		||||
import core.notevault.data.NoteSheet;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class NoteSongAdapter extends RecyclerView.Adapter<NoteSongAdapter.NoteViewHolder> {
 | 
			
		||||
 | 
			
		||||
    private final List<MusicNote> noteTitles;
 | 
			
		||||
    private final OnSongDeleteListener onSongDeleteListener;
 | 
			
		||||
    private final OnSongEditListener onSongEditListener;
 | 
			
		||||
    public interface OnSongDeleteListener {
 | 
			
		||||
        void onSongDeleted(MusicNote song);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface OnSongEditListener {
 | 
			
		||||
        void onSongEdit(MusicNote song);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NoteSongAdapter(List<MusicNote> noteTitles, OnSongDeleteListener onSongDeleteListener, OnSongEditListener onSongEditListener) {
 | 
			
		||||
        this.noteTitles = noteTitles;
 | 
			
		||||
        this.onSongDeleteListener = onSongDeleteListener;
 | 
			
		||||
        this.onSongEditListener = onSongEditListener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NoteSongAdapter(OnSongDeleteListener onSongDeleteListener, OnSongEditListener onSongEditListener) {
 | 
			
		||||
        this.onSongDeleteListener = onSongDeleteListener;
 | 
			
		||||
        this.noteTitles = new ArrayList<>();
 | 
			
		||||
        this.onSongEditListener = onSongEditListener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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());
 | 
			
		||||
        holder.yearTextView.setText(String.valueOf(noteTitles.get(position).getYear()));
 | 
			
		||||
        holder.compositionTextView.setText(noteTitles.get(position).getComposer());
 | 
			
		||||
 | 
			
		||||
        holder.deleteButton.setOnClickListener(v -> {
 | 
			
		||||
            onSongDeleteListener.onSongDeleted(noteTitles.get(position));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        holder.editButton.setOnClickListener(v -> {
 | 
			
		||||
            onSongEditListener.onSongEdit(noteTitles.get(position));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return noteTitles.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void updateSongTitles(List<MusicNote> songs) {
 | 
			
		||||
        this.noteTitles.clear();
 | 
			
		||||
        this.noteTitles.addAll(songs);
 | 
			
		||||
        notifyDataSetChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NoteViewHolder extends RecyclerView.ViewHolder{
 | 
			
		||||
        TextView titleTextView;
 | 
			
		||||
        TextView yearTextView;
 | 
			
		||||
        TextView compositionTextView;
 | 
			
		||||
 | 
			
		||||
        ImageButton deleteButton;
 | 
			
		||||
        ImageButton editButton;
 | 
			
		||||
 | 
			
		||||
        NoteViewHolder(View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            titleTextView = itemView.findViewById(R.id.text_title);
 | 
			
		||||
            yearTextView = itemView.findViewById(R.id.text_year);
 | 
			
		||||
            compositionTextView = itemView.findViewById(R.id.text_composition);
 | 
			
		||||
 | 
			
		||||
            deleteButton = itemView.findViewById(R.id.delete_song_button);
 | 
			
		||||
            editButton = itemView.findViewById(R.id.edit_song_button);
 | 
			
		||||
            titleTextView.setOnClickListener(v -> {
 | 
			
		||||
                int position = getAdapterPosition();
 | 
			
		||||
                if(position != RecyclerView.NO_POSITION) {
 | 
			
		||||
                    MusicNote musicNote = noteTitles.get(position);
 | 
			
		||||
 | 
			
		||||
                    Intent intent = new Intent(itemView.getContext(), FullScreenImageActivity.class);
 | 
			
		||||
                    new LoadNoteSheetsTask(musicNote.getMusicNoteId(),
 | 
			
		||||
                            MusicDatabase.getDatabase(itemView.getContext()).musicNoteDao(), new OnNoteSheedsLoadedListener() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onNoteSheetsLoaded(List<NoteSheet> noteSheets) {
 | 
			
		||||
                            String[] noteSheetFiles = new String[noteSheets.size()];
 | 
			
		||||
                            for (int i = 0; i < noteSheets.size(); i++) {
 | 
			
		||||
                                noteSheetFiles[i] = noteSheets.get(i).getFilePath();
 | 
			
		||||
                            }
 | 
			
		||||
                            intent.putExtra("imageUris", noteSheetFiles);
 | 
			
		||||
                            itemView.getContext().startActivity(intent);
 | 
			
		||||
                        }
 | 
			
		||||
                    }).execute();
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void bind(MusicNote note) {
 | 
			
		||||
            titleTextView.setText(note.getTitle());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface OnNoteSheedsLoadedListener {
 | 
			
		||||
        void onNoteSheetsLoaded(List<NoteSheet> noteSheets);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class LoadNoteSheetsTask extends AsyncTask<Void, Void, List<NoteSheet>> {
 | 
			
		||||
        private final long musicNoteId;
 | 
			
		||||
        private final MusicNoteDAO musicNoteDAO;
 | 
			
		||||
        private final OnNoteSheedsLoadedListener listener;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public LoadNoteSheetsTask(long musicNoteId, MusicNoteDAO musicNoteDAO, OnNoteSheedsLoadedListener listener) {
 | 
			
		||||
            this.musicNoteId = musicNoteId;
 | 
			
		||||
            this.musicNoteDAO = musicNoteDAO;
 | 
			
		||||
            this.listener = listener;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected List<NoteSheet> doInBackground(Void... voids) {
 | 
			
		||||
            List<NoteSheet> sheets =  musicNoteDAO.getNoteSheetsForMusicSong(this.musicNoteId);
 | 
			
		||||
            Log.d("LoadedNoteSheetsTask", "ID: " + this.musicNoteId);
 | 
			
		||||
            Log.d("LoadNoteSheetsTask", "Loaded NoteSheets: " + sheets.size());
 | 
			
		||||
            return sheets;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void onPostExecute(List<NoteSheet> sheets) {
 | 
			
		||||
            listener.onNoteSheetsLoaded(sheets);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
package core.notevault.ui.login;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import core.notevault.sync.APICallback;
 | 
			
		||||
import core.notevault.sync.auth.LoginCallback;
 | 
			
		||||
 | 
			
		||||
public class LoginCallBackImpl implements APICallback {
 | 
			
		||||
    private Context context;
 | 
			
		||||
 | 
			
		||||
    public LoginCallBackImpl(Context context) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSuccess() {
 | 
			
		||||
        Toast.makeText(context, "Login successfull", Toast.LENGTH_SHORT).show();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onError(String error) {
 | 
			
		||||
        Log.d("Login", error);
 | 
			
		||||
        Toast.makeText(context, "Login not successfull: " + error, Toast.LENGTH_LONG).show();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,100 +0,0 @@
 | 
			
		||||
package core.notevault.ui.login;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.Button;
 | 
			
		||||
import android.widget.EditText;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.fragment.app.DialogFragment;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
import core.notevault.sync.APICallback;
 | 
			
		||||
import core.notevault.sync.auth.AuthRepository;
 | 
			
		||||
import core.notevault.sync.auth.LoginCallback;
 | 
			
		||||
import retrofit2.Call;
 | 
			
		||||
import retrofit2.Callback;
 | 
			
		||||
 | 
			
		||||
public class LoginDialogFragment extends DialogFragment {
 | 
			
		||||
    private APICallback loginCallback;
 | 
			
		||||
    private APICallback registerCallback;
 | 
			
		||||
 | 
			
		||||
    private boolean isLoginMode = true; // Default mode
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAttach(Context context) {
 | 
			
		||||
        super.onAttach(context);
 | 
			
		||||
        if (loginCallback == null || registerCallback == null) {
 | 
			
		||||
            throw new IllegalStateException("LoginDialogFragment must be created using newInstance()");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static LoginDialogFragment newInstance(APICallback loginCallback, APICallback registerCallback) {
 | 
			
		||||
        LoginDialogFragment fragment = new LoginDialogFragment();
 | 
			
		||||
        fragment.loginCallback = loginCallback;
 | 
			
		||||
        fragment.registerCallback = registerCallback;
 | 
			
		||||
        return fragment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 | 
			
		||||
        /*return new AlertDialog.Builder(requireContext())
 | 
			
		||||
                .setView(loginView)
 | 
			
		||||
                .setPositiveButton("Speichern", (dialog, which) -> {
 | 
			
		||||
                    String username = usernameInput.getText().toString();
 | 
			
		||||
                    String password = passwordInput.getText().toString();
 | 
			
		||||
 | 
			
		||||
                    authRepository.performLogin(username, password, loginCallback);
 | 
			
		||||
                } )
 | 
			
		||||
                .setNegativeButton("Abbrechen", (dialog, which) -> {} )
 | 
			
		||||
                .create();*/
 | 
			
		||||
 | 
			
		||||
        AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
 | 
			
		||||
        LayoutInflater inflater = requireActivity().getLayoutInflater();
 | 
			
		||||
        View view = inflater.inflate(R.layout.fragment_login_dialog, null);
 | 
			
		||||
 | 
			
		||||
        TextView textViewTitle = view.findViewById(R.id.textViewTitle);
 | 
			
		||||
        EditText editTextUsername = view.findViewById(R.id.editTextUsername);
 | 
			
		||||
        EditText editTextEmail = view.findViewById(R.id.editTextEmail);
 | 
			
		||||
        EditText editTextPassword = view.findViewById(R.id.editTextPassword);
 | 
			
		||||
        Button buttonAction = view.findViewById(R.id.buttonAction);
 | 
			
		||||
        TextView textViewSwitch = view.findViewById(R.id.textViewSwitch);
 | 
			
		||||
 | 
			
		||||
        // Handle action button click
 | 
			
		||||
        buttonAction.setOnClickListener(v -> {
 | 
			
		||||
            if (isLoginMode) {
 | 
			
		||||
                // Handle login logic
 | 
			
		||||
                String email = editTextEmail.getText().toString();
 | 
			
		||||
                String password = editTextPassword.getText().toString();
 | 
			
		||||
                AuthRepository authRepository = new AuthRepository(this.getContext());
 | 
			
		||||
                authRepository.performLogin(email, password, loginCallback);
 | 
			
		||||
            } else {
 | 
			
		||||
                // Handle registration logic
 | 
			
		||||
                String email = editTextEmail.getText().toString();
 | 
			
		||||
                String password = editTextPassword.getText().toString();
 | 
			
		||||
                String username = editTextUsername.getText().toString();
 | 
			
		||||
                AuthRepository authRepository = new AuthRepository(this.getContext());
 | 
			
		||||
                authRepository.performRegistration(email, username, password, registerCallback);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Toggle between Login and Registration
 | 
			
		||||
        textViewSwitch.setOnClickListener(v -> {
 | 
			
		||||
            isLoginMode = !isLoginMode;
 | 
			
		||||
            textViewTitle.setText(isLoginMode ? "Login" : "Register");
 | 
			
		||||
            editTextUsername.setVisibility(isLoginMode ? View.GONE : View.VISIBLE);
 | 
			
		||||
            buttonAction.setText(isLoginMode ? "Login" : "Register");
 | 
			
		||||
            textViewSwitch.setText(isLoginMode ? "Don't have an account? Register" : "Already have an account? Login");
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        builder.setView(view);
 | 
			
		||||
        return builder.create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
package core.notevault.ui.login;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import core.notevault.sync.APICallback;
 | 
			
		||||
 | 
			
		||||
public class RegisterCallback implements APICallback {
 | 
			
		||||
    private Context context;
 | 
			
		||||
 | 
			
		||||
    public RegisterCallback(Context context) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onSuccess() {
 | 
			
		||||
        Toast.makeText(context, "Registration successfull", Toast.LENGTH_SHORT).show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onError(String error) {
 | 
			
		||||
        Log.d("Login", error);
 | 
			
		||||
        Toast.makeText(context, "Login not successfull: " + error, Toast.LENGTH_LONG).show();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,108 +0,0 @@
 | 
			
		||||
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(Uri[] uri, 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(fileUri, 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[0].getScheme().equals("content")) {
 | 
			
		||||
            // ContentResolver verwenden, um die Datei zu finden
 | 
			
		||||
            Cursor cursor = requireContext().getContentResolver().query(this.fileUri[0], 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[0].getScheme().equals("file")) {
 | 
			
		||||
            // Bei einer Datei-Uri einfach den letzten Pfadsegment verwenden
 | 
			
		||||
            fileName = this.fileUri[0].getLastPathSegment();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(fileName.contains(".")) {
 | 
			
		||||
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
 | 
			
		||||
            fileName = fileName.replace("_", " ");
 | 
			
		||||
            fileName = fileName.replace("-", "");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return fileName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String TAG = "MetaDataDialog";
 | 
			
		||||
}
 | 
			
		||||
@ -1,90 +0,0 @@
 | 
			
		||||
package core.notevault.ui.metadatadialog;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
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;
 | 
			
		||||
import core.notevault.data.MusicNote;
 | 
			
		||||
import core.notevault.data.sync.SyncStatus;
 | 
			
		||||
 | 
			
		||||
public class SongEditDialog extends DialogFragment {
 | 
			
		||||
 | 
			
		||||
    private MusicNote song;
 | 
			
		||||
    private SongEditorListener songEditorListener;
 | 
			
		||||
 | 
			
		||||
    public interface SongEditorListener {
 | 
			
		||||
        void onSongEdited(MusicNote updatedSong);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
 | 
			
		||||
        LayoutInflater inflater = requireActivity().getLayoutInflater();
 | 
			
		||||
        View dialogView = inflater.inflate(R.layout.song_metadata_edit_dialog, null); // Ersetze 'your_dialog_layout' durch deinen Dateinamen
 | 
			
		||||
 | 
			
		||||
        EditText title_input = dialogView.findViewById(R.id.title_input);
 | 
			
		||||
        title_input.setText(song.getTitle());
 | 
			
		||||
        EditText composer_input = dialogView.findViewById(R.id.composer_input);
 | 
			
		||||
        composer_input.setText(song.getComposer());
 | 
			
		||||
        EditText year_input = dialogView.findViewById(R.id.year_input);
 | 
			
		||||
        year_input.setText(String.valueOf(song.getYear()));
 | 
			
		||||
        EditText genre_input = dialogView.findViewById(R.id.genre_input);
 | 
			
		||||
        genre_input.setText(song.getGenre());
 | 
			
		||||
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
                    song.setTitle(title);
 | 
			
		||||
                    song.setComposer(composer);
 | 
			
		||||
                    song.setGenre(genre);
 | 
			
		||||
                    song.setYear(year);
 | 
			
		||||
 | 
			
		||||
                    if(song.getSyncStatus() == SyncStatus.SYNCED) {
 | 
			
		||||
                        song.setSyncStatus(SyncStatus.MODIFIED);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    songEditorListener.onSongEdited(song);
 | 
			
		||||
                } )
 | 
			
		||||
                .setNegativeButton("Abbrechen", (dialog, which) -> {} )
 | 
			
		||||
                .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MusicNote getSong() {
 | 
			
		||||
        return song;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSong(MusicNote song) {
 | 
			
		||||
        this.song = song;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onAttach(@NonNull Context context) {
 | 
			
		||||
        super.onAttach(context);
 | 
			
		||||
        if (context instanceof MetaDataDialog.OnMetadataListener) {
 | 
			
		||||
            songEditorListener = (SongEditorListener) context;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException(context.toString()
 | 
			
		||||
                    + " must implement OnMetadataListener");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String TAG = "SONGEDITDIALOG";
 | 
			
		||||
}
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
package core.notevault.ui.noteviewer;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import com.github.chrisbanes.photoview.PhotoView;
 | 
			
		||||
import core.notevault.R;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ImagePagerAdapter extends RecyclerView.Adapter<ImagePagerAdapter.ImageViewHolder> {
 | 
			
		||||
    private final List<String> imageUris;
 | 
			
		||||
    private final Context context;
 | 
			
		||||
 | 
			
		||||
    public ImagePagerAdapter(Context context, List<String> imageUris) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
        this.imageUris = imageUris;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(context).inflate(R.layout.item_image, parent, false);
 | 
			
		||||
        return new ImageViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
 | 
			
		||||
        Uri uri = Uri.parse(imageUris.get(position));
 | 
			
		||||
        holder.photoView.setImageURI(uri);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return imageUris.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ImageViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        PhotoView photoView;
 | 
			
		||||
 | 
			
		||||
        ImageViewHolder(View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            photoView = itemView.findViewById(R.id.photoView);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,54 +0,0 @@
 | 
			
		||||
package core.notevault.util;
 | 
			
		||||
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.media.ExifInterface;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.provider.MediaStore;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.text.ParseException;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
public class NoteSheetsUtil {
 | 
			
		||||
 | 
			
		||||
    private static long getImageTimestamp(Context context, Uri imageUri) {
 | 
			
		||||
        try  {
 | 
			
		||||
            InputStream inputStream = context.getContentResolver().openInputStream(imageUri);
 | 
			
		||||
            ExifInterface exif = new ExifInterface(inputStream);
 | 
			
		||||
 | 
			
		||||
            String dateTime = exif.getAttribute(ExifInterface.TAG_DATETIME);
 | 
			
		||||
            if(dateTime != null) {
 | 
			
		||||
                SimpleDateFormat format = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.getDefault());
 | 
			
		||||
                Date date = format.parse(dateTime);
 | 
			
		||||
                return date != null ? date.getTime() : 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                File file = new File(imageUri.getPath());
 | 
			
		||||
                return file.lastModified();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException | ParseException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void sortNoteSheetsByTimestamp(Context context, Uri[] uris) {
 | 
			
		||||
        ArrayList<UriTimestamp> uriTimestamps = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        for(Uri uri : uris) {
 | 
			
		||||
            long timestamp = getImageTimestamp(context, uri);
 | 
			
		||||
            uriTimestamps.add(new UriTimestamp(uri, timestamp));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Collections.sort(uriTimestamps, Comparator.comparingLong(UriTimestamp::getTimestamp));
 | 
			
		||||
 | 
			
		||||
        for(int i=0; i<uriTimestamps.size(); i++) {
 | 
			
		||||
            uris[i] = uriTimestamps.get(i).getUri();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
package core.notevault.util;
 | 
			
		||||
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
 | 
			
		||||
public class UriTimestamp {
 | 
			
		||||
    private final Uri uri;
 | 
			
		||||
    private final long timestamp;
 | 
			
		||||
 | 
			
		||||
    public UriTimestamp(Uri uri, long timestamp) {
 | 
			
		||||
        this.uri = uri;
 | 
			
		||||
        this.timestamp = timestamp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Uri getUri() {
 | 
			
		||||
        return uri;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public long getTimestamp() {
 | 
			
		||||
        return timestamp;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<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>
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<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="M280,840q-33,0 -56.5,-23.5T200,760v-520h-40v-80h200v-40h240v40h200v80h-40v520q0,33 -23.5,56.5T680,840L280,840ZM680,240L280,240v520h400v-520ZM360,680h80v-360h-80v360ZM520,680h80v-360h-80v360ZM280,240v520,-520Z"
 | 
			
		||||
      android:fillColor="#e8eaed"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <solid android:color="@android:color/white" />
 | 
			
		||||
    <corners android:radius="16dp" />
 | 
			
		||||
    <padding android:left="16dp" android:top="16dp" android:right="16dp" android:bottom="16dp" />
 | 
			
		||||
    <elevation android:height="4dp" />
 | 
			
		||||
</shape>
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<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="M200,760h57l391,-391 -57,-57 -391,391v57ZM120,840v-170l528,-527q12,-11 26.5,-17t30.5,-6q16,0 31,6t26,18l55,56q12,11 17.5,26t5.5,30q0,16 -5.5,30.5T817,313L290,840L120,840ZM760,256 L704,200 760,256ZM619,341 L591,312 648,369 619,341Z"
 | 
			
		||||
      android:fillColor="#e8eaed"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<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="M480,840v-80h280v-560L480,200v-80h280q33,0 56.5,23.5T840,200v560q0,33 -23.5,56.5T760,840L480,840ZM400,680 L345,622 447,520L120,520v-80h327L345,338l55,-58 200,200 -200,200Z"
 | 
			
		||||
      android:fillColor="#e8eaed"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<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="M200,840q-33,0 -56.5,-23.5T120,760v-560q0,-33 23.5,-56.5T200,120h280v80L200,200v560h280v80L200,840ZM640,680 L585,622 687,520L360,520v-80h327L585,338l55,-58 200,200 -200,200Z"
 | 
			
		||||
      android:fillColor="#e8eaed"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
<?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">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <androidx.viewpager2.widget.ViewPager2
 | 
			
		||||
            android:id="@+id/viewPager"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent" />
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
@ -23,4 +23,13 @@
 | 
			
		||||
 | 
			
		||||
    <include layout="@layout/content_main"/>
 | 
			
		||||
 | 
			
		||||
    <com.google.android.material.floatingactionbutton.FloatingActionButton
 | 
			
		||||
            android:id="@+id/fab"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_gravity="bottom|end"
 | 
			
		||||
            android:layout_marginEnd="@dimen/fab_margin"
 | 
			
		||||
            android:layout_marginBottom="16dp"
 | 
			
		||||
            app:srcCompat="@android:drawable/ic_dialog_email"/>
 | 
			
		||||
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
@ -1,81 +0,0 @@
 | 
			
		||||
<?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/concert_editor_dialog">
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:orientation="vertical"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="Konzerteinstellungen"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:id="@+id/concert_settings"
 | 
			
		||||
                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_concert_label"/>
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:layout_weight="1"
 | 
			
		||||
                        android:inputType="text"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/concert_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="Datum"
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:id="@+id/concert_date_label"/>
 | 
			
		||||
                <EditText
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:layout_weight="1"
 | 
			
		||||
                        android:inputType="date"
 | 
			
		||||
                        android:ems="10"
 | 
			
		||||
                        android:id="@+id/concert_date_input"
 | 
			
		||||
                        android:hint="Datum eingeben"
 | 
			
		||||
                        android:foregroundTint="#000000"
 | 
			
		||||
                        android:minHeight="48dp"
 | 
			
		||||
                        android:padding="16dp"
 | 
			
		||||
                        android:minWidth="48dp"
 | 
			
		||||
                        android:focusable="false"
 | 
			
		||||
                        android:clickable="true"/>
 | 
			
		||||
 | 
			
		||||
            </TableRow>
 | 
			
		||||
 | 
			
		||||
        </TableLayout>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,60 +0,0 @@
 | 
			
		||||
<?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" xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
              android:orientation="horizontal"
 | 
			
		||||
              android:padding="16dp">
 | 
			
		||||
 | 
			
		||||
    <!-- Linke Seite mit Datum und Titel -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:orientation="vertical">
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:id="@+id/concert_date"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="Concert Date"
 | 
			
		||||
                android:textColor="@android:color/darker_gray"
 | 
			
		||||
                android:textSize="14sp" />
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:id="@+id/concert_title"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="Concert Title"
 | 
			
		||||
                android:textSize="18sp" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <!-- Abstandshalter, um die Buttons nach rechts zu schieben -->
 | 
			
		||||
    <Space
 | 
			
		||||
            android:layout_width="16dp"
 | 
			
		||||
            android:layout_height="wrap_content" />
 | 
			
		||||
 | 
			
		||||
    <!-- Rechte Seite mit den Buttons -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal">
 | 
			
		||||
 | 
			
		||||
        <ImageButton
 | 
			
		||||
                android:id="@+id/edit_concert_button"
 | 
			
		||||
                android:layout_width="48dp"
 | 
			
		||||
                android:layout_height="48dp"
 | 
			
		||||
                android:src="@drawable/edit_24dp_e8eaed_fill0_wght400_grad0_opsz24"
 | 
			
		||||
                app:tint="@color/teal_700"
 | 
			
		||||
                android:contentDescription="Edit Concert"
 | 
			
		||||
                android:background="?android:selectableItemBackgroundBorderless" />
 | 
			
		||||
 | 
			
		||||
        <ImageButton
 | 
			
		||||
                android:id="@+id/delete_concert_button"
 | 
			
		||||
                android:layout_width="48dp"
 | 
			
		||||
                android:layout_height="48dp"
 | 
			
		||||
                android:src="@drawable/delete"
 | 
			
		||||
                app:tint="@color/red"
 | 
			
		||||
                android:contentDescription="Delete Concert"
 | 
			
		||||
                android:background="?android:selectableItemBackgroundBorderless" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
<?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/concert_song_selector_dialgog">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:text="Wähle Songs für das Konzert 'Jubiläum' am 19.10.2024 aus"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:id="@+id/dialog_title_concert_song_selector"
 | 
			
		||||
            android:textStyle="bold"
 | 
			
		||||
            android:textSize="18sp"/>
 | 
			
		||||
 | 
			
		||||
    <SearchView
 | 
			
		||||
            android:id="@+id/search_view"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:queryHint="Suche Stücke..." />
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/concert_song_selector_recycler"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="0dp"
 | 
			
		||||
            android:layout_weight="1" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,67 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        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" xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:orientation="vertical" android:layout_above="@+id/add_song_concert"
 | 
			
		||||
            android:padding="16dp" android:id="@+id/linearLayout">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        <androidx.cardview.widget.CardView
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_marginBottom="16dp"
 | 
			
		||||
                app:cardCornerRadius="8dp"
 | 
			
		||||
                app:cardElevation="4dp">
 | 
			
		||||
 | 
			
		||||
            <LinearLayout
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:orientation="horizontal"
 | 
			
		||||
                    android:padding="16dp">
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:id="@+id/text_concert_details_title"
 | 
			
		||||
                        android:layout_width="0dp"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:layout_weight="1"
 | 
			
		||||
                        android:text="Konzerttitel"
 | 
			
		||||
                        android:textSize="18sp"
 | 
			
		||||
                        android:textStyle="bold"/>
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                        android:id="@+id/text_concert_details_date"
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:text="01.01.2024"
 | 
			
		||||
                        android:textSize="16sp"/>
 | 
			
		||||
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
        </androidx.cardview.widget.CardView>
 | 
			
		||||
 | 
			
		||||
        <!-- Hier können weitere Details hinzugefügt werden -->
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
                android:id="@+id/note_recycler_view"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent"
 | 
			
		||||
                android:layout_above="@+id/add_song_concert"/>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <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/add_song_concert"
 | 
			
		||||
            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 Concert Song"/>
 | 
			
		||||
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
@ -7,17 +7,17 @@
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.gallery.GalleryFragment">
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/concert_recycler_view"
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/text_gallery"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:layout_above="@+id/add_concert_btn"/>
 | 
			
		||||
 | 
			
		||||
    <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/add_concert_btn"
 | 
			
		||||
            android:layout_marginEnd="16dp" app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp"/>
 | 
			
		||||
            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>
 | 
			
		||||
@ -7,22 +7,17 @@
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".ui.home.HomeFragment">
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/note_recycler_view"
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/text_home"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:layout_above="@+id/add_song_concert"/>
 | 
			
		||||
 | 
			
		||||
    <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/add_song_concert"
 | 
			
		||||
            android:layout_marginEnd="16dp"
 | 
			
		||||
            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_constraintBottom_toBottomOf="parent"
 | 
			
		||||
            android:layout_marginBottom="16dp"
 | 
			
		||||
            app:backgroundTint="@color/teal_200"
 | 
			
		||||
            android:contentDescription="Add Music Notes"/>
 | 
			
		||||
            app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
            app:layout_constraintBottom_toBottomOf="parent"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
@ -1,68 +0,0 @@
 | 
			
		||||
<?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:background="@drawable/dialog_background"
 | 
			
		||||
              android:layout_gravity="center_horizontal">
 | 
			
		||||
 | 
			
		||||
    <!-- Title -->
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/textViewTitle"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Login"
 | 
			
		||||
            android:textSize="18sp"
 | 
			
		||||
            android:textStyle="bold"
 | 
			
		||||
            android:gravity="center"
 | 
			
		||||
            android:paddingBottom="16dp" />
 | 
			
		||||
 | 
			
		||||
    <!-- Username Field (Visible only in Registration mode) -->
 | 
			
		||||
    <EditText
 | 
			
		||||
            android:id="@+id/editTextUsername"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="Username"
 | 
			
		||||
            android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    <!-- Email Field -->
 | 
			
		||||
    <EditText
 | 
			
		||||
            android:id="@+id/editTextEmail"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="Email"
 | 
			
		||||
            android:inputType="textEmailAddress" />
 | 
			
		||||
 | 
			
		||||
    <!-- Password Field -->
 | 
			
		||||
    <EditText
 | 
			
		||||
            android:id="@+id/editTextPassword"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="Password"
 | 
			
		||||
            android:inputType="textPassword" />
 | 
			
		||||
 | 
			
		||||
    <!-- Action Button -->
 | 
			
		||||
    <Button
 | 
			
		||||
            android:id="@+id/buttonAction"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Login"
 | 
			
		||||
            android:backgroundTint="?attr/colorPrimary"
 | 
			
		||||
            android:textColor="@android:color/white"
 | 
			
		||||
            android:layout_marginTop="16dp" />
 | 
			
		||||
 | 
			
		||||
    <!-- Toggle Login/Registration -->
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/textViewSwitch"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Don't have an account? Register"
 | 
			
		||||
            android:gravity="center"
 | 
			
		||||
            android:textColor="?attr/colorPrimary"
 | 
			
		||||
            android:layout_marginTop="8dp"
 | 
			
		||||
            android:padding="8dp"
 | 
			
		||||
            android:clickable="true"
 | 
			
		||||
            android:focusable="true" />
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,126 +0,0 @@
 | 
			
		||||
<?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/concert_date_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>
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
<?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="horizontal"
 | 
			
		||||
              android:padding="8dp">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/song_title"
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:text="Song Title" />
 | 
			
		||||
 | 
			
		||||
    <CheckBox
 | 
			
		||||
            android:id="@+id/song_checkbox"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
             android:layout_width="match_parent"
 | 
			
		||||
             android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <com.github.chrisbanes.photoview.PhotoView
 | 
			
		||||
            android:id="@+id/photoView"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            android:scaleType="fitCenter" />
 | 
			
		||||
</FrameLayout>
 | 
			
		||||
@ -1,77 +0,0 @@
 | 
			
		||||
<?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" xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        android:orientation="horizontal"
 | 
			
		||||
        android:padding="8dp"
 | 
			
		||||
        android:gravity="center_vertical">
 | 
			
		||||
 | 
			
		||||
    <!-- Text Section -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:orientation="vertical">
 | 
			
		||||
 | 
			
		||||
        <!-- First Row: Year and Composition -->
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:orientation="horizontal">
 | 
			
		||||
 | 
			
		||||
            <TextView
 | 
			
		||||
                    android:id="@+id/text_year"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="Year"
 | 
			
		||||
                    android:textSize="14sp"
 | 
			
		||||
                    android:textColor="@android:color/darker_gray" />
 | 
			
		||||
 | 
			
		||||
            <TextView
 | 
			
		||||
                    android:id="@+id/text_composition"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="Composition"
 | 
			
		||||
                    android:textSize="14sp"
 | 
			
		||||
                    android:layout_marginStart="8dp"
 | 
			
		||||
                    android:textColor="@android:color/darker_gray" />
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
 | 
			
		||||
        <!-- Second Row: Title -->
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:id="@+id/text_title"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="Title"
 | 
			
		||||
                android:textSize="16sp"
 | 
			
		||||
                android:textColor="@android:color/black"
 | 
			
		||||
                android:paddingTop="4dp"/>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <!-- Rechte Seite mit den Buttons -->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal">
 | 
			
		||||
 | 
			
		||||
        <ImageButton
 | 
			
		||||
                android:id="@+id/edit_song_button"
 | 
			
		||||
                android:layout_width="48dp"
 | 
			
		||||
                android:layout_height="48dp"
 | 
			
		||||
                android:src="@drawable/edit_24dp_e8eaed_fill0_wght400_grad0_opsz24"
 | 
			
		||||
                app:tint="@color/teal_700"
 | 
			
		||||
                android:contentDescription="Edit Song"
 | 
			
		||||
                android:background="?android:selectableItemBackgroundBorderless" />
 | 
			
		||||
 | 
			
		||||
        <ImageButton
 | 
			
		||||
                android:id="@+id/delete_song_button"
 | 
			
		||||
                android:layout_width="48dp"
 | 
			
		||||
                android:layout_height="48dp"
 | 
			
		||||
                android:src="@drawable/delete"
 | 
			
		||||
                app:tint="@color/red"
 | 
			
		||||
                android:contentDescription="Delete Song"
 | 
			
		||||
                android:background="?android:selectableItemBackgroundBorderless" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -1,126 +0,0 @@
 | 
			
		||||
<?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/concert_date_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>
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- res/menu/main_menu.xml -->
 | 
			
		||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <item
 | 
			
		||||
            android:id="@+id/action_login"
 | 
			
		||||
            android:title="Login"
 | 
			
		||||
            android:icon="@drawable/logout"
 | 
			
		||||
            app:showAsAction="always"/> <!-- Wichtig: immer in der Toolbar anzeigen -->
 | 
			
		||||
</menu>
 | 
			
		||||
<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="100"
 | 
			
		||||
          app:showAsAction="never"/>
 | 
			
		||||
</menu>
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user