diff --git a/.gitignore b/.gitignore
index 8b26667..25b9f6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,18 @@
+# Built application files
+*.apk
+*.ap_
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
# Gradle files
.gradle/
build/
@@ -5,20 +20,21 @@ build/
# Local configuration file (sdk path, etc)
local.properties
-# Log/OS Files
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
*.log
-# Android Studio generated files and folders
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
captures/
-.externalNativeBuild/
-.cxx/
-*.apk
-*.aab
-output.json
-*.dm
-# IntelliJ
+# Intellij
*.iml
+.idea/workspace.xml
.idea/
misc.xml
deploymentTargetDropDown.xml
@@ -26,10 +42,134 @@ render.experimental.xml
# Keystore files
*.jks
-*.keystore
-
-# Google Services (e.g. APIs or Firebase)
-google-services.json
# Android Profiling
*.hprof
+
+# Miscellaneous
+*.class
+*.lock
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/*
+
+# Visual Studio Code related
+.classpath
+.project
+.settings/
+.vscode/*
+
+# Flutter repo-specific
+/bin/cache/
+/bin/mingit/
+/dev/benchmarks/mega_gallery/
+/dev/bots/.recipe_deps
+/dev/bots/android_tools/
+/dev/docs/doc/
+/dev/docs/flutter.docs.zip
+/dev/docs/lib/
+/dev/docs/pubspec.yaml
+/dev/integration_tests/**/xcuserdata
+/dev/integration_tests/**/Pods
+/packages/flutter/coverage/
+version
+
+# packages file containing multi-root paths
+.packages.generated
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+build/
+flutter_*.png
+linked_*.ds
+unlinked.ds
+unlinked_spec.ds
+.fvm/
+
+# Android related
+**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+**/android/key.properties
+**/android/.idea/
+*.jks
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/.last_build_id
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Coverage
+coverage/
+
+# Submodules
+!pubspec.lock
+packages/**/pubspec.lock
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Exceptions to the above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
+!/dev/ci/**/Gemfile.lock
+!.vscode/extensions.json
+!.vscode/launch.json
+!.idea/codeStyles/
+!.idea/dictionaries/
+!.idea/runConfigurations/
diff --git a/android/FucksGiven/.gitignore b/android/FucksGiven/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/android/FucksGiven/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/android/FucksGiven/app/.gitignore b/android/FucksGiven/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/android/FucksGiven/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/android/FucksGiven/app/build.gradle.kts b/android/FucksGiven/app/build.gradle.kts
new file mode 100644
index 0000000..5cabe92
--- /dev/null
+++ b/android/FucksGiven/app/build.gradle.kts
@@ -0,0 +1,103 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.jetbrains.kotlin.android)
+ kotlin("kapt")
+ id("com.google.dagger.hilt.android")
+}
+
+android {
+ namespace = "rocks.poopjournal.fucksgiven"
+ compileSdk = 34
+
+
+ defaultConfig {
+
+ applicationId = "rocks.poopjournal.fucksgiven"
+ minSdk = 26
+ targetSdk = 34
+ versionCode = 1
+ versionName = "1.0.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ compose = true
+ viewBinding = true
+ }
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.5.1"
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+}
+
+dependencies {
+
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.activity.compose)
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.ui)
+ implementation(libs.androidx.ui.graphics)
+ implementation(libs.androidx.ui.tooling.preview)
+ implementation(libs.androidx.material3)
+ implementation(libs.androidx.runtime.livedata)
+ implementation(libs.androidx.glance.appwidget)
+ implementation(libs.androidx.compose.material)
+ implementation(libs.androidx.compose.foundation)
+ implementation(libs.androidx.core.splashscreen)
+ implementation(libs.androidx.appcompat)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(platform(libs.androidx.compose.bom))
+ androidTestImplementation(libs.androidx.ui.test.junit4)
+ debugImplementation(libs.androidx.ui.tooling)
+ debugImplementation(libs.androidx.ui.test.manifest)
+ implementation("androidx.navigation:navigation-compose:2.7.7")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
+ implementation ("androidx.work:work-runtime-ktx:2.9.0")
+
+
+ // Room
+ implementation("androidx.room:room-runtime:2.6.1")
+ annotationProcessor("androidx.room:room-compiler:2.6.1")
+ kapt("androidx.room:room-compiler:2.6.1")
+ implementation("androidx.room:room-ktx:2.6.1")
+
+ //Hilt
+ implementation("com.google.dagger:hilt-android:2.48")
+ kapt("com.google.dagger:hilt-android-compiler:2.48")
+ implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
+ implementation("com.google.accompanist:accompanist-permissions:0.31.0-alpha")
+ implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
+ implementation ("androidx.glance:glance-appwidget:1.0.0")
+ implementation ("androidx.glance:glance-material3:1.0.0")
+}
+
+kapt{
+ correctErrorTypes = true
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/lint.xml b/android/FucksGiven/app/lint.xml
new file mode 100644
index 0000000..44fac75
--- /dev/null
+++ b/android/FucksGiven/app/lint.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/proguard-rules.pro b/android/FucksGiven/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/android/FucksGiven/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/android/FucksGiven/app/release/app-release.aab b/android/FucksGiven/app/release/app-release.aab
new file mode 100644
index 0000000..57d310e
Binary files /dev/null and b/android/FucksGiven/app/release/app-release.aab differ
diff --git a/android/FucksGiven/app/src/androidTest/java/rocks/poopjournal/fucksgiven/ExampleInstrumentedTest.kt b/android/FucksGiven/app/src/androidTest/java/rocks/poopjournal/fucksgiven/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..efa0ac1
--- /dev/null
+++ b/android/FucksGiven/app/src/androidTest/java/rocks/poopjournal/fucksgiven/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package rocks.poopjournal.fucksgiven
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("rocks.poopjournal.fucksgiven", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/AndroidManifest.xml b/android/FucksGiven/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bff8c14
--- /dev/null
+++ b/android/FucksGiven/app/src/main/AndroidManifest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/ic_launcher-playstore.png b/android/FucksGiven/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..81654a9
Binary files /dev/null and b/android/FucksGiven/app/src/main/ic_launcher-playstore.png differ
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/FucksGivenApplication.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/FucksGivenApplication.kt
new file mode 100644
index 0000000..d319bed
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/FucksGivenApplication.kt
@@ -0,0 +1,8 @@
+package rocks.poopjournal.fucksgiven
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class FucksGivenApplication : Application() {
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/MainActivity.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/MainActivity.kt
new file mode 100644
index 0000000..4b5b0c3
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/MainActivity.kt
@@ -0,0 +1,52 @@
+package rocks.poopjournal.fucksgiven
+
+import android.app.LocaleConfig
+import android.app.LocaleManager
+import android.os.Build
+import android.os.Bundle
+import android.os.LocaleList
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.runtime.collectAsState
+import androidx.navigation.compose.rememberNavController
+import dagger.hilt.android.AndroidEntryPoint
+import rocks.poopjournal.fucksgiven.presentation.navigation.NavGraph
+import rocks.poopjournal.fucksgiven.presentation.ui.theme.FucksGivenTheme
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.AppTheme
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.ThemeSetting
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MainActivity : ComponentActivity() {
+ @Inject
+ lateinit var themeSetting: ThemeSetting
+
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ val localeManager = applicationContext
+ .getSystemService(LocaleManager::class.java)
+ localeManager.overrideLocaleConfig = LocaleConfig(
+ LocaleList.forLanguageTags("en-US,de,ur,fr")
+ )
+
+ val overrideLocaleConfig = localeManager.overrideLocaleConfig
+ val supportedLocales = overrideLocaleConfig?.supportedLocales
+
+ val theme = themeSetting.themeFlow.collectAsState()
+ val useDarkColors = when (theme.value) {
+ AppTheme.LIGHT -> false
+ AppTheme.FOLLOW_SYSTEM -> isSystemInDarkTheme()
+ AppTheme.DARK -> true
+ }
+ FucksGivenTheme(darkTheme = useDarkColors) {
+ NavGraph(navController = rememberNavController())
+ }
+ }
+ }
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/DatabaseBackup.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/DatabaseBackup.kt
new file mode 100644
index 0000000..4c30887
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/DatabaseBackup.kt
@@ -0,0 +1,79 @@
+package rocks.poopjournal.fucksgiven.data
+
+import android.content.Context
+import android.content.Intent
+import android.widget.Toast
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.SQLITE_SHMFILE_SUFFIX
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.SQLITE_WALFILE_SUFFIX
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.THEDATABASE_DATABASE_BACKUP_SUFFIX
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.THEDATABASE_DATABASE_NAME
+import java.io.File
+import java.io.IOException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DatabaseBackupManager @Inject constructor(
+ private val context: Context,
+ private val fuckDatabase: FuckDatabase
+) {
+ fun backupDatabase(): Int {
+ var result = -99
+ val dbFile = context.getDatabasePath(THEDATABASE_DATABASE_NAME)
+ val dbWalFile = File(dbFile.path + SQLITE_WALFILE_SUFFIX)
+ val dbShmFile = File(dbFile.path + SQLITE_SHMFILE_SUFFIX)
+ val bkpFile = File(dbFile.path + THEDATABASE_DATABASE_BACKUP_SUFFIX)
+ val bkpWalFile = File(bkpFile.path + SQLITE_WALFILE_SUFFIX)
+ val bkpShmFile = File(bkpFile.path + SQLITE_SHMFILE_SUFFIX)
+ if (bkpFile.exists()) bkpFile.delete()
+ if (bkpWalFile.exists()) bkpWalFile.delete()
+ if (bkpShmFile.exists()) bkpShmFile.delete()
+ checkpoint()
+ try {
+ dbFile.copyTo(bkpFile, true)
+ if (dbWalFile.exists()) dbWalFile.copyTo(bkpWalFile, true)
+ if (dbShmFile.exists()) dbShmFile.copyTo(bkpShmFile, true)
+ result = 0
+ Toast.makeText(context, "Database backed up Successfully", Toast.LENGTH_SHORT).show()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ return result
+ }
+
+ fun restoreDatabase(restart: Boolean = true) {
+ val backupFilePath =
+ context.getDatabasePath(THEDATABASE_DATABASE_NAME).path + THEDATABASE_DATABASE_BACKUP_SUFFIX
+ if (!File(backupFilePath).exists()) {
+ return
+ }
+ if (fuckDatabase == null) return
+ val dbPath = fuckDatabase.openHelper.readableDatabase.path
+ val dbFile = File(dbPath)
+ val dbWalFile = File(dbFile.path + SQLITE_WALFILE_SUFFIX)
+ val dbShmFile = File(dbFile.path + SQLITE_SHMFILE_SUFFIX)
+ val bkpFile = File(dbFile.path + THEDATABASE_DATABASE_BACKUP_SUFFIX)
+ val bkpWalFile = File(bkpFile.path + SQLITE_WALFILE_SUFFIX)
+ val bkpShmFile = File(bkpFile.path + SQLITE_SHMFILE_SUFFIX)
+ try {
+ bkpFile.copyTo(dbFile, true)
+ if (bkpWalFile.exists()) bkpWalFile.copyTo(dbWalFile, true)
+ if (bkpShmFile.exists()) bkpShmFile.copyTo(dbShmFile, true)
+ checkpoint()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ if (restart) {
+ val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
+ intent!!.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ context.startActivity(intent)
+ System.exit(0)
+ }
+ }
+
+ private fun checkpoint() {
+ val db = fuckDatabase.openHelper.writableDatabase
+ db.query("PRAGMA wal_checkpoint(FULL);", emptyArray())
+ db.query("PRAGMA wal_checkpoint(TRUNCATE);", emptyArray())
+ }
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDao.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDao.kt
new file mode 100644
index 0000000..3c32c3f
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDao.kt
@@ -0,0 +1,25 @@
+package rocks.poopjournal.fucksgiven.data
+
+import androidx.lifecycle.LiveData
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import kotlinx.coroutines.flow.Flow
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.THETABLE_TABLENAME
+
+@Dao
+interface FuckDao {
+ @Query("SELECT * from $THETABLE_TABLENAME")
+ fun getAllData(): Flow>
+
+ @Query("SELECT * from $THETABLE_TABLENAME WHERE id = :id")
+ fun getData(id: Int): Flow
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insert(data: FuckData)
+
+ @Query("SELECT * FROM $THETABLE_TABLENAME WHERE date BETWEEN :startDate AND :endDate")
+ fun getDataBetweenDates(startDate: Long, endDate: Long): LiveData>
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckData.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckData.kt
new file mode 100644
index 0000000..48fbb67
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckData.kt
@@ -0,0 +1,13 @@
+package rocks.poopjournal.fucksgiven.data
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.THETABLE_TABLENAME
+
+@Entity(tableName = THETABLE_TABLENAME)
+data class FuckData(
+ @PrimaryKey(autoGenerate = true)
+ val id: Int = 0,
+ val description : String,
+ val date: Long
+)
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDatabase.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDatabase.kt
new file mode 100644
index 0000000..86ebe3f
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckDatabase.kt
@@ -0,0 +1,9 @@
+package rocks.poopjournal.fucksgiven.data
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+
+@Database(entities = [FuckData::class], version = 1, exportSchema = false)
+abstract class FuckDatabase : RoomDatabase() {
+ abstract fun fuckDao(): FuckDao
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckRepository.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckRepository.kt
new file mode 100644
index 0000000..84d0d27
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/FuckRepository.kt
@@ -0,0 +1,66 @@
+package rocks.poopjournal.fucksgiven.data
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+import java.util.Calendar
+import javax.inject.Inject
+
+class FuckRepository @Inject constructor(
+ private val fuckDao: FuckDao
+) {
+ fun getAllFucks() : Flow> = fuckDao.getAllData().flowOn(Dispatchers.IO).conflate()
+ fun getFuck(id: Int) : Flow = fuckDao.getData(id).flowOn(Dispatchers.IO).conflate()
+ suspend fun insertFuck(fuckData: FuckData) = fuckDao.insert(fuckData)
+
+ fun getWeeklyData(): LiveData> {
+ val calendar = Calendar.getInstance().apply {
+ firstDayOfWeek = Calendar.MONDAY
+ set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
+ set(Calendar.HOUR_OF_DAY, 0)
+ set(Calendar.MINUTE, 0)
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }
+ val startOfWeek = calendar.timeInMillis
+ calendar.add(Calendar.DAY_OF_WEEK, 7)
+ val endOfWeek = calendar.timeInMillis
+
+ return fuckDao.getDataBetweenDates(startOfWeek, endOfWeek)
+ }
+
+ fun getMonthlyData(): LiveData> {
+ val calendar = Calendar.getInstance().apply {
+ set(Calendar.DAY_OF_MONTH, 1)
+ set(Calendar.HOUR_OF_DAY, 0)
+ set(Calendar.MINUTE, 0)
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }
+ val startOfMonth = calendar.timeInMillis
+ calendar.add(Calendar.MONTH, 1)
+ calendar.add(Calendar.DATE, -1)
+ val endOfMonth = calendar.timeInMillis
+
+ return fuckDao.getDataBetweenDates(startOfMonth, endOfMonth)
+ }
+
+ fun getYearlyData(): LiveData> {
+ val calendar = Calendar.getInstance().apply {
+ set(Calendar.DAY_OF_YEAR, 1)
+ set(Calendar.HOUR_OF_DAY, 0)
+ set(Calendar.MINUTE, 0)
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }
+ val startOfYear = calendar.timeInMillis
+ calendar.add(Calendar.YEAR, 1)
+ calendar.add(Calendar.DATE, -1)
+ val endOfYear = calendar.timeInMillis
+ return fuckDao.getDataBetweenDates(startOfYear, endOfYear)
+ }
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/ThemeRepositoryImpl.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/ThemeRepositoryImpl.kt
new file mode 100644
index 0000000..21b4e30
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/data/ThemeRepositoryImpl.kt
@@ -0,0 +1,39 @@
+package rocks.poopjournal.fucksgiven.data
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.core.content.edit
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.MutableStateFlow
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.AppTheme
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.ThemeSetting
+import javax.inject.Inject
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+class ThemeSettingImpl @Inject constructor(
+ @ApplicationContext context: Context,
+) : ThemeSetting {
+ override var theme: AppTheme by AppThemePreferenceDelegate("app_theme", AppTheme.LIGHT)
+ override val themeFlow: MutableStateFlow
+ private val preferences: SharedPreferences =
+ context.getSharedPreferences("sample_theme", Context.MODE_PRIVATE)
+ init {
+ themeFlow = MutableStateFlow(theme)
+ }
+ inner class AppThemePreferenceDelegate(
+ private val name: String,
+ private val default: AppTheme,
+ ) : ReadWriteProperty {
+ override fun getValue(thisRef: Any, property: KProperty<*>): AppTheme =
+ AppTheme.fromOrdinal(preferences.getInt(name, default.ordinal))
+
+ override fun setValue(thisRef: Any, property: KProperty<*>, value: AppTheme) {
+ themeFlow.value = value
+ preferences.edit {
+ putInt(name,value.ordinal)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/AppModule.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/AppModule.kt
new file mode 100644
index 0000000..b02414a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/AppModule.kt
@@ -0,0 +1,41 @@
+package rocks.poopjournal.fucksgiven.di
+
+import android.content.Context
+import androidx.room.Room
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import rocks.poopjournal.fucksgiven.data.DatabaseBackupManager
+import rocks.poopjournal.fucksgiven.data.FuckDao
+import rocks.poopjournal.fucksgiven.data.FuckDatabase
+import rocks.poopjournal.fucksgiven.data.ThemeSettingImpl
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.THEDATABASE_DATABASE_NAME
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+object FuckAppModule {
+ @Singleton
+ @Provides
+ fun provideFuckDao(fuckDatabase: FuckDatabase ): FuckDao = fuckDatabase.fuckDao()
+
+ @Singleton
+ @Provides
+ fun provideFuckDatabase(@ApplicationContext context: Context): FuckDatabase =
+ Room.databaseBuilder(
+ context,
+ FuckDatabase::class.java,
+ THEDATABASE_DATABASE_NAME
+ ).build()
+
+ @Singleton
+ @Provides
+ fun provideDatabaseBackupManager(
+ @ApplicationContext context: Context,
+ fuckDatabase: FuckDatabase
+ ): DatabaseBackupManager = DatabaseBackupManager(context, fuckDatabase)
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/SettingModule.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/SettingModule.kt
new file mode 100644
index 0000000..b9d8d43
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/di/SettingModule.kt
@@ -0,0 +1,19 @@
+package rocks.poopjournal.fucksgiven.di
+
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import rocks.poopjournal.fucksgiven.data.ThemeSettingImpl
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.ThemeSetting
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class SettingModule {
+ @Binds
+ @Singleton
+ abstract fun bindThemeSetting(
+ themeSettingImpl: ThemeSettingImpl
+ ) : ThemeSetting
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/BottomBar.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/BottomBar.kt
new file mode 100644
index 0000000..eec6ddb
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/BottomBar.kt
@@ -0,0 +1,83 @@
+package rocks.poopjournal.fucksgiven.presentation.component
+
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.NavigationBarItemDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.navigation.HOME_SCREEN
+import rocks.poopjournal.fucksgiven.presentation.navigation.STATS_SCREEN
+import rocks.poopjournal.fucksgiven.presentation.ui.theme.FuckGreen
+
+data class BottomNavigationItem(
+ val selectedIcon: Int,
+ val unselectedIcon: Int,
+ val route: String,
+)
+
+
+object BottomBar {
+ fun getMenuBottomItems() = mutableListOf(
+ BottomNavigationItem(
+ selectedIcon = R.drawable.selected_home,
+ unselectedIcon = R.drawable.home,
+ route = HOME_SCREEN
+ ),
+ BottomNavigationItem(
+ selectedIcon = R.drawable.selected_graph,
+ unselectedIcon = R.drawable.graph,
+ route = STATS_SCREEN
+ ),
+ )
+}
+
+@Composable
+fun BottomNavBar(
+ navHostController: NavHostController,
+ items: List
+) {
+ val navBackStackEntry by navHostController.currentBackStackEntryAsState()
+ val currentDestination = navBackStackEntry?.destination
+ val currentRoute = currentDestination?.route
+
+ NavigationBar(containerColor = MaterialTheme.colorScheme.background) {
+ items.forEachIndexed { index, bottomNavigationItem ->
+ val isSelected = currentRoute == bottomNavigationItem.route
+ NavigationBarItem(
+ selected = isSelected,
+ onClick = {
+ if (!isSelected) {
+ navHostController.navigate(bottomNavigationItem.route) {
+ navHostController.graph.startDestinationRoute?.let { screenRoute ->
+ popUpTo(screenRoute) {
+ saveState = true
+ }
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+ }
+ },
+ colors = NavigationBarItemDefaults.colors(
+ indicatorColor = MaterialTheme.colorScheme.background,
+ unselectedIconColor = Color.Gray,
+ selectedIconColor = FuckGreen,
+ ),
+ icon = {
+ Icon(
+ painter = painterResource(id = if (isSelected) bottomNavigationItem.selectedIcon else bottomNavigationItem.unselectedIcon
+ ),
+ contentDescription = bottomNavigationItem.route
+ )
+ },
+ )
+ }
+ }
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Chart.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Chart.kt
new file mode 100644
index 0000000..1679fec
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Chart.kt
@@ -0,0 +1,154 @@
+package rocks.poopjournal.fucksgiven.presentation.component
+
+import android.graphics.Typeface
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.res.ResourcesCompat
+import androidx.core.text.layoutDirection
+import com.github.mikephil.charting.charts.LineChart
+import com.github.mikephil.charting.components.XAxis
+import com.github.mikephil.charting.data.Entry
+import com.github.mikephil.charting.data.LineData
+import com.github.mikephil.charting.data.LineDataSet
+import com.github.mikephil.charting.formatter.IndexAxisValueFormatter
+import com.github.mikephil.charting.formatter.ValueFormatter
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.ui.theme.FuckGreen
+import java.util.Locale
+
+@Composable
+fun LineChartComposable(
+ lineDataPoints: List,
+ xCount : Int
+
+) {
+ val context1 = LocalContext.current
+ val entries = lineDataPoints.mapIndexed { index, dataPoint ->
+ Entry(index.toFloat(), dataPoint.yValue.toFloat())
+ }
+
+ val tf = ResourcesCompat.getFont(context1, R.font.opensans_regular)
+ AndroidView(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(300.dp),
+ factory = { context ->
+ LineChart(context).apply {
+ layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ setBackgroundColor(Color.White.toArgb())
+ xAxis.position = XAxis.XAxisPosition.BOTTOM
+ axisRight.isEnabled = true
+ axisLeft.isEnabled = false
+ axisRight.textColor = Color.Black.toArgb()
+ xAxis.textColor = Color.Black.toArgb()
+ legend.isEnabled = false
+
+ // Customizing the Line Chart
+ description.isEnabled = false
+ setDrawGridBackground(false)
+
+ // Data Setup
+
+ val dataSet = LineDataSet(entries, "Label").apply {
+ color = FuckGreen.toArgb()
+ valueTextColor = Color.Black.toArgb()
+ lineWidth = 2f
+ setDrawCircles(true)
+ setCircleColor(FuckGreen.toArgb())
+ setDrawValues(false)
+ setPinchZoom(false)
+ }
+
+ val lineData = LineData(dataSet)
+ this.data = lineData
+
+ // XAxis configuration
+ xAxis.valueFormatter = IndexAxisValueFormatter(lineDataPoints.map { it.xValue })
+ xAxis.granularity = 1f
+ xAxis.labelCount = xCount
+ xAxis.position = XAxis.XAxisPosition.BOTTOM
+ xAxis.isGranularityEnabled = true
+ xAxis.setDrawGridLines(true)
+ xAxis.setAvoidFirstLastClipping(true)
+ xAxis.setTextSize(14f)
+ xAxis.typeface = tf
+
+
+ axisRight.valueFormatter = object : ValueFormatter() {
+ override fun getFormattedValue(value: Float): String {
+ return value.toInt().toString()
+ }
+ }
+ // YAxis configuration
+ axisRight.granularity = 1f
+ axisRight.setDrawGridLines(true)
+ // For 0, 5, 10
+ axisRight.setLabelCount(3,true)
+ axisRight.axisMinimum = 0f
+// axisRight.axisMaximum = 10f
+ axisRight.isGranularityEnabled = true
+ notifyDataSetChanged()
+ invalidate() // Refresh the chart
+ }
+ },
+ update = { chart ->
+
+ val dataSet = LineDataSet(entries, "Label").apply {
+ color = FuckGreen.toArgb()
+ valueTextColor = Color.Black.toArgb()
+ lineWidth = 2f
+ setDrawCircles(true)
+ setCircleColor(FuckGreen.toArgb())
+ setDrawValues(false)
+ }
+
+ chart.data = LineData(dataSet)
+
+ // XAxis configuration
+ chart.xAxis.valueFormatter = IndexAxisValueFormatter(lineDataPoints.map { it.xValue })
+ chart.xAxis.granularity = 1f
+ chart.xAxis.labelCount = xCount
+ chart.xAxis.position = XAxis.XAxisPosition.BOTTOM
+ chart.xAxis.isGranularityEnabled = true
+ chart.xAxis.setDrawGridLines(true)
+ chart.xAxis.setAvoidFirstLastClipping(true)
+ chart.xAxis.setTextSize(14f)
+ chart.xAxis.typeface = tf
+
+ // YAxis configuration
+ chart.axisRight.valueFormatter = object : ValueFormatter() {
+ override fun getFormattedValue(value: Float): String {
+ return value.toInt().toString()
+ }
+ }
+ chart.axisRight.granularity = 1f
+ chart.axisRight.setDrawGridLines(true)
+ chart.axisRight.setLabelCount(3,true)
+ chart.axisRight.axisMinimum = 0f
+// chart.axisRight.axisMaximum = 10f
+ chart.axisRight.isGranularityEnabled = true
+ chart.notifyDataSetChanged()
+
+ chart.invalidate() // Refresh the chart
+ }
+ )
+}
+
+
+data class LineDataPoint(val xValue: String, val yValue: Int)
+
+
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Horizontal Pager.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Horizontal Pager.kt
new file mode 100644
index 0000000..385447c
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/Horizontal Pager.kt
@@ -0,0 +1,288 @@
+package rocks.poopjournal.fucksgiven.presentation.component
+
+import android.util.Log
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.PagerState
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.StatsViewModel
+import java.text.SimpleDateFormat
+import java.util.Calendar
+import java.util.Locale
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun HorizontalPagerView(
+ pagerState: PagerState,
+ viewModel: StatsViewModel,
+
+ ) {
+ val weeklyData by viewModel.weeklyData.observeAsState(emptyList())
+ val monthlyData by viewModel.monthlyData.observeAsState(emptyList())
+ val yearlyData by viewModel.yearlyData.observeAsState(emptyList())
+
+
+ //weekly data processing
+ val weeklyXValues = listOf(
+ stringResource(id = R.string.m),
+ stringResource(id = R.string.t),
+ stringResource(id = R.string.w),
+ stringResource(id = R.string.th),
+ stringResource(id = R.string.f),
+ stringResource(id = R.string.s),
+ stringResource(id = R.string.su)
+ )
+ // Create a list of LineDataPoint objects
+ val weeklyLineDataPoints = weeklyXValues.map { day ->
+ val dayOfWeek = getDayOfWeek(day)
+ val count = weeklyData.count { data ->
+ val calendar = Calendar.getInstance()
+ calendar.timeInMillis = data.date
+ calendar.get(Calendar.DAY_OF_WEEK) == dayOfWeek
+ }
+ LineDataPoint(day, count)
+ }
+
+ val total = weeklyLineDataPoints.sumOf { it.yValue }
+ val weeklyAverage: Double = if (weeklyLineDataPoints.isNotEmpty()) {
+ total.toDouble() / weeklyLineDataPoints.size
+ } else {
+ 0.0
+ }
+
+
+ val calendar1 = Calendar.getInstance()
+ calendar1.firstDayOfWeek = Calendar.MONDAY
+ while (calendar1.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
+ calendar1.add(Calendar.DATE, -1)
+ }
+ val weekStart = calendar1.time
+ calendar1.add(Calendar.DATE, 6)
+ val weekEnd = calendar1.time
+ val dateFormat = SimpleDateFormat("dd", Locale.getDefault())
+ val weekStartStr = dateFormat.format(weekStart)
+ val weekEndStr = dateFormat.format(weekEnd)
+ val currentWeekRange = "$weekStartStr - $weekEndStr"
+
+ //monthly data processing
+ val monthlyXValues = listOf(
+ stringResource(id = R.string.one),
+ stringResource(id = R.string.two),
+ stringResource(id = R.string.three),
+ stringResource(id = R.string.four),
+ stringResource(id = R.string.five),
+ stringResource(id = R.string.six),
+ stringResource(id = R.string.seven),
+ stringResource(id = R.string.eight),
+ stringResource(id = R.string.nine),
+ stringResource(id = R.string.ten),
+ stringResource(id = R.string.eleven),
+ stringResource(id = R.string.twelve),
+ stringResource(id = R.string.thirteen),
+ stringResource(id = R.string.fourteen),
+ stringResource(id = R.string.fifteen),
+ stringResource(id = R.string.sixteen),
+ stringResource(id = R.string.seventeen),
+ stringResource(id = R.string.eighteen),
+ stringResource(id = R.string.nineteen),
+ stringResource(id = R.string.twenty),
+ stringResource(id = R.string.twentyone),
+ stringResource(id = R.string.twentytwo),
+ stringResource(id = R.string.twentythree),
+ stringResource(id = R.string.twentyfour),
+ stringResource(id = R.string.twentyfive),
+ stringResource(id = R.string.twentysix),
+ stringResource(id = R.string.twentyseven),
+ stringResource(id = R.string.twentyeight),
+ stringResource(id = R.string.twentynine),
+ stringResource(id = R.string.thirty),
+ stringResource(id = R.string.thirtyone)
+ )
+ val monthlyLineDataPoints = monthlyXValues.map { day ->
+ val dayOfMonth = day.toInt()
+ val count = monthlyData.count { data ->
+ val calendar = Calendar.getInstance()
+ calendar.timeInMillis = data.date
+ calendar.get(Calendar.DAY_OF_MONTH) == dayOfMonth
+ }
+ LineDataPoint(day, count)
+ }
+ val totalMonthly = monthlyLineDataPoints.sumOf { it.yValue }
+ val monthlyAverage: Double =
+ if (monthlyLineDataPoints.isNotEmpty()) totalMonthly.toDouble() / monthlyLineDataPoints.size else 0.0
+
+ val currentMonth =
+ Calendar.getInstance().getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
+ Log.d("MonthlyData", "Monthly data: $monthlyLineDataPoints , $monthlyAverage")
+
+ //yearly data processing
+ val yearlyXValues = listOf(
+ stringResource(id = R.string.jan),
+ stringResource(id = R.string.Feb),
+ stringResource(id = R.string.Mar),
+ stringResource(id = R.string.April),
+ stringResource(id = R.string.May),
+ stringResource(id = R.string.june),
+ stringResource(id = R.string.july),
+ stringResource(id = R.string.aug),
+ stringResource(id = R.string.sep),
+ stringResource(id = R.string.oct),
+ stringResource(id = R.string.nov),
+ stringResource(id = R.string.dec)
+ )
+ val yearlyLineDataPoints = yearlyXValues.mapIndexed { index, month ->
+ val monthOfYear = index + 1
+ val count = yearlyData.count { data ->
+ val calendar = Calendar.getInstance()
+ calendar.timeInMillis = data.date
+ calendar.get(Calendar.MONTH) == monthOfYear - 1 // Calendar.MONTH is zero-based
+ }
+ LineDataPoint(month, count)
+ }
+ val totalYearly = yearlyLineDataPoints.sumOf { it.yValue }
+ val yearlyAverage: Double =
+ if (yearlyLineDataPoints.isNotEmpty()) totalYearly.toDouble() / yearlyLineDataPoints.size else 0.0
+
+
+ HorizontalPager(
+ state = pagerState,
+ userScrollEnabled = false,
+ modifier = Modifier.padding(top = 20.dp, start = 20.dp, end = 20.dp)
+ ) { page ->
+ when (page) {
+ 0 -> {
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 10.dp, bottom = 10.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = when {
+ weeklyAverage == 0.0 -> "0"
+ weeklyAverage < 1.0 -> "<1"
+ else -> weeklyAverage.toString()
+ },
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(end = 3.dp),
+ style = MaterialTheme.typography.titleLarge
+ )
+ Text(
+ text = stringResource(id = R.string.average_fucks),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+
+ Text(
+ text = "Week $currentWeekRange",
+ modifier = Modifier.padding(end = 3.dp, bottom = 5.dp, start = 10.dp),
+ style = MaterialTheme.typography.bodyLarge,
+ fontWeight = FontWeight.W400
+ )
+
+ LineChartComposable(
+ lineDataPoints = weeklyLineDataPoints,
+ xCount = weeklyLineDataPoints.size
+ )
+ }
+ }
+
+ 1 -> {
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 10.dp, bottom = 10.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = when {
+ monthlyAverage == 0.0 -> "0"
+ monthlyAverage < 1.0 -> "<1"
+ else -> monthlyAverage.toString()
+ },
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(end = 3.dp),
+ style = MaterialTheme.typography.titleLarge
+ )
+ Text(
+ text = stringResource(id = R.string.average_fucks),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+ Text(
+ text = "$currentMonth 1-31",
+ modifier = Modifier.padding(end = 3.dp, bottom = 5.dp, start = 10.dp),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ LineChartComposable(lineDataPoints = monthlyLineDataPoints, xCount = 6)
+ }
+ }
+
+ 2 -> {
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 10.dp, bottom = 10.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = when {
+ yearlyAverage == 0.0 -> "0"
+ yearlyAverage < 1.0 -> "<1"
+ else -> yearlyAverage.toString()
+ },
+ modifier = Modifier.padding(end = 3.dp),
+ fontWeight = FontWeight.Bold,
+ style = MaterialTheme.typography.titleLarge
+ )
+ Text(
+ text = stringResource(id = R.string.average_fucks),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+ Text(
+ text = stringResource(id = R.string.january_december),
+ modifier = Modifier.padding(end = 3.dp, bottom = 5.dp, start = 10.dp),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ LineChartComposable(
+ lineDataPoints = yearlyLineDataPoints,
+ xCount = yearlyLineDataPoints.size
+ )
+ }
+ }
+ }
+ }
+}
+
+fun getDayOfWeek(day: String): Int {
+ return when (day) {
+ "M" -> Calendar.MONDAY
+ "T" -> Calendar.TUESDAY
+ "W" -> Calendar.WEDNESDAY
+ "TH" -> Calendar.THURSDAY
+ "F" -> Calendar.FRIDAY
+ "S" -> Calendar.SATURDAY
+ "SU" -> Calendar.SUNDAY
+ else -> throw IllegalArgumentException("Invalid day of the week")
+ }
+}
+
+
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/ThemeChangeDialog.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/ThemeChangeDialog.kt
new file mode 100644
index 0000000..5ae03b0
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/ThemeChangeDialog.kt
@@ -0,0 +1,111 @@
+package rocks.poopjournal.fucksgiven.presentation.component
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.foundation.selection.selectableGroup
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.RadioButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.dp
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.AppTheme
+
+
+@Composable
+fun ThemeContent(
+ selectedTheme: AppTheme,
+ onItemSelect: (AppTheme) -> Unit,
+ modifier: Modifier = Modifier
+) {
+ val themeItems = listOf(
+ RadioItems(
+ id = AppTheme.LIGHT.ordinal,
+ name = stringResource(id = R.string.light_theme)
+ ),
+ RadioItems(
+ id = AppTheme.DARK.ordinal,
+ name = stringResource(id = R.string.dark_theme)
+ ),
+ RadioItems(
+ id = AppTheme.FOLLOW_SYSTEM.ordinal,
+ name = stringResource(id = R.string.follow_system)
+ )
+ )
+
+ Column(
+ modifier = modifier
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ RadioGroup(
+ items = themeItems,
+ selected = selectedTheme.ordinal,
+ onItemSelected = { id -> onItemSelect(AppTheme.fromOrdinal(id)) },
+ )
+ }
+}
+
+data class RadioItems(
+ var id: Int,
+ var name: String,
+)
+
+@Composable
+fun RadioGroup(
+ items: Iterable,
+ selected: Int,
+ onItemSelected: ((Int) -> Unit)?,
+ modifier: Modifier = Modifier
+) {
+ Column(
+ modifier = modifier
+ .selectableGroup()
+ ) {
+ items.forEach { item ->
+ RadioGroupItems(
+ items = item,
+ selected = selected == item.id,
+ onClick = { onItemSelected?.invoke(item.id) },
+ )
+ }
+ }
+}
+
+@Composable
+private fun RadioGroupItems(
+ items: RadioItems,
+ selected: Boolean,
+ onClick: ((Int) -> Unit)?,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier = modifier
+ .selectable(
+ selected = selected,
+ onClick = { onClick?.invoke(items.id) },
+ role = Role.RadioButton
+ )
+ .fillMaxWidth()
+ .padding(top = 8.dp, bottom = 8.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ RadioButton(selected = selected, onClick = null)
+ Spacer(modifier = modifier.width(5.dp))
+ Text(
+ text = items.name,
+ color = MaterialTheme.colorScheme.onSurface,
+ style = MaterialTheme.typography.bodySmall
+ )
+ }
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/TopAppBar.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/TopAppBar.kt
new file mode 100644
index 0000000..5c8ef6d
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/component/TopAppBar.kt
@@ -0,0 +1,41 @@
+package rocks.poopjournal.fucksgiven.presentation.component
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.navigation.NavHostController
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.navigation.SETTINGS_SCREEN
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AppBar(
+ title: String,
+ navigate : NavHostController
+) {
+ TopAppBar(title = {
+ Text(text = title, style = MaterialTheme.typography.titleLarge)
+ },
+ colors = TopAppBarDefaults.topAppBarColors(
+ containerColor = MaterialTheme.colorScheme.background
+ ) ,
+ actions = {
+ IconButton(onClick = { navigate.navigate(SETTINGS_SCREEN) }) {
+ Icon(
+ painter = painterResource(id = R.drawable.settings),
+ contentDescription = stringResource(id = R.string.settings),
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+ })
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/AppRoutes.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/AppRoutes.kt
new file mode 100644
index 0000000..05784fc
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/AppRoutes.kt
@@ -0,0 +1,6 @@
+package rocks.poopjournal.fucksgiven.presentation.navigation
+
+const val HOME_SCREEN = "HomeScreen"
+const val SETTINGS_SCREEN = "SettingsScreen"
+const val STATS_SCREEN = "StatsScreen"
+const val ABOUT_SCREEN = "AboutScreen"
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/NavGraph.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/NavGraph.kt
new file mode 100644
index 0000000..ab405db
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/navigation/NavGraph.kt
@@ -0,0 +1,42 @@
+package rocks.poopjournal.fucksgiven.presentation.navigation
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.runtime.Composable
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import rocks.poopjournal.fucksgiven.presentation.screens.AboutScreen
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.HomeViewModel
+import rocks.poopjournal.fucksgiven.presentation.screens.HomeScreen
+import rocks.poopjournal.fucksgiven.presentation.screens.SettingScreen
+import rocks.poopjournal.fucksgiven.presentation.screens.StatsScreen
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.SettingsViewModel
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.StatsViewModel
+
+@RequiresApi(Build.VERSION_CODES.P)
+@Composable
+fun NavGraph(navController: NavHostController){
+ val viewModel : HomeViewModel = hiltViewModel()
+ val statsViewModel : StatsViewModel = hiltViewModel()
+ val settingsViewModel : SettingsViewModel = hiltViewModel()
+
+ NavHost(navController = navController, startDestination = HOME_SCREEN) {
+ composable(route = HOME_SCREEN){
+ HomeScreen(navController,viewModel)
+ }
+ composable(route = STATS_SCREEN){
+ StatsScreen(navController = navController, viewModel = statsViewModel)
+ }
+
+ composable(route = ABOUT_SCREEN){
+ AboutScreen(navController = navController)
+ }
+
+ composable(route = SETTINGS_SCREEN){
+ SettingScreen(navController = navController, viewModel = settingsViewModel)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/AboutScreen.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/AboutScreen.kt
new file mode 100644
index 0000000..0c5c1af
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/AboutScreen.kt
@@ -0,0 +1,456 @@
+package rocks.poopjournal.fucksgiven.presentation.screens
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.text.ClickableText
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material3.Divider
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.core.content.ContextCompat.startActivity
+import androidx.navigation.NavHostController
+import rocks.poopjournal.fucksgiven.R
+
+@RequiresApi(Build.VERSION_CODES.P)
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AboutScreen(navController: NavHostController) {
+ val context = LocalContext.current
+ val packageManager = context.packageManager
+ val packageName = context.packageName
+ val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
+ } else {
+ packageManager.getPackageInfo(packageName, 0)
+ }
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Text(
+ text = stringResource(id = R.string.about),
+ style = MaterialTheme.typography.titleLarge
+ )
+ },
+ colors = TopAppBarDefaults.topAppBarColors(
+ containerColor = MaterialTheme.colorScheme.background
+ ),
+ navigationIcon = {
+ IconButton(onClick = { navController.popBackStack() }) {
+ Icon(
+ imageVector = Icons.Default.ArrowBack,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+ }
+ )
+ }
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(it)
+ .verticalScroll(rememberScrollState())
+ ) {
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.fucks),
+ contentDescription = "rounded icon",
+ modifier = Modifier
+ .size(96.dp)
+ .clip(CircleShape)
+ )
+ Text(
+ text = stringResource(id = R.string.app_name),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ val stylizedPoetry = buildAnnotatedString {
+ withStyle(style = SpanStyle(fontSize = 14.sp, fontWeight = FontWeight.W400)) {
+ append("v${packageInfo.longVersionCode}")
+ append("—")
+ withStyle(style = SpanStyle(color = MaterialTheme.colorScheme.primary)) {
+ append("Apache License 2.0")
+ addStringAnnotation(
+ tag = "URL",
+ annotation = "https://www.apache.org/licenses/LICENSE-2.0",
+ start = length - "Apache License 2.0".length,
+ end = length
+ )
+ }
+ }
+ }
+ ClickableText(text = stylizedPoetry, onClick = {})
+ Spacer(modifier = Modifier.height(10.dp))
+ Column(modifier = Modifier.padding(8.dp)) {
+ MarvinRow(context = context)
+
+ Spacer(modifier = Modifier.height(8.dp))
+ Divider(modifier = Modifier.padding(start = 12.dp))
+
+ MubeenRow(context = context)
+ }
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.contribution),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+ ContributionRow(context = context)
+ }
+
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.open_source),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+ LicenseRow(context = context)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun MarvinRow(context: Context) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Row {
+ Image(
+ painter = painterResource(id = R.drawable.marvin),
+ contentDescription = "crazy marvin",
+ modifier = Modifier
+ .size(32.dp)
+ .clip(CircleShape)
+ )
+ Spacer(modifier = Modifier.width(10.dp))
+ Column {
+ Text(
+ text = stringResource(id = R.string.crazy_marvin),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ Text(
+ text = stringResource(id = R.string.developer),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onTertiary
+ )
+
+ }
+ }
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.message),
+ contentDescription = "message",
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_SENDTO).apply {
+ data =
+ Uri.parse("mailto:marvin@poopjournal.rocks?subject=Fucks%20Given")
+ }
+ startActivity(context, intent, null)
+ }
+ )
+ Image(
+ painter = painterResource(id = R.drawable.github),
+ contentDescription = "github",
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/Crazy-Marvin")
+ }
+ startActivity(context, intent, null)
+ }
+ )
+ Image(
+ painter = painterResource(id = R.drawable.gmail),
+ contentDescription = "mail",
+ modifier = Modifier.clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://fosstodon.org/@CrazyMarvinApps")
+ }
+ startActivity(context, intent, null)
+ }
+ )
+ }
+ }
+}
+
+@Composable
+fun MubeenRow(context: Context) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Row {
+ Image(
+ painter = painterResource(id = R.drawable.mubeen),
+ contentDescription = "crazy marvin",
+ modifier = Modifier
+ .size(32.dp)
+ .clip(CircleShape),
+ contentScale = ContentScale.FillBounds
+ )
+ Spacer(modifier = Modifier.width(10.dp))
+ Column {
+ Text(
+ text = stringResource(id = R.string.mubeen),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ Text(
+ text = stringResource(id = R.string.developer),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onTertiary
+ )
+
+ }
+ }
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.message),
+ contentDescription = "message",
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_SENDTO).apply {
+ data = Uri.parse("mailto:mubeen1519@gmail.com?subject=Fucks%20Given")
+ }
+ context.startActivity(intent)
+ }
+ )
+ Image(
+ painter = painterResource(id = R.drawable.github),
+ contentDescription = "github",
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/mubeen1519")
+ }
+ context.startActivity(intent)
+ }
+ )
+ Image(
+ painter = painterResource(id = R.drawable.x),
+ contentDescription = "x",
+ modifier = Modifier.clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://twitter.com/MubeenA74")
+ }
+ context.startActivity(intent)
+ }
+ )
+ }
+ }
+}
+
+@Composable
+fun ContributionRow(context: Context) {
+ Column(modifier = Modifier.padding(8.dp)) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://hosted.weblate.org/engage/fucks-given/")
+ }
+ context.startActivity(intent)
+ }, verticalAlignment = Alignment.CenterVertically
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.translate),
+ contentDescription = "translate",
+ modifier = Modifier
+ .size(24.dp)
+ .clip(CircleShape)
+ )
+ Spacer(modifier = Modifier.width(10.dp))
+ Text(
+ text = stringResource(id = R.string.translate),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ Divider(modifier = Modifier.padding(start = 8.dp))
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/Crazy-Marvin/FucksGiven/issues")
+ }
+ context.startActivity(intent)
+ }, verticalAlignment = Alignment.CenterVertically
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.report),
+ contentDescription = "report",
+ modifier = Modifier
+ .size(24.dp)
+ .clip(CircleShape)
+ )
+ Spacer(modifier = Modifier.width(10.dp))
+ Text(
+ text = stringResource(id = R.string.report),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ Divider(modifier = Modifier.padding(start = 8.dp))
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/Crazy-Marvin/FucksGiven")
+ }
+ context.startActivity(intent)
+ }, verticalAlignment = Alignment.CenterVertically
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.source),
+ contentDescription = "source",
+ modifier = Modifier
+ .size(24.dp)
+ .clip(CircleShape)
+ )
+ Spacer(modifier = Modifier.width(10.dp))
+ Text(
+ text = stringResource(id = R.string.view_source),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ }
+ }
+}
+
+@Composable
+fun LicenseRow(context: Context) {
+ Column(modifier = Modifier
+ .padding(8.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/feathericons/feather/blob/main/LICENSE")
+ }
+ context.startActivity(intent)
+ }) {
+ Text(
+ text = stringResource(id = R.string.feather_icons),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ Text(
+ text = stringResource(id = R.string.mit_license),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onTertiary
+ )
+ }
+ Spacer(modifier = Modifier.height(8.dp))
+ Divider(modifier = Modifier.padding(start = 8.dp))
+ Column(modifier = Modifier
+ .padding(8.dp)
+ .clickable {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("https://github.com/androidx/androidx/blob/androidx-main/LICENSE.txt")
+ }
+ context.startActivity(intent)
+ }) {
+ Text(
+ text = stringResource(id = R.string.android_jetpack),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ Text(
+ text = stringResource(id = R.string.apache_license),
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.onTertiary
+ )
+ }
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/HomeScreen.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/HomeScreen.kt
new file mode 100644
index 0000000..7e43121
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/HomeScreen.kt
@@ -0,0 +1,349 @@
+package rocks.poopjournal.fucksgiven.presentation.screens
+
+import android.Manifest
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.DateRange
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DatePicker
+import androidx.compose.material3.DatePickerDefaults
+import androidx.compose.material3.DatePickerDialog
+import androidx.compose.material3.Divider
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.OutlinedTextFieldDefaults
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.material3.rememberDatePickerState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableLongStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.google.accompanist.permissions.ExperimentalPermissionsApi
+import com.google.accompanist.permissions.isGranted
+import com.google.accompanist.permissions.rememberPermissionState
+import com.google.accompanist.permissions.shouldShowRationale
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.data.FuckData
+import rocks.poopjournal.fucksgiven.presentation.component.AppBar
+import rocks.poopjournal.fucksgiven.presentation.component.BottomBar
+import rocks.poopjournal.fucksgiven.presentation.component.BottomNavBar
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.HomeViewModel
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+@OptIn(ExperimentalPermissionsApi::class)
+@Composable
+fun HomeScreen(
+ navController: NavHostController,
+ viewModel: HomeViewModel,
+) {
+ val uiState by viewModel.uiState.collectAsState()
+ val context = LocalContext.current
+ var addTaskDialogOpen by remember {
+ mutableStateOf(false)
+ }
+
+ val storagePermission = rememberPermissionState(
+ permission = Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+
+ val requestPermissionLauncher = rememberLauncherForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ // Permission granted
+ } else {
+ // Handle permission denial
+ }
+ }
+
+ LaunchedEffect(key1 = storagePermission) {
+ if (!storagePermission.status.isGranted && storagePermission.status.shouldShowRationale) {
+ // Show rationale if needed
+ } else {
+ requestPermissionLauncher.launch(Manifest.permission.CAMERA)
+ }
+
+ }
+
+
+ Scaffold(topBar = {
+ AppBar(
+ title = stringResource(id = R.string.app_name),
+ navigate = navController
+ )
+ },
+ floatingActionButton = {
+ FloatingActionButton(
+ onClick = { addTaskDialogOpen = true },
+ shape = CircleShape,
+ containerColor = MaterialTheme.colorScheme.primary
+ ) {
+ Icon(
+ imageVector = Icons.Default.Add,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.background
+ )
+ }
+ },
+ bottomBar = {
+ BottomNavBar(navHostController = navController, items = BottomBar.getMenuBottomItems())
+ }) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
+ .padding(it)
+ ) {
+ if (addTaskDialogOpen) {
+ AddDialog(onDismiss = { addTaskDialogOpen = false }) { data ->
+ viewModel.addFuck(data, context)
+ }
+ }
+ if (uiState.fuckList.isNotEmpty()) {
+ FucksList(fuckList = uiState.fuckList)
+ } else {
+ Text(
+ text = stringResource(id = R.string.no_fucks),
+ modifier = Modifier.padding(12.dp)
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun FucksList(
+ fuckList: List
+) {
+ val sortedFucks = fuckList.sortedWith(compareBy({ !isToday(getFormattedDate(it.date)) }, { -it.date }))
+
+ // Group the sorted list by date
+ val groupedFucks = sortedFucks.groupBy { getFormattedDate(it.date) }
+
+ LazyColumn {
+ groupedFucks.forEach { (date, fucks) ->
+ // Header for each date
+ item {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ val headerText = if (isToday(date)) {
+ "Today"
+ } else {
+ date
+ }
+ Text(
+ text = headerText,
+ modifier = Modifier.padding(start = 8.dp),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall
+ )
+ }
+ }
+ // Items under each date
+ items(fucks) { fuck ->
+ Column(
+ modifier = Modifier
+ .fillMaxWidth(),
+ verticalArrangement = Arrangement.Center
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = fuck.description,
+ modifier = Modifier.padding(start = 8.dp),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+ Divider(
+ color = Color.LightGray,
+ thickness = 0.5.dp,
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+ }
+ }
+ }
+}
+
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AddDialog(
+ onDismiss: () -> Unit,
+ onAdd: (FuckData) -> Unit,
+) {
+ var description by remember { mutableStateOf("") }
+ var dateDialogOpen by remember {
+ mutableStateOf(false)
+ }
+ var date by remember {
+ mutableLongStateOf(0)
+ }
+
+ val datePickerState = rememberDatePickerState()
+
+ AlertDialog(onDismissRequest = onDismiss, confirmButton = {
+ Button(
+ onClick = {
+ onAdd(
+ FuckData(description = description, date = date)
+ )
+ onDismiss()
+ }, colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.background
+ )
+ ) {
+ Text(text = stringResource(id = R.string.add))
+ }
+ }, dismissButton = {
+ TextButton(
+ onClick = onDismiss, colors = ButtonDefaults.textButtonColors(
+ contentColor = MaterialTheme.colorScheme.primary
+ )
+ ) {
+ Text(text = stringResource(id = R.string.cancel))
+ }
+ }, containerColor = MaterialTheme.colorScheme.background, text = {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(10.dp)
+ ) {
+ OutlinedTextField(
+ value = description, onValueChange = {
+ description = it
+ }, colors = OutlinedTextFieldDefaults.colors(
+ focusedBorderColor = MaterialTheme.colorScheme.primary,
+ unfocusedBorderColor = MaterialTheme.colorScheme.primary
+ ),
+ placeholder = {
+ Text(
+ text = stringResource(id = R.string.description),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+ )
+ Spacer(modifier = Modifier.height(10.dp))
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .border(
+ 1.dp,
+ shape = RoundedCornerShape(5.dp),
+ color = MaterialTheme.colorScheme.primary
+ )
+ .padding(5.dp)
+ .clickable { dateDialogOpen = true }
+ .height(50.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Text(
+ text = if (date == 0L) stringResource(id = R.string.select_date) else getFormattedDate(
+ date
+ ),
+ modifier = Modifier.padding(start = 8.dp),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ Icon(
+ imageVector = Icons.Filled.DateRange, contentDescription = stringResource(
+ id = R.string.select_date
+ )
+ )
+ }
+
+
+ if (dateDialogOpen) {
+ DatePickerDialog(onDismissRequest = { dateDialogOpen = false },
+ confirmButton = {
+ TextButton(
+ onClick = {
+ date = datePickerState.selectedDateMillis ?: 0L
+ dateDialogOpen = false
+ }) {
+ Text(text = stringResource(id = R.string.ok))
+ }
+ },
+ dismissButton = {
+ TextButton(
+ onClick = { dateDialogOpen = false }) {
+ Text(text = stringResource(id = R.string.cancel))
+ }
+ }
+ ) {
+ DatePicker(
+ state = datePickerState, colors = DatePickerDefaults.colors(
+ containerColor = MaterialTheme.colorScheme.background,
+ headlineContentColor = MaterialTheme.colorScheme.primary,
+ dayContentColor = MaterialTheme.colorScheme.primary,
+ yearContentColor = MaterialTheme.colorScheme.primary,
+ todayContentColor = MaterialTheme.colorScheme.primary,
+ selectedDayContainerColor = MaterialTheme.colorScheme.primary,
+ )
+ )
+ }
+ }
+ }
+ })
+}
+
+fun getFormattedDate(timestamp: Long): String {
+ val date = Date(timestamp)
+ val sdf = SimpleDateFormat("MMMM dd", Locale.getDefault())
+ return sdf.format(date)
+}
+
+fun isToday(dateString: String): Boolean {
+ val todayString = getFormattedDate(System.currentTimeMillis())
+ return dateString == todayString
+}
+
+
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/SettingsScreen.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/SettingsScreen.kt
new file mode 100644
index 0000000..142f49a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/SettingsScreen.kt
@@ -0,0 +1,223 @@
+package rocks.poopjournal.fucksgiven.presentation.screens
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.Divider
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.component.ThemeContent
+import rocks.poopjournal.fucksgiven.presentation.navigation.ABOUT_SCREEN
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.ThemeSetting
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.SettingsViewModel
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun SettingScreen(navController: NavHostController, viewModel: SettingsViewModel) {
+ var showDialog by remember { mutableStateOf(false) }
+
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = { Text(text = stringResource(id = R.string.settings), style = MaterialTheme.typography.titleLarge) },
+ navigationIcon = {
+ IconButton(onClick = { navController.popBackStack() }) {
+ Icon(
+ imageVector = Icons.Default.ArrowBack,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ }
+ },
+ colors = TopAppBarDefaults.topAppBarColors(
+ containerColor = MaterialTheme.colorScheme.background
+ ),
+ )
+ }
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(it)
+ ) {
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.general),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.padding(start = 11.dp)
+ )
+ }
+ Column(modifier = Modifier
+ .fillMaxWidth()
+ .padding(11.dp)
+ .clickable { showDialog = true }) {
+ Text(text = stringResource(id = R.string.apperance), style = MaterialTheme.typography.bodyLarge)
+ Text(
+ text = viewModel.themeSetting.theme.nameTheme,
+ style = MaterialTheme.typography.labelSmall,
+ fontWeight = FontWeight.Light
+ )
+ if (showDialog) {
+ ThemeSelectionDialog(
+ onDismissRequest = { showDialog = false },
+ userSetting = viewModel.themeSetting
+ )
+ }
+ }
+ }
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.data),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.padding(start = 11.dp)
+ )
+ }
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .padding(11.dp)
+ .clickable {
+ viewModel.backupDatabase()
+ },
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.backup),
+ contentDescription = stringResource(id = R.string.backup)
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(text = stringResource(id = R.string.backup), style = MaterialTheme.typography.bodyLarge)
+ }
+ Divider(
+ thickness = 0.8.dp,
+ color = Color.LightGray,
+ modifier = Modifier.padding(start = 11.dp)
+ )
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .padding(11.dp)
+ .clickable {
+ viewModel.restoreDatabase()
+ },
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.restore),
+ contentDescription = stringResource(id = R.string.restore)
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(text = stringResource(id = R.string.restore), style = MaterialTheme.typography.bodyLarge)
+ }
+ }
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .background(MaterialTheme.colorScheme.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.about),
+ color = MaterialTheme.colorScheme.primary,
+ style = MaterialTheme.typography.labelSmall,
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .padding(8.dp)
+ .clickable {
+ navController.navigate(ABOUT_SCREEN)
+ },
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.about),
+ contentDescription = "about"
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(text = stringResource(id = R.string.about), style = MaterialTheme.typography.bodyLarge)
+ }
+ }
+ }
+ }
+}
+
+
+@Composable
+fun ThemeSelectionDialog(
+ onDismissRequest: () -> Unit,
+ userSetting: ThemeSetting
+) {
+ val theme = userSetting.themeFlow.collectAsState()
+ AlertDialog(
+ onDismissRequest = onDismissRequest,
+ title = { Text(text = stringResource(id = R.string.select_theme)) },
+ text = {
+ ThemeContent(selectedTheme = theme.value, onItemSelect = { themes ->
+ userSetting.theme = themes
+ })
+ },
+ confirmButton = {
+ Button(onClick = onDismissRequest) {
+ Text(stringResource(id = R.string.ok))
+ }
+ }
+ )
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/StatsScreen.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/StatsScreen.kt
new file mode 100644
index 0000000..3997d9a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/screens/StatsScreen.kt
@@ -0,0 +1,145 @@
+package rocks.poopjournal.fucksgiven.presentation.screens
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import kotlinx.coroutines.launch
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.component.AppBar
+import rocks.poopjournal.fucksgiven.presentation.component.BottomBar
+import rocks.poopjournal.fucksgiven.presentation.component.BottomNavBar
+import rocks.poopjournal.fucksgiven.presentation.component.HorizontalPagerView
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.StatsViewModel
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun StatsScreen(navController: NavHostController, viewModel: StatsViewModel) {
+ val scope = rememberCoroutineScope()
+ val pager = rememberPagerState(pageCount = {
+ 3
+ })
+ var selectedPage by remember { mutableIntStateOf(0) } // Track selected page
+
+ Scaffold(topBar = { AppBar(title = stringResource(id = R.string.stats), navigate = navController) },
+ bottomBar = {
+ BottomNavBar(navHostController = navController, items = BottomBar.getMenuBottomItems())
+ }) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
+ .padding(it)
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ .height(IntrinsicSize.Min)
+ .border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.primary,
+ shape = RoundedCornerShape(8.dp)
+ ),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
+ ) {
+ OutlinedButton(
+ onClick = {
+ scope.launch {
+ pager.animateScrollToPage(0)
+ }
+ selectedPage = 0 // Update selected page
+ },
+ border = BorderStroke(
+ width = 1.dp,
+ color = if (selectedPage == 0) MaterialTheme.colorScheme.primary else Color.Transparent,
+ ),
+ modifier = Modifier.height(48.dp),
+ shape = RoundedCornerShape(8.dp),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = if (selectedPage == 0) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.background,
+ contentColor = MaterialTheme.colorScheme.primary
+ )
+ ) {
+ Text(stringResource(id = R.string.weekly), style = MaterialTheme.typography.bodySmall)
+ }
+ OutlinedButton(
+ onClick = {
+ scope.launch {
+ pager.animateScrollToPage(1)
+ }
+ selectedPage = 1 // Update selected page
+
+ },
+ border = BorderStroke(
+ width = 1.dp,
+ color = if (selectedPage == 1) MaterialTheme.colorScheme.primary else Color.Transparent,
+ ),
+ modifier = Modifier.height(48.dp),
+ shape = RoundedCornerShape(8.dp),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = if (selectedPage == 1) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.background,
+ contentColor = MaterialTheme.colorScheme.primary
+ )
+
+ ) {
+ Text(stringResource(id = R.string.monthly), style = MaterialTheme.typography.bodySmall)
+ }
+ OutlinedButton(
+ onClick = {
+ scope.launch {
+ pager.animateScrollToPage(2)
+ }
+ selectedPage = 2 // Update selected page
+
+ },
+ border = BorderStroke(
+ width = 1.dp,
+ color = if (selectedPage == 2) MaterialTheme.colorScheme.primary else Color.Transparent,
+ ),
+ modifier = Modifier.height(48.dp),
+ shape = RoundedCornerShape(8.dp),
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = if (selectedPage == 2) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.background,
+ contentColor = MaterialTheme.colorScheme.primary
+ )
+
+ ) {
+ Text(stringResource(id = R.string.yearly), style = MaterialTheme.typography.bodySmall)
+ }
+ }
+
+ HorizontalPagerView(
+ pagerState = pager,
+ viewModel = viewModel
+ )
+ }
+ }
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Color.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Color.kt
new file mode 100644
index 0000000..8f926c2
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Color.kt
@@ -0,0 +1,15 @@
+package rocks.poopjournal.fucksgiven.presentation.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF717184)
+val Pink40 = Color(0xFF7D5260)
+
+val FuckGreen = Color(0xFF29A331)
+val FuckSecondary = Color(0xFFEEF8EF)
+val WatchGrey = Color(0xFFC8C8D0)
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Theme.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Theme.kt
new file mode 100644
index 0000000..548d5dd
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Theme.kt
@@ -0,0 +1,68 @@
+package rocks.poopjournal.fucksgiven.presentation.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+
+val DarkColorScheme = darkColorScheme(
+ primary = FuckGreen,
+ secondary = FuckSecondary,
+ tertiary = Pink80,
+ background = Color.Black,
+ onBackground = Color.White,
+ onPrimary = WatchGrey,
+ onTertiary = PurpleGrey40
+)
+
+val LightColorScheme = lightColorScheme(
+ primary = FuckGreen,
+ secondary = FuckSecondary,
+ onBackground = Color.Black,
+ tertiary = Pink40,
+ background = Color.White,
+ onPrimary = WatchGrey,
+ onTertiary = PurpleGrey40
+
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun FucksGivenTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = false,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Type.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Type.kt
new file mode 100644
index 0000000..283788b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/theme/Type.kt
@@ -0,0 +1,65 @@
+package rocks.poopjournal.fucksgiven.presentation.ui.theme
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import rocks.poopjournal.fucksgiven.R
+
+// Set of Material typography styles to start with
+val UbuntuFamily = FontFamily(
+ Font(R.font.ubuntu_light, FontWeight.Light),
+ Font(R.font.ubuntu_regular, FontWeight.Normal),
+ Font(R.font.ubuntu_italic, FontWeight.Normal, FontStyle.Italic),
+ Font(R.font.ubuntu_medium, FontWeight.Medium),
+ Font(R.font.ubuntu_bold, FontWeight.Bold),
+ Font(R.font.opensans_regular,FontWeight.W700),
+ Font(R.font.opensans_regular,FontWeight.W400)
+)
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = UbuntuFamily,
+ fontWeight = FontWeight.W400,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = UbuntuFamily,
+ fontWeight = FontWeight.W700,
+ fontSize = 14.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp,
+ ),
+ titleLarge = TextStyle(
+ fontFamily = UbuntuFamily,
+ fontWeight = FontWeight.Bold,
+ fontSize = 24.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp,
+ ),
+
+ bodySmall = TextStyle(
+ fontFamily = UbuntuFamily,
+ fontWeight = FontWeight.W700,
+ fontSize = 14.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp,
+ )
+
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+
+ */
+)
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/Constants.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/Constants.kt
new file mode 100644
index 0000000..48586da
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/Constants.kt
@@ -0,0 +1,7 @@
+package rocks.poopjournal.fucksgiven.presentation.ui.utils
+
+ const val THETABLE_TABLENAME = "fucksTable"
+ const val THEDATABASE_DATABASE_NAME = "fucks_db"
+ const val THEDATABASE_DATABASE_BACKUP_SUFFIX = "-bkp"
+ const val SQLITE_WALFILE_SUFFIX = "-wal"
+ const val SQLITE_SHMFILE_SUFFIX = "-shm"
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/ThemeModes.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/ThemeModes.kt
new file mode 100644
index 0000000..4cbbfd9
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/ui/utils/ThemeModes.kt
@@ -0,0 +1,19 @@
+package rocks.poopjournal.fucksgiven.presentation.ui.utils
+
+import kotlinx.coroutines.flow.StateFlow
+
+enum class AppTheme(val nameTheme : String){
+ LIGHT("Light"),
+ DARK( "Dark"),
+ FOLLOW_SYSTEM( "Follow System");
+
+ companion object{
+ fun fromOrdinal(ordinal : Int) = entries[ordinal]
+ }
+}
+
+
+interface ThemeSetting {
+ val themeFlow : StateFlow
+ var theme : AppTheme
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/HomeViewModel.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/HomeViewModel.kt
new file mode 100644
index 0000000..01684ac
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/HomeViewModel.kt
@@ -0,0 +1,67 @@
+package rocks.poopjournal.fucksgiven.presentation.viewmodel
+
+import android.content.Context
+import android.widget.Toast
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import rocks.poopjournal.fucksgiven.data.FuckData
+import rocks.poopjournal.fucksgiven.data.FuckRepository
+import javax.inject.Inject
+
+data class UiState(
+ val fuckList: List = listOf(),
+ val currentlyViewedTask: FuckData? = null
+)
+
+@HiltViewModel
+class HomeViewModel @Inject constructor(
+ private val fuckRepository: FuckRepository
+) : ViewModel() {
+
+ private val _uiState = MutableStateFlow(UiState())
+ val uiState = _uiState.asStateFlow()
+
+ init {
+ viewModelScope.launch(Dispatchers.IO) {
+ fuckRepository.getAllFucks().distinctUntilChanged().collect { list ->
+ _uiState.update {
+ it.copy(
+ fuckList = list
+ )
+ }
+ }
+ }
+ }
+
+
+ fun getFuck(id: Int) {
+ viewModelScope.launch(Dispatchers.IO) {
+ fuckRepository.getFuck(id).distinctUntilChanged().collect { task ->
+ _uiState.update {
+ it.copy(
+ currentlyViewedTask = task
+ )
+ }
+ }
+ }
+ }
+
+ fun addFuck(fuck: FuckData,context: Context) {
+ if(fuck.description.isEmpty() && fuck.date == 0L){
+ Toast.makeText(context,"Fill all information",Toast.LENGTH_SHORT).show()
+ return
+ }
+ viewModelScope.launch {
+ fuckRepository.insertFuck(fuck)
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/SettingsViewModel.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/SettingsViewModel.kt
new file mode 100644
index 0000000..5965d47
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/SettingsViewModel.kt
@@ -0,0 +1,34 @@
+package rocks.poopjournal.fucksgiven.presentation.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import rocks.poopjournal.fucksgiven.data.DatabaseBackupManager
+import rocks.poopjournal.fucksgiven.presentation.ui.utils.ThemeSetting
+import javax.inject.Inject
+
+
+@HiltViewModel
+class SettingsViewModel @Inject constructor(
+ private val databaseBackupManager: DatabaseBackupManager
+) : ViewModel() {
+
+ @Inject
+ lateinit var themeSetting: ThemeSetting
+
+
+ fun backupDatabase() {
+ viewModelScope.launch {
+ val result = databaseBackupManager.backupDatabase()
+ // Handle the result
+ }
+ }
+
+ fun restoreDatabase() {
+ viewModelScope.launch {
+ databaseBackupManager.restoreDatabase()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/StatsViewModel.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/StatsViewModel.kt
new file mode 100644
index 0000000..c2c7621
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/viewmodel/StatsViewModel.kt
@@ -0,0 +1,24 @@
+package rocks.poopjournal.fucksgiven.presentation.viewmodel
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import rocks.poopjournal.fucksgiven.data.FuckData
+import rocks.poopjournal.fucksgiven.data.FuckRepository
+import javax.inject.Inject
+
+@HiltViewModel
+class StatsViewModel @Inject constructor(private val repository: FuckRepository) : ViewModel() {
+
+
+ val weeklyData: LiveData> = repository.getWeeklyData()
+ val monthlyData: LiveData> = repository.getMonthlyData()
+ val yearlyData: LiveData> = repository.getYearlyData()
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetProvider.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetProvider.kt
new file mode 100644
index 0000000..a43bd1a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetProvider.kt
@@ -0,0 +1,167 @@
+package rocks.poopjournal.fucksgiven.presentation.widget
+
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.unit.dp
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.GlanceTheme
+import androidx.glance.ImageProvider
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.appWidgetBackground
+import androidx.glance.appwidget.components.CircleIconButton
+import androidx.glance.appwidget.lazy.LazyColumn
+import androidx.glance.appwidget.lazy.items
+import androidx.glance.appwidget.provideContent
+import androidx.glance.background
+import androidx.glance.layout.Alignment
+import androidx.glance.layout.Column
+import androidx.glance.layout.Row
+import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.fillMaxWidth
+import androidx.glance.layout.height
+import androidx.glance.layout.padding
+import androidx.glance.layout.size
+import androidx.glance.text.FontFamily
+import androidx.glance.text.FontWeight
+import androidx.glance.text.Text
+import androidx.glance.text.TextStyle
+import dagger.hilt.EntryPoint
+import dagger.hilt.EntryPoints
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import rocks.poopjournal.fucksgiven.MainActivity
+import rocks.poopjournal.fucksgiven.R
+import rocks.poopjournal.fucksgiven.presentation.screens.getFormattedDate
+import rocks.poopjournal.fucksgiven.presentation.screens.isToday
+
+class MyAppWidget : GlanceAppWidget() {
+ override val sizeMode: SizeMode
+ get() = SizeMode.Exact
+ override suspend fun provideGlance(context: Context, id: GlanceId) {
+ val appContext = context.applicationContext
+ val viewModel =
+ EntryPoints.get(
+ appContext,
+ AppWidgetEntryPoint::class.java,
+ ).getViewModel()
+
+ provideContent {
+ WidgetTheme {
+ val uiState by viewModel.uiState.collectAsState()
+ val list = uiState.fuckList ?: emptyList()
+ Column(
+ modifier = GlanceModifier
+ .fillMaxSize()
+ .background(ImageProvider(R.drawable.app_widget_background))
+ .appWidgetBackground()
+ .padding(5.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Row(
+ modifier = GlanceModifier.fillMaxWidth().padding(10.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalAlignment = Alignment.End
+ ) {
+ Text(
+ text = "Fucks Given", // Replace with a plain string
+ modifier = GlanceModifier.defaultWeight(),
+ style = TextStyle(
+ fontFamily = FontFamily.SansSerif,
+ fontWeight = FontWeight.Bold
+ )
+ )
+
+ CircleIconButton(
+ imageProvider = ImageProvider(R.drawable.baseline_add_24),
+ onClick = {
+ Intent(context, MainActivity::class.java).apply {
+ flags = FLAG_ACTIVITY_NEW_TASK
+ context.startActivity(this)
+ }
+ },
+ contentDescription = "",
+ modifier = GlanceModifier
+ .size(34.dp)
+ .background(GlanceTheme.colors.onBackground)
+ .padding(8.dp),
+ contentColor = GlanceTheme.colors.tertiary,
+ backgroundColor = GlanceTheme.colors.onBackground
+ )
+ }
+ if (list.isNotEmpty()) {
+ val sortedFucks = list.sortedWith(compareBy({ !isToday(getFormattedDate(it.date)) }, { -it.date }))
+
+ // Group the sorted list by date
+ val groupedFucks = sortedFucks.groupBy { getFormattedDate(it.date) }
+ LazyColumn(modifier = GlanceModifier.padding(top = 8.dp)) {
+ groupedFucks.forEach { (date, fucks) ->
+ item {
+ Row(
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ .height(20.dp).background(GlanceTheme.colors.secondary),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ val headerText = if (isToday(date)) {
+ "Today"
+ } else {
+ date
+ }
+ Text(
+ text = headerText,
+ modifier = GlanceModifier.padding(start = 8.dp),
+ style = TextStyle(
+ color = GlanceTheme.colors.onBackground,
+ fontFamily = FontFamily.SansSerif
+ )
+ )
+ }
+ }
+ items(fucks) { fuck ->
+ Column(
+ modifier = GlanceModifier
+ .fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Row(
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ .height(20.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = fuck.description,
+ modifier = GlanceModifier.padding(start = 8.dp),
+ )
+ }
+ }
+ }
+ }
+ }
+ } else {
+ Text(
+ text = "No fucks given", // Replace with a plain string
+ modifier = GlanceModifier.padding(12.dp)
+ )
+ }
+ }
+ }
+ }
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent::class)
+ interface AppWidgetEntryPoint {
+ fun getViewModel(): AppWidgetViewModel
+ }
+}
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetReceiver.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetReceiver.kt
new file mode 100644
index 0000000..f11e84a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/TaskWidgetReceiver.kt
@@ -0,0 +1,9 @@
+package rocks.poopjournal.fucksgiven.presentation.widget
+
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+
+class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
+ override val glanceAppWidget: GlanceAppWidget
+ get() = MyAppWidget()
+}
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetTheme.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetTheme.kt
new file mode 100644
index 0000000..a1f139e
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetTheme.kt
@@ -0,0 +1,54 @@
+package rocks.poopjournal.fucksgiven.presentation.widget
+
+import android.R
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.glance.GlanceTheme
+import androidx.glance.LocalContext
+import androidx.glance.material3.ColorProviders
+import rocks.poopjournal.fucksgiven.presentation.ui.theme.DarkColorScheme
+import rocks.poopjournal.fucksgiven.presentation.ui.theme.LightColorScheme
+
+@Composable
+fun WidgetTheme(
+ content: @Composable () -> Unit,
+
+ ) {
+ val resources = LocalContext.current.resources
+ val theme = LocalContext.current.theme
+
+ val lightBackgroundColor = Color(0xfffffbfe)
+ val darkBackgroundColor = Color(0xff1c1b1f)
+ val lightTextColor = Color(0xFF29A331)
+ val darkTextColor = Color(0xFF29A331)
+ val whiteColor = Color(0xFFFFFFFF)
+ val rowBackground = Color(0xFFEEF8EF)
+
+ GlanceTheme(
+ colors =
+ ColorProviders(
+ light =
+ lightColorScheme(
+ background = lightBackgroundColor,
+ onBackground = lightTextColor,
+ tertiary = whiteColor,
+ secondary = rowBackground
+
+ ),
+ dark =
+ darkColorScheme(
+ background = darkBackgroundColor,
+ onBackground = darkTextColor,
+ tertiary = whiteColor,
+ secondary = rowBackground
+ ),
+ ),
+ content = content,
+ )
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetViewModel.kt b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetViewModel.kt
new file mode 100644
index 0000000..40fef1a
--- /dev/null
+++ b/android/FucksGiven/app/src/main/java/rocks/poopjournal/fucksgiven/presentation/widget/WidgetViewModel.kt
@@ -0,0 +1,33 @@
+package rocks.poopjournal.fucksgiven.presentation.widget
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import rocks.poopjournal.fucksgiven.data.FuckRepository
+import rocks.poopjournal.fucksgiven.presentation.viewmodel.UiState
+import javax.inject.Inject
+
+class AppWidgetViewModel @Inject constructor(
+ private val fuckRepository: FuckRepository,
+) : ViewModel() {
+ private val _uiState = MutableStateFlow(UiState())
+ val uiState = _uiState.asStateFlow()
+
+
+ init {
+ viewModelScope.launch(Dispatchers.IO) {
+ fuckRepository.getAllFucks().distinctUntilChanged().collect { list ->
+ _uiState.update {
+ it.copy(
+ fuckList = list
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable-nodpi/example_appwidget_preview.png b/android/FucksGiven/app/src/main/res/drawable-nodpi/example_appwidget_preview.png
new file mode 100644
index 0000000..894b069
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/drawable-nodpi/example_appwidget_preview.png differ
diff --git a/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_background.xml b/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_background.xml
new file mode 100644
index 0000000..567b256
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_background.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml b/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml
new file mode 100644
index 0000000..007e287
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable/about.xml b/android/FucksGiven/app/src/main/res/drawable/about.xml
new file mode 100644
index 0000000..5440c37
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/about.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/backup.xml b/android/FucksGiven/app/src/main/res/drawable/backup.xml
new file mode 100644
index 0000000..679eda2
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/backup.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/baseline_add_24.xml b/android/FucksGiven/app/src/main/res/drawable/baseline_add_24.xml
new file mode 100644
index 0000000..2ae27b8
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/baseline_add_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/bg_widget.xml b/android/FucksGiven/app/src/main/res/drawable/bg_widget.xml
new file mode 100644
index 0000000..b01c011
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/bg_widget.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable/btn_background.xml b/android/FucksGiven/app/src/main/res/drawable/btn_background.xml
new file mode 100644
index 0000000..258ffa8
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/btn_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable/fucks.xml b/android/FucksGiven/app/src/main/res/drawable/fucks.xml
new file mode 100644
index 0000000..99f5576
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/fucks.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/github.xml b/android/FucksGiven/app/src/main/res/drawable/github.xml
new file mode 100644
index 0000000..b8cb70b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/github.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/gmail.xml b/android/FucksGiven/app/src/main/res/drawable/gmail.xml
new file mode 100644
index 0000000..162414b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/gmail.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/graph.xml b/android/FucksGiven/app/src/main/res/drawable/graph.xml
new file mode 100644
index 0000000..bf4c5ec
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/graph.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/home.xml b/android/FucksGiven/app/src/main/res/drawable/home.xml
new file mode 100644
index 0000000..02c2c8b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/home.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/ic_launcher_background.xml b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/drawable/ic_launcher_monochrome.xml b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_monochrome.xml
new file mode 100644
index 0000000..87c01c6
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/ic_launcher_monochrome.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/marvin.png b/android/FucksGiven/app/src/main/res/drawable/marvin.png
new file mode 100644
index 0000000..be84e1c
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/drawable/marvin.png differ
diff --git a/android/FucksGiven/app/src/main/res/drawable/message.xml b/android/FucksGiven/app/src/main/res/drawable/message.xml
new file mode 100644
index 0000000..6c79f6f
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/message.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/mubeen.jpg b/android/FucksGiven/app/src/main/res/drawable/mubeen.jpg
new file mode 100644
index 0000000..34b04ca
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/drawable/mubeen.jpg differ
diff --git a/android/FucksGiven/app/src/main/res/drawable/report.xml b/android/FucksGiven/app/src/main/res/drawable/report.xml
new file mode 100644
index 0000000..0986191
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/report.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/restore.xml b/android/FucksGiven/app/src/main/res/drawable/restore.xml
new file mode 100644
index 0000000..5b3d7a8
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/restore.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/selected_graph.xml b/android/FucksGiven/app/src/main/res/drawable/selected_graph.xml
new file mode 100644
index 0000000..ed514d6
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/selected_graph.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/selected_home.xml b/android/FucksGiven/app/src/main/res/drawable/selected_home.xml
new file mode 100644
index 0000000..b47ab44
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/selected_home.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/settings.xml b/android/FucksGiven/app/src/main/res/drawable/settings.xml
new file mode 100644
index 0000000..133a0a1
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/settings.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/source.xml b/android/FucksGiven/app/src/main/res/drawable/source.xml
new file mode 100644
index 0000000..8242b4e
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/source.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/splash_icon.xml b/android/FucksGiven/app/src/main/res/drawable/splash_icon.xml
new file mode 100644
index 0000000..7874e83
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/splash_icon.xml
@@ -0,0 +1,27 @@
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/translate.xml b/android/FucksGiven/app/src/main/res/drawable/translate.xml
new file mode 100644
index 0000000..4bd5194
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/translate.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/drawable/x.xml b/android/FucksGiven/app/src/main/res/drawable/x.xml
new file mode 100644
index 0000000..9394008
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/drawable/x.xml
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/android/FucksGiven/app/src/main/res/font/opensans_regular.ttf b/android/FucksGiven/app/src/main/res/font/opensans_regular.ttf
new file mode 100644
index 0000000..67803bb
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/opensans_regular.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/font/ubuntu_bold.ttf b/android/FucksGiven/app/src/main/res/font/ubuntu_bold.ttf
new file mode 100644
index 0000000..c2293d5
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/ubuntu_bold.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/font/ubuntu_italic.ttf b/android/FucksGiven/app/src/main/res/font/ubuntu_italic.ttf
new file mode 100644
index 0000000..a599244
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/ubuntu_italic.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/font/ubuntu_light.ttf b/android/FucksGiven/app/src/main/res/font/ubuntu_light.ttf
new file mode 100644
index 0000000..b310d15
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/ubuntu_light.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/font/ubuntu_medium.ttf b/android/FucksGiven/app/src/main/res/font/ubuntu_medium.ttf
new file mode 100644
index 0000000..7340a40
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/ubuntu_medium.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/font/ubuntu_regular.ttf b/android/FucksGiven/app/src/main/res/font/ubuntu_regular.ttf
new file mode 100644
index 0000000..f98a2da
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/font/ubuntu_regular.ttf differ
diff --git a/android/FucksGiven/app/src/main/res/layout/widget_initial_layout.xml b/android/FucksGiven/app/src/main/res/layout/widget_initial_layout.xml
new file mode 100644
index 0000000..607e0b6
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/layout/widget_initial_layout.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..32d3639
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..4ae7d12
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..0766957
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp
new file mode 100644
index 0000000..649f296
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..f44c8ad
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..2457487
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..1f7631c
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp
new file mode 100644
index 0000000..75eedb8
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..334c1fb
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b48c56f
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..e8c3fe6
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp
new file mode 100644
index 0000000..0fa39be
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..feb8cb5
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..fe63ba8
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..ad96cf9
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp
new file mode 100644
index 0000000..16d7bb0
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..9d1d1ca
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..5ffd1f2
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..2b5db35
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp
new file mode 100644
index 0000000..37e625b
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..a2b8ebf
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1a3ccf5
Binary files /dev/null and b/android/FucksGiven/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/android/FucksGiven/app/src/main/res/values-de/strings.xml b/android/FucksGiven/app/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..84a3dd5
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-de/strings.xml
@@ -0,0 +1,93 @@
+
+ Fucks Given
+ Um
+ Apache-Lizenz 2.0
+ Keine Scheiße gegeben
+ Hinzufügen
+ Stornieren
+ Beschreibung
+ Datum auswählen
+ OK
+ Einstellungen
+ Allgemein
+ Aussehen
+ Daten
+ Sicherung
+ Wiederherstellen
+ Thema wählen
+ Statistiken
+ Wöchentlich
+ Monatlich
+ Jährlich
+ Scheiße im Durchschnitt gegeben
+ Januar-Dezember
+ M
+ T
+ W
+ TH
+ F
+ S
+ Sie sind
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ J
+ F
+ M
+ A
+ M
+ J
+ J
+ A
+ S
+ Ö
+ N
+ D
+ Lichtthema
+ Dunkles Thema
+ Folgen Sie dem System
+ BEISPIEL
+ Widget hinzufügen
+ Dies ist eine Beschreibung des App-Widgets
+ WearActivity
+ Crazy Marvin
+ Entwickler
+ Mubeen Ali
+ Beitragen
+ Translate
+ Ein Problem melden
+ Quelltext anzeigen
+ Open-source Licenses
+ Feather Icons
+ MIT License
+ Android Jetpack
+ Apache License 2.0
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-eo/strings.xml b/android/FucksGiven/app/src/main/res/values-eo/strings.xml
new file mode 100644
index 0000000..372f18e
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-eo/strings.xml
@@ -0,0 +1,93 @@
+
+ Fikas Donita
+ Pri
+ Apache-Licenco 2.0
+ Neniu Fiko Donita
+ Aldoni
+ Nuligi
+ Priskribo
+ Elektu Daton
+ Bone
+ Agordoj
+ Generalo
+ Aspekto
+ Datumoj
+ Rezervo
+ Restaŭri
+ Elektu Temon
+ Statoj
+ Ĉiusemajne
+ Monata
+ Ĉiujare
+ fikoj donitaj averaĝe
+ januaro-decembro
+ M
+ T
+ W
+ TH
+ F
+ S
+ Ili estas
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ J
+ F
+ M
+ A
+ M
+ J
+ J
+ A
+ S
+ O
+ N
+ D
+ Luma Temo
+ Malhela Temo
+ Sekvu Sistemon
+ EKZEMPLO
+ Aldonu fenestraĵon
+ Ĉi tio estas priskribo de aplikaĵo
+ WearActivity
+ Crazy Marvin
+ Ellaboranto
+ Mubeen Ali
+ Kontribuu
+ Translate
+ Raportu problemon
+ Vidi Fonton
+ Open-source Licenses
+ Feather Icons
+ MIT License
+ Android Jetpack
+ Apache License 2.0
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-fr/strings.xml b/android/FucksGiven/app/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..4ba6f1d
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-fr/strings.xml
@@ -0,0 +1,93 @@
+
+ Baise donnée
+ À propos
+ Licence Apache 2.0
+ Pas de baise donnée
+ Ajouter
+ Annuler
+ Description
+ Sélectionner une date
+ D\'accord
+ Paramètres
+ Général
+ Apparence
+ Données
+ Sauvegarde
+ Restaurer
+ Sélectionne un thème
+ Statistiques
+ Hebdomadaire
+ Mensuel
+ Annuel
+ baise donnée en moyenne
+ janvier-décembre
+ M
+ T
+ W
+ ÈME
+ F
+ S
+ Ils sont
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ J.
+ F
+ M
+ UN
+ M
+ J.
+ J.
+ UN
+ S
+ Ô
+ N
+ D
+ Thème Lumière
+ Thème sombre
+ Suivre le système
+ EXEMPLE
+ Ajouter un widget
+ Ceci est une description du widget d\'application
+ PorterActivité
+ Crazy Marvin
+ Développeur
+ Mubeen Ali
+ Contribuer
+ Translate
+ Signaler un problème
+ Voir la source
+ Open-source Licenses
+ Feather Icons
+ MIT License
+ Android Jetpack
+ Apache License 2.0
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-night-v31/themes.xml b/android/FucksGiven/app/src/main/res/values-night-v31/themes.xml
new file mode 100644
index 0000000..2684851
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-night-v31/themes.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-pt/strings.xml b/android/FucksGiven/app/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..a6b3dae
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-pt/strings.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-ur/strings.xml b/android/FucksGiven/app/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..54ec4c5
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-ur/strings.xml
@@ -0,0 +1,93 @@
+
+ Fucks دیا
+ کے بارے میں
+ اپاچی لائسنس 2.0
+ کوئی fucks دیا
+ شامل کریں۔
+ منسوخ کریں۔
+ تفصیل
+ تاریخ منتخب کریں۔
+ ٹھیک ہے
+ ترتیبات
+ جنرل
+ ظہور
+ ڈیٹا
+ بیک اپ
+ بحال کریں۔
+ تھیم منتخب کریں۔
+ اعدادوشمار
+ ہفتہ وار
+ ماہانہ
+ سالانہ
+ fucks اوسط پر دیا
+ جنوری دسمبر
+ M
+ T
+ W
+ TH
+ F
+ S
+ SU
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ J
+ F
+ M
+ A
+ M
+ J
+ J
+ A
+ S
+ O
+ N
+ D
+ ہلکی تھیم
+ ڈارک تھیم
+ سسٹم کو فالو کریں۔
+ مثال
+ ویجیٹ شامل کریں۔
+ یہ ایک ایپ ویجیٹ کی تفصیل ہے۔
+ WearActivity
+ Crazy Marvin
+ ڈویلپر
+ Mubeen Ali
+ تعاون کریں۔
+ Translate
+ مسئلے کے بارے میں بتائیے
+ ماخذ دیکھیں
+ Open-source Licenses
+ Feather Icons
+ MIT License
+ Android Jetpack
+ Apache License 2.0
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-v21/styles.xml b/android/FucksGiven/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..c8a22f3
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-v31/styles.xml b/android/FucksGiven/app/src/main/res/values-v31/styles.xml
new file mode 100644
index 0000000..a03eb72
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-v31/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values-v31/themes.xml b/android/FucksGiven/app/src/main/res/values-v31/themes.xml
new file mode 100644
index 0000000..db1ee6b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values-v31/themes.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/attrs.xml b/android/FucksGiven/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..7781ac8
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/attrs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/colors.xml b/android/FucksGiven/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..61297e3
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/colors.xml
@@ -0,0 +1,16 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+ #FF29A331
+ #A9AAA9
+ #FFE1F5FE
+ #FF81D4FA
+ #FF039BE5
+ #FF01579B
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/dimens.xml b/android/FucksGiven/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..4db8c59
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/dimens.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ 0dp
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/strings.xml b/android/FucksGiven/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1607e61
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/strings.xml
@@ -0,0 +1,93 @@
+
+ Fucks Given
+ About
+ Apache License 2.0
+ No Fucks Given
+ Add
+ Cancel
+ Description
+ Select Date
+ Ok
+ Settings
+ General
+ Appearance
+ Data
+ Backup
+ Restore
+ Select Theme
+ Stats
+ Weekly
+ Monthly
+ Yearly
+ fucks given on average
+ January-December
+ M
+ T
+ W
+ TH
+ F
+ S
+ SU
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ J
+ F
+ M
+ A
+ M
+ J
+ J
+ A
+ S
+ O
+ N
+ D
+ Light Theme
+ Dark Theme
+ Follow System
+ EXAMPLE
+ Add widget
+ This is an app widget description
+ WearActivity
+ Crazy Marvin
+ Developer
+ Mubeen Ali
+ Contribute
+ Translate
+ Report a problem
+ View Source
+ Open-source Licenses
+ Feather Icons
+ MIT License
+ Android Jetpack
+ Apache License 2.0
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/styles.xml b/android/FucksGiven/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..97ab6f6
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/values/themes.xml b/android/FucksGiven/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..2201671
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/values/themes.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/xml-v31/my_app_widget_info.xml b/android/FucksGiven/app/src/main/res/xml-v31/my_app_widget_info.xml
new file mode 100644
index 0000000..7223b4b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/xml-v31/my_app_widget_info.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/xml/backup_rules.xml b/android/FucksGiven/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/xml/data_extraction_rules.xml b/android/FucksGiven/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/xml/local_config.xml b/android/FucksGiven/app/src/main/res/xml/local_config.xml
new file mode 100644
index 0000000..5472c2b
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/xml/local_config.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/main/res/xml/my_app_widget_info.xml b/android/FucksGiven/app/src/main/res/xml/my_app_widget_info.xml
new file mode 100644
index 0000000..4e816d3
--- /dev/null
+++ b/android/FucksGiven/app/src/main/res/xml/my_app_widget_info.xml
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/android/FucksGiven/app/src/test/java/rocks/poopjournal/fucksgiven/ExampleUnitTest.kt b/android/FucksGiven/app/src/test/java/rocks/poopjournal/fucksgiven/ExampleUnitTest.kt
new file mode 100644
index 0000000..5b0efb7
--- /dev/null
+++ b/android/FucksGiven/app/src/test/java/rocks/poopjournal/fucksgiven/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package rocks.poopjournal.fucksgiven
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/android/FucksGiven/build.gradle.kts b/android/FucksGiven/build.gradle.kts
new file mode 100644
index 0000000..01c689a
--- /dev/null
+++ b/android/FucksGiven/build.gradle.kts
@@ -0,0 +1,7 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.jetbrains.kotlin.android) apply false
+ id("com.google.dagger.hilt.android") version "2.48" apply false
+
+}
\ No newline at end of file
diff --git a/android/FucksGiven/gradle.properties b/android/FucksGiven/gradle.properties
new file mode 100644
index 0000000..20e2a01
--- /dev/null
+++ b/android/FucksGiven/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/android/FucksGiven/gradle/libs.versions.toml b/android/FucksGiven/gradle/libs.versions.toml
new file mode 100644
index 0000000..ddc6dd8
--- /dev/null
+++ b/android/FucksGiven/gradle/libs.versions.toml
@@ -0,0 +1,43 @@
+[versions]
+agp = "8.4.0"
+kotlin = "1.9.0"
+coreKtx = "1.10.1"
+junit = "4.13.2"
+junitVersion = "1.1.5"
+espressoCore = "3.5.1"
+lifecycleRuntimeKtx = "2.7.0"
+activityCompose = "1.9.0"
+composeBom = "2023.08.00"
+runtimeLivedata = "1.6.7"
+glanceAppwidget = "1.1.0"
+composeMaterial = "1.2.1"
+composeFoundation = "1.2.1"
+coreSplashscreen = "1.0.1"
+appcompat = "1.7.0"
+
+[libraries]
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
+androidx-ui = { group = "androidx.compose.ui", name = "ui" }
+androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
+androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
+androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
+androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
+androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
+androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+androidx-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" }
+androidx-glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glanceAppwidget" }
+androidx-compose-material = { group = "androidx.wear.compose", name = "compose-material", version.ref = "composeMaterial" }
+androidx-compose-foundation = { group = "androidx.wear.compose", name = "compose-foundation", version.ref = "composeFoundation" }
+androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "coreSplashscreen" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+
diff --git a/android/FucksGiven/gradle/wrapper/gradle-wrapper.properties b/android/FucksGiven/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..ed560de
--- /dev/null
+++ b/android/FucksGiven/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu May 16 15:46:04 PKT 2024
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/android/FucksGiven/gradlew b/android/FucksGiven/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/android/FucksGiven/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/android/FucksGiven/gradlew.bat b/android/FucksGiven/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/android/FucksGiven/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/FucksGiven/settings.gradle.kts b/android/FucksGiven/settings.gradle.kts
new file mode 100644
index 0000000..7d18c38
--- /dev/null
+++ b/android/FucksGiven/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven (url = "https://jitpack.io" )
+
+ }
+}
+
+rootProject.name = "FucksGiven"
+include(":app")
+
\ No newline at end of file
diff --git a/android/app-release.aab b/android/app-release.aab
new file mode 100644
index 0000000..57d310e
Binary files /dev/null and b/android/app-release.aab differ
diff --git a/android/release/baselineProfiles/0/app-release.dm b/android/release/baselineProfiles/0/app-release.dm
new file mode 100644
index 0000000..cae0d11
Binary files /dev/null and b/android/release/baselineProfiles/0/app-release.dm differ
diff --git a/android/release/baselineProfiles/1/app-release.dm b/android/release/baselineProfiles/1/app-release.dm
new file mode 100644
index 0000000..3624072
Binary files /dev/null and b/android/release/baselineProfiles/1/app-release.dm differ
diff --git a/android/release/output-metadata.json b/android/release/output-metadata.json
new file mode 100644
index 0000000..ad63d75
--- /dev/null
+++ b/android/release/output-metadata.json
@@ -0,0 +1,37 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "rocks.poopjournal.fucksgiven",
+ "variantName": "release",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 1,
+ "versionName": "1.0",
+ "outputFile": "app-release.apk"
+ }
+ ],
+ "elementType": "File",
+ "baselineProfiles": [
+ {
+ "minApi": 28,
+ "maxApi": 30,
+ "baselineProfiles": [
+ "baselineProfiles/1/app-release.dm"
+ ]
+ },
+ {
+ "minApi": 31,
+ "maxApi": 2147483647,
+ "baselineProfiles": [
+ "baselineProfiles/0/app-release.dm"
+ ]
+ }
+ ],
+ "minSdkVersionForDexing": 26
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 84a3dd5..a6b3dae 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1,93 +1,2 @@
-
- Fucks Given
- Um
- Apache-Lizenz 2.0
- Keine Scheiße gegeben
- Hinzufügen
- Stornieren
- Beschreibung
- Datum auswählen
- OK
- Einstellungen
- Allgemein
- Aussehen
- Daten
- Sicherung
- Wiederherstellen
- Thema wählen
- Statistiken
- Wöchentlich
- Monatlich
- Jährlich
- Scheiße im Durchschnitt gegeben
- Januar-Dezember
- M
- T
- W
- TH
- F
- S
- Sie sind
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- J
- F
- M
- A
- M
- J
- J
- A
- S
- Ö
- N
- D
- Lichtthema
- Dunkles Thema
- Folgen Sie dem System
- BEISPIEL
- Widget hinzufügen
- Dies ist eine Beschreibung des App-Widgets
- WearActivity
- Crazy Marvin
- Entwickler
- Mubeen Ali
- Beitragen
- Translate
- Ein Problem melden
- Quelltext anzeigen
- Open-source Licenses
- Feather Icons
- MIT License
- Android Jetpack
- Apache License 2.0
-
\ No newline at end of file
+
+
\ No newline at end of file