Skip to content

Commit a13aa2a

Browse files
committed
Rename folder
1 parent 4e3a2ae commit a13aa2a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2596
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
plugins {
2+
id("com.android.application")
3+
id("kotlin-android")
4+
id("kotlin-kapt")
5+
id("com.google.gms.google-services")
6+
id("dagger.hilt.android.plugin")
7+
}
8+
9+
android {
10+
namespace = "com.notes.app"
11+
compileSdk = 34
12+
13+
defaultConfig {
14+
applicationId = "com.notes.app"
15+
minSdk = 26
16+
targetSdk = 34
17+
versionCode = 1
18+
versionName = "1.0"
19+
20+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
21+
vectorDrawables.useSupportLibrary = true
22+
}
23+
24+
buildTypes {
25+
getByName("release") {
26+
isMinifyEnabled = false
27+
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
28+
}
29+
}
30+
compileOptions {
31+
sourceCompatibility = JavaVersion.VERSION_17
32+
targetCompatibility = JavaVersion.VERSION_17
33+
}
34+
kotlinOptions {
35+
jvmTarget = "17"
36+
}
37+
buildFeatures {
38+
compose = true
39+
buildConfig = true
40+
}
41+
composeOptions {
42+
kotlinCompilerExtensionVersion = "1.4.5"
43+
}
44+
packaging {
45+
resources.excludes.add("/META-INF/{AL2.0,LGPL2.1}")
46+
}
47+
}
48+
49+
dependencies {
50+
implementation("androidx.core:core-ktx:1.13.0")
51+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
52+
implementation("androidx.activity:activity-compose:1.9.0")
53+
implementation(platform("androidx.compose:compose-bom:2022.10.00"))
54+
implementation("androidx.compose.ui:ui")
55+
implementation("androidx.compose.ui:ui-graphics")
56+
implementation("androidx.compose.ui:ui-tooling-preview")
57+
implementation("androidx.compose.material3:material3")
58+
implementation("androidx.navigation:navigation-compose:2.7.7")
59+
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
60+
implementation("com.google.dagger:hilt-android:2.49")
61+
kapt("com.google.dagger:hilt-compiler:2.44")
62+
63+
//Firebase
64+
implementation(platform("com.google.firebase:firebase-bom:32.8.1"))
65+
implementation("com.google.firebase:firebase-auth")
66+
implementation("com.google.firebase:firebase-firestore")
67+
68+
//Authentication with Credential Manager
69+
implementation("com.google.android.gms:play-services-auth:21.1.0")
70+
implementation("androidx.credentials:credentials:1.2.2")
71+
implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
72+
implementation("com.google.android.libraries.identity.googleid:googleid:1.1.0")
73+
74+
testImplementation("junit:junit:4.13.2")
75+
androidTestImplementation("androidx.test.ext:junit:1.1.5")
76+
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
77+
androidTestImplementation(platform("androidx.compose:compose-bom:2022.10.00"))
78+
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
79+
debugImplementation("androidx.compose.ui:ui-tooling")
80+
debugImplementation("androidx.compose.ui:ui-test-manifest")
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.kts.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
22+
23+
-if class androidx.credentials.CredentialManager
24+
-keep class androidx.credentials.playservices.** {
25+
*;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<application
6+
android:allowBackup="true"
7+
android:dataExtractionRules="@xml/data_extraction_rules"
8+
android:fullBackupContent="@xml/backup_rules"
9+
android:icon="@mipmap/ic_launcher"
10+
android:label="@string/app_name"
11+
android:roundIcon="@mipmap/ic_launcher_round"
12+
android:supportsRtl="true"
13+
android:theme="@style/Theme.Notes"
14+
android:usesCleartextTraffic="true"
15+
tools:targetApi="31"
16+
android:name = ".NotesHiltApp">
17+
<activity
18+
android:name=".NotesActivity"
19+
android:exported="true"
20+
android:theme="@style/Theme.Notes">
21+
<intent-filter>
22+
<action android:name="android.intent.action.MAIN" />
23+
24+
<category android:name="android.intent.category.LAUNCHER" />
25+
</intent-filter>
26+
</activity>
27+
</application>
28+
29+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.notes.app
2+
3+
import android.os.Bundle
4+
import androidx.activity.ComponentActivity
5+
import androidx.activity.compose.setContent
6+
import com.google.firebase.auth.auth
7+
import com.google.firebase.firestore.firestore
8+
import com.google.firebase.Firebase
9+
import dagger.hilt.android.AndroidEntryPoint
10+
11+
@AndroidEntryPoint
12+
class NotesActivity : ComponentActivity() {
13+
override fun onCreate(savedInstanceState: Bundle?) {
14+
super.onCreate(savedInstanceState)
15+
16+
// Uncomment the following line if you want to run
17+
// against the Firebase Local Emulator Suite:
18+
// configureFirebaseServices()
19+
20+
setContent { NotesApp() }
21+
}
22+
23+
private fun configureFirebaseServices() {
24+
if (BuildConfig.DEBUG) {
25+
Firebase.auth.useEmulator(LOCALHOST, AUTH_PORT)
26+
Firebase.firestore.useEmulator(LOCALHOST, FIRESTORE_PORT)
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.notes.app
2+
3+
import androidx.compose.foundation.layout.padding
4+
import androidx.compose.material3.ExperimentalMaterial3Api
5+
import androidx.compose.material3.MaterialTheme
6+
import androidx.compose.material3.Scaffold
7+
import androidx.compose.material3.Surface
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.remember
10+
import androidx.compose.ui.Modifier
11+
import androidx.navigation.compose.NavHost
12+
import androidx.navigation.NavGraphBuilder
13+
import androidx.navigation.NavHostController
14+
import androidx.navigation.compose.composable
15+
import androidx.navigation.compose.rememberNavController
16+
import androidx.navigation.navArgument
17+
import com.notes.app.screens.account_center.AccountCenterScreen
18+
import com.notes.app.screens.note.NoteScreen
19+
import com.notes.app.screens.notes_list.NotesListScreen
20+
import com.notes.app.screens.sign_in.SignInScreen
21+
import com.notes.app.screens.sign_up.SignUpScreen
22+
import com.notes.app.screens.splash.SplashScreen
23+
import com.notes.app.ui.theme.NotesTheme
24+
25+
@Composable
26+
@OptIn(ExperimentalMaterial3Api::class)
27+
fun NotesApp() {
28+
NotesTheme {
29+
Surface(color = MaterialTheme.colorScheme.background) {
30+
val appState = rememberAppState()
31+
32+
Scaffold { innerPaddingModifier ->
33+
NavHost(
34+
navController = appState.navController,
35+
startDestination = SPLASH_SCREEN,
36+
modifier = Modifier.padding(innerPaddingModifier)
37+
) {
38+
notesGraph(appState)
39+
}
40+
}
41+
}
42+
}
43+
}
44+
45+
@Composable
46+
fun rememberAppState(navController: NavHostController = rememberNavController()) =
47+
remember(navController) {
48+
NotesAppState(navController)
49+
}
50+
51+
fun NavGraphBuilder.notesGraph(appState: NotesAppState) {
52+
composable(NOTES_LIST_SCREEN) {
53+
NotesListScreen(
54+
restartApp = { route -> appState.clearAndNavigate(route) },
55+
openScreen = { route -> appState.navigate(route) }
56+
)
57+
}
58+
59+
composable(
60+
route = "$NOTE_SCREEN$NOTE_ID_ARG",
61+
arguments = listOf(navArgument(NOTE_ID) { defaultValue = NOTE_DEFAULT_ID })
62+
) {
63+
NoteScreen(
64+
noteId = it.arguments?.getString(NOTE_ID) ?: NOTE_DEFAULT_ID,
65+
popUpScreen = { appState.popUp() },
66+
restartApp = { route -> appState.clearAndNavigate(route) }
67+
)
68+
}
69+
70+
composable(SIGN_IN_SCREEN) {
71+
SignInScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) })
72+
}
73+
74+
composable(SIGN_UP_SCREEN) {
75+
SignUpScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) })
76+
}
77+
78+
composable(SPLASH_SCREEN) {
79+
SplashScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) })
80+
}
81+
82+
composable(ACCOUNT_CENTER_SCREEN) {
83+
AccountCenterScreen(restartApp = { route -> appState.clearAndNavigate(route) })
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.notes.app
2+
3+
import androidx.compose.runtime.Stable
4+
import androidx.navigation.NavHostController
5+
6+
@Stable
7+
class NotesAppState(val navController: NavHostController) {
8+
fun popUp() {
9+
navController.popBackStack()
10+
}
11+
12+
fun navigate(route: String) {
13+
navController.navigate(route) { launchSingleTop = true }
14+
}
15+
16+
fun navigateAndPopUp(route: String, popUp: String) {
17+
navController.navigate(route) {
18+
launchSingleTop = true
19+
popUpTo(popUp) { inclusive = true }
20+
}
21+
}
22+
23+
fun clearAndNavigate(route: String) {
24+
navController.navigate(route) {
25+
launchSingleTop = true
26+
popUpTo(0) { inclusive = true }
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.notes.app
2+
3+
const val ERROR_TAG = "NOTES APP ERROR"
4+
const val UNEXPECTED_CREDENTIAL = "Unexpected type of credential"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.notes.app
2+
3+
import android.app.Application
4+
import dagger.hilt.android.HiltAndroidApp
5+
6+
@HiltAndroidApp class NotesHiltApp : Application() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.notes.app
2+
3+
const val NOTES_LIST_SCREEN = "NotesListScreen"
4+
const val NOTE_SCREEN = "NoteScreen"
5+
const val SIGN_IN_SCREEN = "SignInScreen"
6+
const val SIGN_UP_SCREEN = "SignUpScreen"
7+
const val SPLASH_SCREEN = "SplashScreen"
8+
const val ACCOUNT_CENTER_SCREEN = "AccountCenterScreen"
9+
10+
const val NOTE_ID = "noteId"
11+
const val NOTE_DEFAULT_ID = "-1"
12+
const val NOTE_ID_ARG = "?$NOTE_ID={$NOTE_ID}"
13+
14+
const val LOCALHOST = "10.0.2.2"
15+
const val AUTH_PORT = 9099
16+
const val FIRESTORE_PORT = 8080
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.notes.app.model
2+
3+
import com.google.firebase.firestore.DocumentId
4+
5+
private const val TITLE_MAX_SIZE = 30
6+
7+
data class Note(
8+
@DocumentId val id: String = "",
9+
val text: String = "",
10+
val userId: String = ""
11+
)
12+
13+
fun Note.getTitle(): String {
14+
val isLongText = this.text.length > TITLE_MAX_SIZE
15+
val endRange = if (isLongText) TITLE_MAX_SIZE else this.text.length - 1
16+
return this.text.substring(IntRange(0, endRange))
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.notes.app.model
2+
3+
data class User(
4+
val id: String = "",
5+
val email: String = "",
6+
val provider: String = "",
7+
val displayName: String = "",
8+
val isAnonymous: Boolean = true
9+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.notes.app.model.service
2+
3+
import com.notes.app.model.User
4+
import kotlinx.coroutines.flow.Flow
5+
6+
interface AccountService {
7+
val currentUser: Flow<User?>
8+
val currentUserId: String
9+
fun hasUser(): Boolean
10+
fun getUserProfile(): User
11+
suspend fun createAnonymousAccount()
12+
suspend fun updateDisplayName(newDisplayName: String)
13+
suspend fun linkAccountWithGoogle(idToken: String)
14+
suspend fun linkAccountWithEmail(email: String, password: String)
15+
suspend fun signInWithGoogle(idToken: String)
16+
suspend fun signInWithEmail(email: String, password: String)
17+
suspend fun signOut()
18+
suspend fun deleteAccount()
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.notes.app.model.service
2+
3+
import com.notes.app.model.Note
4+
import kotlinx.coroutines.flow.Flow
5+
6+
interface StorageService {
7+
val notes: Flow<List<Note>>
8+
suspend fun createNote(note: Note)
9+
suspend fun readNote(noteId: String): Note?
10+
suspend fun updateNote(note: Note)
11+
suspend fun deleteNote(noteId: String)
12+
}

0 commit comments

Comments
 (0)