├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── deploymentTargetDropDown.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── developers
│ │ └── noteappktorserver
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── developers
│ │ │ └── noteappktorserver
│ │ │ ├── app
│ │ │ └── MyBaseApplication.kt
│ │ │ ├── data
│ │ │ ├── local
│ │ │ │ └── DataStoreManager.kt
│ │ │ └── network
│ │ │ │ └── ApiNoteService.kt
│ │ │ ├── di
│ │ │ ├── AppModel.kt
│ │ │ ├── DataTimeModel.kt
│ │ │ └── RetrofitModel.kt
│ │ │ ├── entities
│ │ │ ├── MyResponse.kt
│ │ │ ├── Note.kt
│ │ │ ├── User.kt
│ │ │ └── UserInfoDB.kt
│ │ │ ├── helpers
│ │ │ ├── Event.kt
│ │ │ ├── MyValidation.kt
│ │ │ ├── RepositoryUtils.kt
│ │ │ └── Resource.kt
│ │ │ ├── qualifiers
│ │ │ ├── IOThread.kt
│ │ │ ├── MainThread.kt
│ │ │ └── Token.kt
│ │ │ ├── repositories
│ │ │ ├── AuthenticationRepository.kt
│ │ │ ├── CreateNoteRepository.kt
│ │ │ └── HomeRepository.kt
│ │ │ ├── ui
│ │ │ ├── activities
│ │ │ │ └── MainActivity.kt
│ │ │ ├── adapters
│ │ │ │ └── NoteAdapter.kt
│ │ │ ├── dialogs
│ │ │ │ └── AddUrlDialogs.kt
│ │ │ ├── fragments
│ │ │ │ ├── CreateNoteFragment.kt
│ │ │ │ ├── HomeFragment.kt
│ │ │ │ ├── LoginFragment.kt
│ │ │ │ ├── RegisterFragment.kt
│ │ │ │ └── SplashFragment.kt
│ │ │ └── viewmodels
│ │ │ │ ├── AuthenticationViewModel.kt
│ │ │ │ ├── CreateNoteViewModel.kt
│ │ │ │ └── HomeViewModel.kt
│ │ │ └── utils
│ │ │ ├── BaseEXT.kt
│ │ │ ├── FragmentEXT.kt
│ │ │ ├── KeyBordEXT.kt
│ │ │ ├── NoteUtility.kt
│ │ │ └── constants.kt
│ └── res
│ │ ├── drawable-anydpi
│ │ ├── back_icon.xml
│ │ ├── emai_icon.xml
│ │ ├── lock_icon.xml
│ │ ├── logout.xml
│ │ └── user_icon.xml
│ │ ├── drawable-hdpi
│ │ ├── back_icon.png
│ │ ├── emai_icon.png
│ │ ├── lock_icon.png
│ │ ├── logout.png
│ │ └── user_icon.png
│ │ ├── drawable-mdpi
│ │ ├── back_icon.png
│ │ ├── emai_icon.png
│ │ ├── ic_error.xml
│ │ ├── ic_image.xml
│ │ ├── lock_icon.png
│ │ ├── logout.png
│ │ └── user_icon.png
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── back_icon.png
│ │ ├── emai_icon.png
│ │ ├── lock_icon.png
│ │ ├── logout.png
│ │ └── user_icon.png
│ │ ├── drawable-xxhdpi
│ │ ├── back_icon.png
│ │ ├── emai_icon.png
│ │ ├── ic_copy.xml
│ │ ├── ic_done.xml
│ │ ├── lock_icon.png
│ │ ├── logout.png
│ │ └── user_icon.png
│ │ ├── drawable
│ │ ├── background_add_button.xml
│ │ ├── background_bottom_sheet.xml
│ │ ├── background_default_note.xml
│ │ ├── background_indicator.xml
│ │ ├── background_note.xml
│ │ ├── background_note2.xml
│ │ ├── background_note3.xml
│ │ ├── background_note4.xml
│ │ ├── background_note5.xml
│ │ ├── background_save_button.xml
│ │ ├── background_search.xml
│ │ ├── button_background.xml
│ │ ├── card_background.xml
│ │ ├── edit_text_background.xml
│ │ ├── ic_add_circle_outline.xml
│ │ ├── ic_add_image.xml
│ │ ├── ic_add_link.xml
│ │ ├── ic_add_main.xml
│ │ ├── ic_alert.xml
│ │ ├── ic_baseline_delete_forever_24.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_search.xml
│ │ └── ic_web.xml
│ │ ├── font
│ │ ├── brandon_medium.otf
│ │ ├── israr_syria.ttf
│ │ ├── poppins.xml
│ │ ├── poppins_bold.xml
│ │ ├── rta_regular.ttf
│ │ ├── uber_move.ttf
│ │ └── uber_move_bold.ttf
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_create_note.xml
│ │ ├── fragment_home.xml
│ │ ├── fragment_login.xml
│ │ ├── fragment_register.xml
│ │ ├── fragment_splash.xml
│ │ ├── item_container_note.xml
│ │ ├── layout_dialog_add_url.xml
│ │ └── layout_persistent_bottom_sheet.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── navigation
│ │ └── main_nav_graph.xml
│ │ ├── raw
│ │ ├── note_splash.json
│ │ └── notesplash.json
│ │ └── values
│ │ ├── colors.xml
│ │ ├── font_certs.xml
│ │ ├── preloaded_fonts.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── developers
│ └── noteappktorserver
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NoteAppWithApiKtor
2 |
3 | Note App used to save your notes as text, images, and URLs by beautiful design by using ktor framework backend by server ngrok
4 |
5 | # Screenshots
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ## Built With
22 |
23 | * [Kotlin](https://kotlinlang.org) - As a programming language.
24 | * [Coroutines](https://developer.android.com/kotlin/coroutines) - For multithreading while handling requests to the server and local database.
25 | * [Navigation Component](https://developer.android.com/guide/navigation/navigation-getting-started) - To handle app navigation.
26 | * [Multidex](https://developer.android.com/studio/build/multidex) - To enable creating multi dex files because of using set of libraries that reached the maximum size of single dex file.
27 | * [Model-View-ViewModel(MVVM)](https://developer.android.com/topic/architecture) - Offers an implementation of observer design pattern.
28 | * [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) - notifies views of any database changes in an observer way.
29 | * [Retrofit](https://square.github.io/retrofit/) - A type-safe HTTP client for Android and Java
30 | * [Glide](https://github.com/bumptech/glide) - It is a fast and efficient open source media management and image loading framework for Android that wraps media decoding, memory and disk caching, and resource pooling into a simple and easy to use interface.
31 | * [Timber](https://github.com/JakeWharton/timber) - It helps in logging while debugging your app. and all logging code will not be embedded in the released APK.
32 | * [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) - It is arguably the most used Dependency Injection, or DI, framework for Android. Many Android projects use Dagger to simplify building and providing dependencies across the app. It gives you the ability to create specific scopes, modules, and components, where each forms a piece of a puzzle: The dependency graph.
33 | * [Clean Architecture](https://www.raywenderlich.com/3595916-clean-architecture-tutorial-for-android-getting-started) - Applying Clean Architecture and Solid Principles to build a robust, maintainable, and testable application.
34 |
35 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | id 'androidx.navigation.safeargs.kotlin'
5 | id 'kotlin-kapt'
6 | id 'dagger.hilt.android.plugin'
7 | id 'kotlin-android-extensions'
8 | }
9 |
10 | android {
11 | compileSdk 31
12 |
13 | defaultConfig {
14 | applicationId "com.developers.noteappktorserver"
15 | minSdk 21
16 | targetSdk 31
17 | versionCode 1
18 | versionName "1.0"
19 |
20 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | kotlinOptions {
34 | jvmTarget = '1.8'
35 | }
36 |
37 | buildFeatures {
38 | viewBinding true
39 | }
40 | }
41 |
42 | dependencies {
43 |
44 | implementation 'androidx.core:core-ktx:1.7.0'
45 | implementation 'androidx.appcompat:appcompat:1.4.0'
46 | implementation 'com.google.android.material:material:1.4.0'
47 | implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
48 | testImplementation 'junit:junit:4.+'
49 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
50 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
51 |
52 |
53 |
54 | // Material Design
55 | implementation 'com.google.android.material:material:1.5.0-beta01'
56 |
57 |
58 | // Coroutine Lifecycle Scopes , ViewModel and architecture components
59 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
60 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
61 |
62 |
63 | // Glide
64 | implementation 'com.github.bumptech.glide:glide:4.12.0'
65 | kapt 'com.github.bumptech.glide:compiler:4.12.0'
66 | annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
67 |
68 | //okhttps
69 | implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
70 | implementation ('com.github.bumptech.glide:okhttp3-integration:4.7.1'){
71 | exclude group: 'glide-parent'
72 | }
73 | // Permissions
74 | implementation 'pub.devrel:easypermissions:3.0.0'
75 |
76 |
77 | // Timber
78 | implementation 'com.jakewharton.timber:timber:4.7.1'
79 |
80 |
81 | implementation 'android.arch.lifecycle:extensions:1.1.1'
82 |
83 | implementation 'com.intuit.ssp:ssp-android:1.0.6'
84 | implementation 'com.intuit.sdp:sdp-android:1.0.6'
85 |
86 | // Navigation component.
87 | implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
88 | implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
89 |
90 |
91 |
92 | //ViewModels delegation extensions for activity
93 | implementation 'androidx.activity:activity-ktx:1.4.0'
94 |
95 | // LiveData
96 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
97 |
98 | // Coroutines
99 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
100 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
101 |
102 | // circleImageview
103 | implementation 'de.hdodenhof:circleimageview:3.1.0'
104 |
105 | // Retrofit
106 | implementation 'com.squareup.retrofit2:retrofit:2.9.0'
107 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
108 | implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
109 | implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2'
110 | implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
111 |
112 | // Moshi
113 | implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
114 | kapt "com.squareup.moshi:moshi-kotlin-codegen:1.8.0"
115 |
116 | // hilt implementation.
117 | implementation 'com.google.dagger:hilt-android:2.39.1'
118 | kapt 'com.google.dagger:hilt-android-compiler:2.39.1'
119 | //hilt view model.
120 | implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
121 |
122 | // Room Data Base
123 | def room_version = "2.3.0"
124 | implementation "androidx.room:room-runtime:$room_version"
125 | kapt "androidx.room:room-compiler:$room_version"
126 | // optional - Kotlin Extensions and Coroutines support for Room
127 | implementation "androidx.room:room-ktx:$room_version"
128 | implementation "androidx.datastore:datastore-preferences:1.0.0"
129 |
130 | api 'com.theartofdev.edmodo:android-image-cropper:2.8.+'
131 |
132 | // rounded Image View
133 | implementation 'com.makeramen:roundedimageview:2.3.0'
134 | // other
135 | implementation 'com.facebook.shimmer:shimmer:0.5.0'
136 | implementation 'com.github.ybq:Android-SpinKit:1.4.0'
137 | implementation "com.airbnb.android:lottie:4.2.1"
138 |
139 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
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.
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
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/developers/noteappktorserver/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.developers.noteappktorserver", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
17 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/app/MyBaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.app
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 |
7 | @HiltAndroidApp
8 | class MyBaseApplication :Application()
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/data/local/DataStoreManager.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.data.local
2 |
3 | import android.content.Context
4 | import androidx.datastore.preferences.core.edit
5 | import androidx.datastore.preferences.preferencesDataStore
6 | import androidx.lifecycle.LiveData
7 | import androidx.lifecycle.MutableLiveData
8 | import com.developers.noteappktorserver.entities.UserInfoDB
9 | import com.developers.noteappktorserver.utils.Constants
10 | import kotlinx.coroutines.*
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.collect
13 | import kotlinx.coroutines.flow.map
14 |
15 | private val Context.dataStore by preferencesDataStore(Constants.USERS_INFO_FILE)
16 |
17 | class DataStoreManager(appContext: Context) {
18 |
19 | private val tokenDataStore = appContext.dataStore
20 | private val scope = CoroutineScope(Job() + Dispatchers.Main)
21 | private val _glucoseFlow = MutableLiveData()
22 | // For public variables, prefer use LiveData just to read values.
23 | val glucoseFlow: LiveData get() = _glucoseFlow
24 |
25 | suspend fun setUserInfo(email: String?=null,password:String?=null,token:String?=null) {
26 | tokenDataStore.edit {preferences->
27 | email?.let {email->
28 | preferences[Constants.USER_EMAIL] = email
29 | }
30 | password?.let{password->
31 | preferences[Constants.USER_PASSWORD] = password
32 | }
33 | token?.let {token->
34 | preferences[Constants.USER_TOKEN] = token
35 | }
36 | }
37 | }
38 |
39 | val infoUser: Flow = tokenDataStore.data.map { preferences ->
40 | UserInfoDB(
41 | preferences[Constants.USER_EMAIL] ?: "",
42 | preferences[Constants.USER_PASSWORD] ?: "",
43 | preferences[Constants.USER_TOKEN] ?: ""
44 | )
45 |
46 | }
47 |
48 |
49 | init {
50 | getTokenUser()
51 | }
52 |
53 | private fun getTokenUser() {
54 | scope.launch {
55 | infoUser.collect { token ->
56 | _glucoseFlow.postValue(token)
57 | }
58 | }
59 |
60 | }
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/data/network/ApiNoteService.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.data.network
2 |
3 | import com.developers.noteappktorserver.entities.MyResponse
4 | import com.developers.noteappktorserver.entities.Note
5 | import com.developers.noteappktorserver.entities.User
6 | import retrofit2.http.*
7 |
8 |
9 | interface ApiNoteService {
10 |
11 | @POST("users/login")
12 | suspend fun loginUser( @Body userinfo: HashMap): MyResponse
13 |
14 |
15 | @POST("users/register")
16 | suspend fun register( @Body userinfo: User): MyResponse
17 |
18 | @GET("notes")
19 | suspend fun getMyNotes(): MyResponse>
20 |
21 | @POST("notes/create")
22 | suspend fun createNote( @Body note: Note): MyResponse
23 |
24 | @DELETE("notes/delete")
25 | suspend fun deleteNote( @Query("id") noteId: Int): MyResponse
26 |
27 | @PUT("notes/update")
28 | suspend fun updateNote(@Body note: Note): MyResponse
29 |
30 | @GET("users/me")
31 | suspend fun getMe(): MyResponse
32 |
33 |
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/di/AppModel.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.di
2 |
3 | import android.content.Context
4 | import com.bumptech.glide.Glide
5 | import com.bumptech.glide.load.engine.DiskCacheStrategy
6 | import com.bumptech.glide.request.RequestOptions
7 | import com.developers.noteappktorserver.R
8 | import com.developers.noteappktorserver.data.local.DataStoreManager
9 | import com.developers.noteappktorserver.qualifiers.IOThread
10 | import com.developers.noteappktorserver.qualifiers.MainThread
11 |
12 | import dagger.Module
13 | import dagger.Provides
14 | import dagger.hilt.InstallIn
15 | import dagger.hilt.android.qualifiers.ApplicationContext
16 | import dagger.hilt.components.SingletonComponent
17 | import kotlinx.coroutines.*
18 | import javax.inject.Singleton
19 |
20 | @Module
21 | @InstallIn(SingletonComponent::class)
22 | object AppModel {
23 |
24 |
25 | @Singleton
26 | @Provides
27 | fun provideApplicationContext(
28 | @ApplicationContext context: Context
29 | ) = context
30 |
31 | // TODO: 11/8/2021 For implementation MainDispatcher
32 |
33 | @MainThread
34 | @Singleton
35 | @Provides
36 | fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
37 |
38 |
39 | // TODO: 11/8/2021 For implementation IODispatcher
40 |
41 | @IOThread
42 | @Singleton
43 | @Provides
44 | fun provideIODispatcher(): CoroutineDispatcher = Dispatchers.IO
45 |
46 |
47 | // TODO: 11/8/2021 For implementation Glide
48 | @Singleton
49 | @Provides
50 | fun provideGlideInstance(
51 | @ApplicationContext context: Context
52 | ) = Glide.with(context).setDefaultRequestOptions(
53 | RequestOptions()
54 | .placeholder(R.drawable.ic_image)
55 | .error(R.drawable.ic_error)
56 | .diskCacheStrategy(DiskCacheStrategy.DATA)
57 |
58 | )
59 | @Provides
60 | @Singleton
61 | fun dataStoreManager(@ApplicationContext appContext: Context): DataStoreManager =
62 | DataStoreManager(appContext)
63 |
64 | // TODO: 11/8/2021 For implementation AppDatabase
65 |
66 | // @Provides
67 | // @Singleton
68 | // fun provideAppDatabase(@ApplicationContext appContext: Context): JobDataBase {
69 | // return Room.databaseBuilder(
70 | // appContext,
71 | // JobDataBase::class.java,
72 | // "job_DB"
73 | // ).setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
74 | // .build()
75 | // }
76 |
77 |
78 |
79 |
80 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/di/DataTimeModel.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.android.components.FragmentComponent
7 | import dagger.hilt.android.components.ViewModelComponent
8 | import dagger.hilt.android.scopes.FragmentScoped
9 | import dagger.hilt.android.scopes.ViewModelScoped
10 | import java.text.SimpleDateFormat
11 | import java.util.*
12 |
13 | @Module
14 | @InstallIn(ViewModelComponent::class)
15 | object DataTimeModel {
16 |
17 | @ViewModelScoped
18 | @Provides
19 | fun provideSimpleDateFormat(): SimpleDateFormat = SimpleDateFormat("EEEE, dd MMMM yyyy HH:mm a", Locale.getDefault())
20 |
21 |
22 | @ViewModelScoped
23 | @Provides
24 | fun provideDate(): Date = Date()
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/di/RetrofitModel.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.di
2 |
3 | import android.util.Log
4 | import com.developers.noteappktorserver.data.local.DataStoreManager
5 | import com.developers.noteappktorserver.data.network.ApiNoteService
6 | import com.developers.noteappktorserver.qualifiers.Token
7 | import com.developers.noteappktorserver.utils.Constants
8 | import com.squareup.moshi.Moshi
9 | import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
10 | import dagger.Module
11 | import dagger.Provides
12 | import dagger.hilt.InstallIn
13 | import dagger.hilt.android.components.ViewModelComponent
14 | import dagger.hilt.android.scopes.ViewModelScoped
15 | import okhttp3.OkHttpClient
16 | import okhttp3.Request
17 | import okhttp3.logging.HttpLoggingInterceptor
18 | import retrofit2.Retrofit
19 | import retrofit2.converter.gson.GsonConverterFactory
20 | import java.util.concurrent.TimeUnit
21 |
22 | @Module
23 | @InstallIn(ViewModelComponent::class)
24 | object RetrofitModel {
25 |
26 |
27 |
28 | @Provides
29 | @ViewModelScoped
30 | @Token
31 | fun provideTokenUser(dataStoreManager: DataStoreManager):String = dataStoreManager.glucoseFlow.value?.token?:""
32 |
33 |
34 |
35 | // TODO: 11/8/2021 For implementation Moshi
36 |
37 | @Provides
38 | @ViewModelScoped
39 | fun providesMoshi(): Moshi = Moshi
40 | .Builder()
41 | .add(KotlinJsonAdapterFactory())
42 | .build()
43 |
44 |
45 | // TODO: 11/8/2021 For implementation OkHttpClient
46 |
47 | @Provides
48 | @ViewModelScoped
49 | fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
50 | val localHttpLoggingInterceptor = HttpLoggingInterceptor()
51 | localHttpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
52 | return localHttpLoggingInterceptor
53 | }
54 |
55 | @Provides
56 | @ViewModelScoped
57 | fun provideOkHttpClient(interceptor: HttpLoggingInterceptor, @Token token: String = ""): OkHttpClient =
58 | OkHttpClient.Builder()
59 | .connectTimeout(30, TimeUnit.SECONDS)
60 | .writeTimeout(30, TimeUnit.SECONDS)
61 | .readTimeout(30, TimeUnit.SECONDS)
62 | .addInterceptor { chain ->
63 | val original: Request = chain.request()
64 | val builder: Request.Builder = chain.request().newBuilder()
65 | val newQuest = if (token.isNotEmpty()) {
66 | Log.i(Constants.TAG, "provideOkHttpClient: $token")
67 | original.newBuilder()
68 | .header("Authorization", "Bearer $token")
69 | .header("Content-Type", "application/json")
70 | .method(original.method, original.body)
71 | .build()
72 | } else {
73 | Log.i(Constants.TAG, "provideOkHttpClient: is empty")
74 |
75 | original.newBuilder()
76 | .header("Content-Type", "application/json")
77 | .method(original.method, original.body)
78 | .build()
79 | }
80 | // builder.addHeader(Constants.CONTENT_TYPE, Constants.APP_JSON)
81 | // builder.method(original.method, original.body)
82 | // chain.proceed(builder.build())
83 | chain.proceed(newQuest)
84 | }
85 | .addNetworkInterceptor(interceptor)
86 | .build()
87 |
88 |
89 | // TODO: 11/8/2021 For implementation Retrofit
90 |
91 | @Provides
92 | @ViewModelScoped
93 | fun providesApiService(moshi: Moshi, okHttpClient: OkHttpClient): ApiNoteService =
94 | Retrofit.Builder()
95 | .run {
96 | baseUrl(Constants.BASE_URL)
97 | client(okHttpClient)
98 | addConverterFactory(GsonConverterFactory.create())
99 | build()
100 | }.create(ApiNoteService::class.java)
101 |
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/entities/MyResponse.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.entities
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 |
6 | data class MyResponse(
7 | @SerializedName("success")
8 | val success:Boolean=false,
9 | @SerializedName("message")
10 | val message:String,
11 | @SerializedName("data")
12 | val data:T?=null
13 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/entities/Note.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.entities
2 |
3 | import android.os.Parcel
4 | import android.os.Parcelable
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class Note(
9 | val id: Int?,
10 | val title: String,
11 | val subTitle: String,
12 | val dataTime: String,
13 | val imagePath: String?=null,
14 | val note: String,
15 | val color: String="#333333",
16 | val webLink: String?=null,
17 | val userId: Int?
18 | ):Parcelable
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/entities/User.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.entities
2 |
3 |
4 |
5 |
6 | data class User(
7 | val id:Int?=-1,
8 | val username:String,
9 | val email:String,
10 | val image:String?,
11 | val password:String
12 | )
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/entities/UserInfoDB.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.entities
2 |
3 | data class UserInfoDB(
4 | val email:String="",
5 | val password:String="",
6 | val token:String=""
7 | ){
8 |
9 | override fun toString(): String {
10 | return "email:${email},password:${password},token ${token}"
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/helpers/Event.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.helpers
2 |
3 | import com.developers.shopapp.helpers.Resource
4 | import kotlinx.coroutines.flow.FlowCollector
5 |
6 | class Event(private val content: T) {
7 |
8 | var hasBeenHandled = false
9 | private set
10 |
11 | fun getContentIfNotHandled(): T? {
12 | return if(!hasBeenHandled) {
13 | hasBeenHandled = true
14 | content
15 | } else null
16 | }
17 |
18 | fun peekContent() = content
19 | }
20 |
21 | class EventObserver(
22 | private inline val onError: ((String) -> Unit)? = null,
23 | private inline val onLoading: (() -> Unit)? = null,
24 | private inline val onSuccess: (T) -> Unit
25 | ) : FlowCollector>> {
26 |
27 |
28 | override suspend fun emit(value: Event>) {
29 | when(val content = value?.peekContent()) {
30 | is Resource.Success -> {
31 | content.data?.let(onSuccess)
32 | }
33 | is Resource.Error -> {
34 | value.getContentIfNotHandled()?.let {
35 | onError?.let { error ->
36 | error(it.message!!)
37 | }
38 | }
39 | }
40 | is Resource.Loading -> {
41 | onLoading?.let { loading ->
42 | loading()
43 | }
44 | }
45 | }
46 |
47 | }
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/helpers/MyValidation.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.helpers
2 |
3 | import android.content.Context
4 | import android.util.Patterns
5 | import com.developers.noteappktorserver.R
6 | import com.google.android.material.textfield.TextInputLayout
7 | import java.util.regex.Matcher
8 | import java.util.regex.Pattern
9 |
10 |
11 | object MyValidation {
12 | fun isValidEmail(email: String): Boolean {
13 | if (email != "") {
14 | //for mail
15 | val mailContainCars = !Patterns.EMAIL_ADDRESS.matcher(email).matches()
16 | val checkMailNumbers = email.split("@")[0]
17 | val checkIfMailNumbers: Int? = checkMailNumbers.toIntOrNull()
18 |
19 | return when {
20 | mailContainCars -> {
21 | false
22 | }
23 | email.length < 14 -> {
24 | false
25 | }
26 | checkIfMailNumbers != null -> {
27 | false
28 | }
29 | else -> {
30 | true
31 | }
32 | }
33 | } else {
34 | return false
35 | }
36 | }
37 |
38 | fun validatePass(
39 | context: Context,
40 | userPass: TextInputLayout
41 | ): Boolean {
42 | val pass = userPass.editText?.text.toString()
43 | val pat = Pattern.compile("[A-Z][^A-Z]*$")
44 | val matchCapital: Matcher = pat.matcher(pass)
45 |
46 | var lastCapitalIndex = -1
47 | if (matchCapital.find()) {
48 | lastCapitalIndex = matchCapital.start()
49 | }
50 | val patNumber = Pattern.compile("[0-9]")
51 | val matchNumber: Matcher = patNumber.matcher(pass)
52 | var lastNum = -1
53 | if (matchNumber.find()) {
54 | lastNum = matchNumber.start()
55 | }
56 | if (pass != "") {
57 | // Info.setText(getString(R.string.add_empty))
58 | //for password
59 | val specialPass = Pattern.compile("[.!@#\$%&*()_+=|<>?{}\\\\\\[\\]~-]")
60 | val b = specialPass.matcher(pass)
61 | val passContainCars = b.find()
62 | //for mail
63 |
64 | //for pass
65 |
66 | when {
67 | pass.length < 8 -> {
68 | userPass.helperText = context.resources.getString(R.string.min_password)
69 | userPass.requestFocus()
70 | return false
71 | }
72 | passContainCars -> {
73 | userPass.helperText =
74 | context.resources.getString(R.string.pass_no_spec_charecters)
75 | userPass.requestFocus()
76 | return false
77 | }
78 | lastCapitalIndex == -1 -> {
79 | userPass.helperText = context.getString(R.string.cap_letter)
80 | userPass.requestFocus()
81 | return false
82 | }
83 | lastNum == -1 -> {
84 | userPass.helperText = context.getString(R.string.on_num)
85 | userPass.requestFocus()
86 | return false
87 | }
88 | else -> {
89 | userPass.helperText = null
90 | return true
91 | }
92 | }
93 | } else {
94 | userPass.helperText = context.resources.getString(R.string.password_empty)
95 | userPass.requestFocus()
96 |
97 | return false
98 |
99 | }
100 |
101 | }
102 |
103 | fun validateMobile(mobile: String): Boolean {
104 | when (mobile.length) {
105 | 11 -> {
106 | val emailSplit = mobile.split("")
107 |
108 | val mobileFirstThreeNumber: String = emailSplit[1] + emailSplit[2] + emailSplit[3]
109 | return mobileFirstThreeNumber == "010" || mobileFirstThreeNumber == "011" || mobileFirstThreeNumber == "012" || mobileFirstThreeNumber == "015"
110 | }
111 | 10 -> {
112 | val emailSplit = mobile.split("")
113 |
114 | val mobileFirstThreeNumber: String = emailSplit[1] + emailSplit[2] + emailSplit[3]
115 | return (mobileFirstThreeNumber == "050" || mobileFirstThreeNumber == "053" || mobileFirstThreeNumber == "054" || mobileFirstThreeNumber == "055"
116 | || mobileFirstThreeNumber == "056" || mobileFirstThreeNumber == "057" || mobileFirstThreeNumber == "058" || mobileFirstThreeNumber == "059")
117 | }
118 | else -> {
119 | return false
120 | }
121 | }
122 |
123 |
124 | }
125 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/helpers/RepositoryUtils.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.helpers
2 |
3 | import com.developers.shopapp.helpers.Resource
4 |
5 | inline fun safeCall(action: () -> Resource): Resource {
6 | return try {
7 | action()
8 | } catch(e: Exception) {
9 | Resource.Error(e.message ?: "An unknown error occurred")
10 | }
11 | }
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/helpers/Resource.kt:
--------------------------------------------------------------------------------
1 | package com.developers.shopapp.helpers
2 |
3 |
4 | sealed class Resource(val data : T? = null , val message : String? = null) {
5 | class Success(data : T) : Resource(data)
6 | class Error(message : String? , data : T? = null) : Resource(data , message)
7 | class Loading(data : T? = null) : Resource(data)
8 | class Init(data : T? = null) : Resource(data)
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/qualifiers/IOThread.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class IOThread()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/qualifiers/MainThread.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class MainThread()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/qualifiers/Token.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.qualifiers
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class Token()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/repositories/AuthenticationRepository.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.repositories
2 |
3 | import com.developers.noteappktorserver.data.network.ApiNoteService
4 | import com.developers.noteappktorserver.entities.MyResponse
5 | import com.developers.noteappktorserver.entities.User
6 | import com.developers.noteappktorserver.qualifiers.IOThread
7 | import com.developers.shopapp.helpers.Resource
8 | import com.developers.noteappktorserver.helpers.safeCall
9 | import kotlinx.coroutines.CoroutineDispatcher
10 | import kotlinx.coroutines.withContext
11 | import javax.inject.Inject
12 | import kotlin.collections.HashMap
13 |
14 | class AuthenticationRepository @Inject constructor(
15 | private val apiShopService: ApiNoteService,
16 | @IOThread
17 | private val dispatcher: CoroutineDispatcher
18 | ) {
19 |
20 | suspend fun loginUser(email: String, password: String): Resource> =
21 | withContext(dispatcher) {
22 | safeCall {
23 | val hasmap = HashMap()
24 | hasmap["email"] = email
25 | hasmap["password"] = password
26 | val result = apiShopService.loginUser(hasmap)
27 | Resource.Success(result)
28 | }
29 | }
30 |
31 |
32 | suspend fun createAccount(user: User): Resource> = withContext(dispatcher) {
33 | safeCall {
34 |
35 | val result = apiShopService.register(user)
36 | Resource.Success(result)
37 | }
38 | }
39 |
40 | suspend fun getProfile(): Resource> = withContext(dispatcher) {
41 | safeCall {
42 | val result=apiShopService.getMe()
43 | Resource.Success(result)
44 | }
45 | }
46 | //
47 | // suspend fun logout():Resource = withContext(dispatcher){
48 | // safeCall {
49 | // val result=apiShopService.logout()
50 | // Resource.Success(result)
51 | // }
52 | // }
53 | //
54 | // suspend fun verifyEmail(email:String):Resource = withContext(dispatcher){
55 | // safeCall {
56 | // val hashMap=HashMap()
57 | // hashMap["email"] = email
58 | // val result=apiShopService.verifyEmail(hashMap)
59 | // Resource.Success(result)
60 | // }
61 | // }
62 | //
63 | // suspend fun verifyCode(email:String,code:String):Resource = withContext(dispatcher){
64 | // safeCall {
65 | // val hashMap=HashMap()
66 | // hashMap["email"] = email
67 | // hashMap["code"] = code
68 | // val result=apiShopService.verifyCode(hashMap)
69 | // Resource.Success(result)
70 | // }
71 | // }
72 | //
73 | // suspend fun resetPassword(password: String, email: String, code: String): Resource = withContext(dispatcher){
74 | // safeCall {
75 | // val hashMap=HashMap()
76 | // hashMap["email"] = email
77 | // hashMap["code"] = code
78 | // hashMap["password"] = password
79 | //
80 | // val result=apiShopService.resetPassword(hashMap)
81 | // Resource.Success(result)
82 | // }
83 | // }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/repositories/CreateNoteRepository.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.repositories
2 |
3 | import com.developers.noteappktorserver.data.network.ApiNoteService
4 | import com.developers.noteappktorserver.entities.MyResponse
5 | import com.developers.noteappktorserver.entities.Note
6 | import com.developers.noteappktorserver.helpers.safeCall
7 | import com.developers.noteappktorserver.qualifiers.IOThread
8 | import com.developers.shopapp.helpers.Resource
9 | import kotlinx.coroutines.CoroutineDispatcher
10 | import kotlinx.coroutines.Dispatchers
11 | import kotlinx.coroutines.withContext
12 | import java.text.SimpleDateFormat
13 | import java.util.*
14 | import javax.inject.Inject
15 |
16 | class NoteRepository @Inject constructor(
17 | private val apiShopService: ApiNoteService,
18 | @IOThread
19 | private val dispatcher: CoroutineDispatcher,
20 | private var simpleDateFormat : SimpleDateFormat,
21 | private var date: Date
22 | ) {
23 |
24 | suspend fun getTimeAndData():String = withContext(dispatcher) {
25 | simpleDateFormat.format(date)
26 | }
27 |
28 | suspend fun setColorIndicator(color:String):String = withContext(dispatcher) {
29 | color
30 | }
31 |
32 | suspend fun insertNote(note: Note): Resource> = withContext(dispatcher) {
33 | safeCall {
34 | val result=apiShopService.createNote(note)
35 |
36 | Resource.Success(result)
37 | }
38 | }
39 |
40 | suspend fun deleteNote(noteId: Int): Resource> = withContext(dispatcher) {
41 | safeCall {
42 | val result=apiShopService.deleteNote(noteId)
43 | Resource.Success(result)
44 | }
45 | }
46 |
47 | suspend fun updateNote(note: Note): Resource> = withContext(dispatcher){
48 | safeCall {
49 | val result=apiShopService.updateNote(note)
50 | Resource.Success(result)
51 | }
52 | }
53 |
54 |
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/repositories/HomeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.repositories
2 |
3 | import com.developers.noteappktorserver.data.network.ApiNoteService
4 | import com.developers.noteappktorserver.entities.MyResponse
5 | import com.developers.noteappktorserver.entities.Note
6 | import com.developers.noteappktorserver.qualifiers.IOThread
7 | import com.developers.shopapp.helpers.Resource
8 | import com.developers.noteappktorserver.helpers.safeCall
9 | import kotlinx.coroutines.CoroutineDispatcher
10 | import kotlinx.coroutines.withContext
11 | import javax.inject.Inject
12 |
13 | class HomeRepository @Inject constructor(
14 | private val apiShopService: ApiNoteService,
15 | @IOThread
16 | private val dispatcher: CoroutineDispatcher
17 | ) {
18 |
19 |
20 |
21 | suspend fun getNotes() :Resource>> = withContext(dispatcher){
22 | safeCall {
23 | val result= apiShopService.getMyNotes()
24 | Resource.Success(result)
25 | }
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/activities/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.activities
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import com.developers.noteappktorserver.R
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 |
9 | @AndroidEntryPoint
10 | class MainActivity : AppCompatActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_main)
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/adapters/NoteAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.adapters
2 |
3 | import android.annotation.SuppressLint
4 | import android.graphics.Color
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.recyclerview.widget.AsyncListDiffer
9 | import androidx.recyclerview.widget.DiffUtil
10 | import androidx.recyclerview.widget.RecyclerView
11 | import com.bumptech.glide.RequestManager
12 | import com.developers.noteappktorserver.R
13 | import com.developers.noteappktorserver.entities.Note
14 | import kotlinx.android.synthetic.main.item_container_note.view.*
15 | import javax.inject.Inject
16 |
17 | class NoteAdapter @Inject constructor(
18 | private val glide : RequestManager
19 | ) : RecyclerView.Adapter() {
20 |
21 |
22 | var notes : List
23 | get() = differ.currentList
24 | set(value) = differ.submitList(value)
25 |
26 | private val diffCallback = object : DiffUtil.ItemCallback() {
27 | override fun areContentsTheSame(oldItem : Note , newItem : Note) : Boolean {
28 | return oldItem.hashCode() == newItem.hashCode()
29 | }
30 |
31 | override fun areItemsTheSame(oldItem : Note , newItem : Note) : Boolean {
32 | return oldItem.id == newItem.id
33 | }
34 | }
35 | private val differ = AsyncListDiffer(this , diffCallback)
36 |
37 | class NoteViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
38 | val imageNote = itemView.image_list_note
39 | val titleNote = itemView.titleNote
40 | val subtitleNote = itemView.subtitleNote
41 | val textDataTimeNote = itemView.textDataTimeNote
42 | val urlItem = itemView.urlItem
43 | val ic_delete_note_list = itemView.ic_delete_note_list
44 | val cardNote = itemView.cardNote
45 | }
46 |
47 | override fun onCreateViewHolder(parent : ViewGroup , viewType : Int) : NoteViewHolder {
48 | return NoteViewHolder(
49 | LayoutInflater.from(parent.context).inflate(
50 | R.layout.item_container_note ,
51 | parent ,
52 | false
53 | )
54 | )
55 | }
56 |
57 | @SuppressLint("Range")
58 | override fun onBindViewHolder(holder : NoteViewHolder , position : Int) {
59 | val note = notes[position]
60 | holder.apply {
61 | note.imagePath?.let {uri->
62 | if (uri.isNotEmpty())
63 | glide.load(uri).into(imageNote)
64 | }
65 | titleNote.text = note.title
66 | subtitleNote.text = note.subTitle
67 | textDataTimeNote.text = note.dataTime
68 |
69 |
70 | note.webLink?.let {uri->
71 | urlItem.text=uri
72 | }
73 |
74 |
75 | itemView.setOnClickListener {
76 | onNoteClickListener?.let { click ->
77 | click(note)
78 | }
79 | }
80 | ic_delete_note_list.setOnClickListener {
81 | onDeleteClickListener?.let { click ->
82 | click(note)
83 | }
84 | }
85 |
86 |
87 | note.color.let { color ->
88 | if (color.endsWith("#FFFFFF")) {
89 | titleNote.setTextColor(Color.parseColor("#000000"))
90 | subtitleNote.setTextColor(Color.parseColor("#000000"))
91 | textDataTimeNote.setTextColor(Color.parseColor("#000000"))
92 | } else {
93 | titleNote.setTextColor(Color.parseColor("#FFFFFF"))
94 | subtitleNote.setTextColor(Color.parseColor("#FFFFFF"))
95 | textDataTimeNote.setTextColor(Color.parseColor("#FFFFFF"))
96 | }
97 | // try {
98 | cardNote.setCardBackgroundColor(Color.parseColor(color))
99 | // } catch (e : Exception) {
100 | // cardNote.setCardBackgroundColor(Color.parseColor("#333333"))
101 | // }
102 |
103 | }
104 |
105 | }
106 | }
107 |
108 | override fun getItemCount() : Int = notes.size
109 |
110 |
111 | // click options
112 | private var onNoteClickListener : ((Note) -> Unit)? = null
113 |
114 | fun setOnNoteClickListener(listener : (Note) -> Unit) {
115 | onNoteClickListener = listener
116 | }
117 |
118 | private var onDeleteClickListener : ((Note) -> Unit)? = null
119 |
120 | fun setOnDeleteClickListener(listener : (Note) -> Unit) {
121 | onDeleteClickListener = listener
122 | }
123 |
124 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/dialogs/AddUrlDialogs.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.dialogs
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Dialog
5 | import android.graphics.Color
6 | import android.graphics.drawable.ColorDrawable
7 | import android.os.Bundle
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import androidx.fragment.app.DialogFragment
12 | import com.developers.noteappktorserver.R
13 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
14 | import dagger.hilt.android.AndroidEntryPoint
15 | import kotlinx.android.synthetic.main.layout_dialog_add_url.*
16 |
17 | @AndroidEntryPoint
18 | class AddUrlDialogs : DialogFragment() {
19 |
20 |
21 | private lateinit var dialogView : View
22 |
23 | private var addUrlListener: ((String,Dialog?) -> Unit)? = null
24 |
25 | fun setPositiveAddUrlListener(listener: (String,Dialog?) -> Unit) {
26 | addUrlListener = listener
27 | }
28 | override fun onCreateView(inflater : LayoutInflater , container : ViewGroup? , savedInstanceState : Bundle?) : View {
29 | return dialogView
30 | }
31 |
32 | @SuppressLint("InflateParams")
33 | override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
34 | dialogView = LayoutInflater.from(requireContext()).inflate(
35 | R.layout.layout_dialog_add_url ,
36 | null
37 | )
38 | return MaterialAlertDialogBuilder(requireContext())
39 | .setView(dialogView)
40 | .setBackground(ColorDrawable(Color.TRANSPARENT))
41 | .create()
42 | }
43 |
44 | override fun onViewCreated(view : View , savedInstanceState : Bundle?) {
45 | super.onViewCreated(view , savedInstanceState)
46 | btAdd.setOnClickListener {
47 | addUrlListener?.let { click ->
48 | click(input_url.text.toString(),dialog)
49 | dismiss()
50 | }
51 | }
52 |
53 | btCancel.setOnClickListener {
54 | dismiss()
55 | }
56 |
57 |
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/fragments/LoginFragment.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.fragments
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.core.view.isVisible
9 | import androidx.core.widget.doAfterTextChanged
10 | import androidx.fragment.app.Fragment
11 | import androidx.fragment.app.viewModels
12 | import androidx.lifecycle.lifecycleScope
13 | import androidx.navigation.NavOptions
14 | import androidx.navigation.fragment.findNavController
15 | import com.developers.noteappktorserver.R
16 | import com.developers.noteappktorserver.data.local.DataStoreManager
17 | import com.developers.noteappktorserver.databinding.FragmentLoginBinding
18 | import com.developers.noteappktorserver.helpers.EventObserver
19 | import com.developers.noteappktorserver.ui.viewmodels.AuthenticationViewModel
20 | import com.developers.noteappktorserver.utils.Constants
21 | import com.developers.shopapp.utils.snackbar
22 |
23 | import dagger.hilt.android.AndroidEntryPoint
24 | import kotlinx.coroutines.launch
25 | import javax.inject.Inject
26 |
27 | @AndroidEntryPoint
28 | class LoginFragment:Fragment() {
29 | private var _binding: FragmentLoginBinding? = null
30 | private val binding get() = _binding!!
31 |
32 |
33 | private val authenticationViewModel: AuthenticationViewModel by viewModels()
34 |
35 | @Inject
36 | lateinit var dataStoreManager: DataStoreManager
37 |
38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
39 | super.onViewCreated(view, savedInstanceState)
40 |
41 |
42 |
43 | // to get email , password if sets it as remember me
44 | val dataUserInfo = dataStoreManager.glucoseFlow.value
45 | binding.inputTextEmail.setText(dataUserInfo?.email)
46 | binding.inputTextPassword.setText(dataUserInfo?.password)
47 | Log.i(Constants.TAG, "dataUserInfo: ${dataUserInfo.toString()}")
48 | // clear error text
49 | binding.inputTextEmail.doAfterTextChanged {
50 | binding.inputTextLayoutEmail.isHelperTextEnabled = false
51 | }
52 |
53 | binding.inputTextPassword.doAfterTextChanged {
54 | binding.inputTextLayoutPassword.isHelperTextEnabled = false
55 | }
56 |
57 | binding.textSignUp.setOnClickListener {
58 | findNavController().navigate(R.id.action_loginFragment_to_registerFragment)
59 | }
60 |
61 | binding.forgetPassword.setOnClickListener {
62 | //findNavController().navigate(R.id.action_loginFragment_to_forgetPasswordFragment)
63 | }
64 | binding.backIcon.setOnClickListener {
65 | requireActivity().finish()
66 | }
67 | // sign in
68 | binding.singinBtn.setOnClickListener {
69 |
70 | authenticationViewModel.loginUser(
71 | binding.inputTextLayoutEmail,
72 | binding.inputTextLayoutPassword,
73 | )
74 | }
75 |
76 | // check login state
77 | subscribeToObservables(savedInstanceState)
78 |
79 |
80 |
81 |
82 | }
83 |
84 | private fun subscribeToObservables(savedInstanceState: Bundle?) {
85 | lifecycleScope.launchWhenCreated {
86 | authenticationViewModel.authLoginUserStatus.collect(EventObserver(
87 | onLoading = {
88 | binding.spinKit.isVisible=true
89 |
90 | Log.i(Constants.TAG, "onViewCreated: Loding ")
91 |
92 | },
93 | onError = {
94 | snackbar(it)
95 | binding.spinKit.isVisible=false
96 | Log.i(Constants.TAG, "onViewCreated: ERROR $it")
97 |
98 | },
99 | onSuccess = {
100 | binding.spinKit.isVisible=false
101 | Log.i(Constants.TAG, "onViewCreated: onSuccess $it")
102 | snackbar(it.message)
103 | it.data?.let { token ->
104 | lifecycleScope.launch {
105 | saveDataAndNavigate(token,savedInstanceState)
106 | }
107 | }
108 |
109 | }
110 | ))
111 | }
112 |
113 | }
114 | private suspend fun saveDataAndNavigate(token: String, savedInstanceState: Bundle?) {
115 | updateToken(token)
116 | if (binding.switchRememberMe.isChecked) {
117 | val password = binding.inputTextPassword.text.toString()
118 | val email = binding.inputTextEmail.text.toString()
119 | saveEmailAndPassword(email, password)
120 | }
121 |
122 | val navOptions = NavOptions.Builder()
123 | .setPopUpTo(R.id.loginFragment, true)
124 | .build()
125 | findNavController().navigate(
126 | R.id.action_loginFragment_to_homeFragment,
127 | savedInstanceState,
128 | navOptions
129 | )
130 | }
131 |
132 | private suspend fun saveEmailAndPassword(email: String, password: String) {
133 | dataStoreManager.setUserInfo(email = email, password = password)
134 |
135 | }
136 |
137 | private suspend fun updateToken(token: String) {
138 | dataStoreManager.setUserInfo(token = token)
139 |
140 | }
141 |
142 | override fun onCreateView(
143 | inflater: LayoutInflater,
144 | container: ViewGroup?,
145 | savedInstanceState: Bundle?
146 | ): View? {
147 | _binding= FragmentLoginBinding.inflate(inflater, container, false)
148 |
149 | return binding.root
150 | }
151 |
152 |
153 | override fun onDestroyView() {
154 | super.onDestroyView()
155 | _binding=null
156 | }
157 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/fragments/RegisterFragment.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.fragments
2 |
3 | import android.Manifest
4 | import android.annotation.SuppressLint
5 | import android.app.Activity
6 | import android.content.Intent
7 | import android.net.Uri
8 | import android.os.Build
9 | import android.os.Bundle
10 | import android.util.Log
11 | import android.view.LayoutInflater
12 | import android.view.View
13 | import android.view.ViewGroup
14 | import androidx.annotation.RequiresApi
15 | import androidx.core.view.isVisible
16 | import androidx.core.widget.doAfterTextChanged
17 | import androidx.fragment.app.Fragment
18 | import androidx.fragment.app.viewModels
19 | import androidx.lifecycle.lifecycleScope
20 | import androidx.navigation.NavOptions
21 | import androidx.navigation.fragment.findNavController
22 | import com.developers.noteappktorserver.R
23 | import com.developers.noteappktorserver.data.local.DataStoreManager
24 | import com.developers.noteappktorserver.databinding.FragmentRegisterBinding
25 | import com.developers.noteappktorserver.entities.Note
26 | import com.developers.noteappktorserver.helpers.EventObserver
27 | import com.developers.noteappktorserver.ui.viewmodels.AuthenticationViewModel
28 | import com.developers.noteappktorserver.utils.Constants
29 | import com.developers.noteappktorserver.utils.NoteUtility
30 | import com.developers.shopapp.utils.snackbar
31 | import com.theartofdev.edmodo.cropper.CropImage
32 | import com.theartofdev.edmodo.cropper.CropImageView
33 |
34 | import dagger.hilt.android.AndroidEntryPoint
35 | import kotlinx.coroutines.launch
36 | import pub.devrel.easypermissions.AppSettingsDialog
37 | import pub.devrel.easypermissions.EasyPermissions
38 | import javax.inject.Inject
39 |
40 | @AndroidEntryPoint
41 | class RegisterFragment:Fragment(), EasyPermissions.PermissionCallbacks {
42 | private var _binding: FragmentRegisterBinding? = null
43 | private val binding get() = _binding!!
44 |
45 | private val authenticationViewModel: AuthenticationViewModel by viewModels()
46 |
47 | @Inject
48 | lateinit var dataStoreManager: DataStoreManager
49 | private var imageUserUri:String=""
50 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
51 | super.onViewCreated(view, savedInstanceState)
52 |
53 | // clear error text
54 | binding.inputTextUserName.doAfterTextChanged {
55 | binding.inputTextLayoutUserName.isHelperTextEnabled = false
56 | }
57 | binding.inputTextEmail.doAfterTextChanged {
58 | binding.inputTextLayoutEmail.isHelperTextEnabled = false
59 | }
60 |
61 | binding.inputTextPassword.doAfterTextChanged {
62 | binding.inputTextLayoutPassword.isHelperTextEnabled = false
63 | }
64 |
65 | binding.alreadyHaveAccount.setOnClickListener {
66 | findNavController().navigate(R.id.action_registerFragment_to_loginFragment)
67 | }
68 | binding.backIcon.setOnClickListener {
69 | findNavController().popBackStack()
70 | }
71 | // sign in
72 | binding.createAccount.setOnClickListener {
73 | authenticationViewModel.createAccount(
74 | binding.inputTextLayoutUserName,
75 | binding.inputTextLayoutEmail,
76 | binding.inputTextLayoutPassword,imageUserUri
77 | )
78 | }
79 |
80 | binding.userImage.setOnClickListener {
81 | requestPermissions()
82 | }
83 |
84 | // check login state
85 | subscribeToObservables(savedInstanceState)
86 |
87 |
88 |
89 |
90 | }
91 |
92 | private fun subscribeToObservables(savedInstanceState: Bundle?) {
93 | lifecycleScope.launchWhenStarted {
94 | authenticationViewModel.createAccountStatus.collect(EventObserver(
95 | onLoading ={
96 | binding.spinKit.isVisible=true
97 | },
98 | onSuccess = {
99 | binding.spinKit.isVisible=false
100 |
101 | snackbar(it.message)
102 | it.data?.let {
103 | lifecycleScope.launch {
104 |
105 | saveDataAndNavigate(it,savedInstanceState)
106 | }
107 | }
108 | },
109 | onError = {
110 | binding.spinKit.isVisible=false
111 | snackbar(it)
112 | }
113 | ))
114 | }
115 | }
116 |
117 | private suspend fun saveDataAndNavigate(token: String, savedInstanceState: Bundle?) {
118 | updateToken(token)
119 | val navOptions = NavOptions.Builder()
120 | .setPopUpTo(R.id.registerFragment, true)
121 | .build()
122 | findNavController().navigate(
123 | R.id.action_registerFragment_to_homeFragment,
124 | savedInstanceState,
125 | navOptions
126 | )
127 | }
128 |
129 | private fun saveEmailAndPassword(email: String, password: String) {
130 | lifecycleScope.launch {
131 | dataStoreManager.setUserInfo(email = email,password = password)
132 | }
133 | }
134 |
135 | private suspend fun updateToken(token: String) {
136 | dataStoreManager.setUserInfo(token = token)
137 |
138 | }
139 |
140 |
141 | override fun onCreateView(
142 | inflater: LayoutInflater,
143 | container: ViewGroup?,
144 | savedInstanceState: Bundle?
145 | ): View? {
146 | _binding= FragmentRegisterBinding.inflate(inflater, container, false)
147 |
148 | return binding.root
149 | }
150 |
151 |
152 | override fun onDestroyView() {
153 | super.onDestroyView()
154 | _binding=null
155 | }
156 |
157 | private fun requestPermissions() {
158 |
159 | if (NoteUtility.hasReadExternalStoragePermissions(requireContext())) {
160 | null
161 | }
162 |
163 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
164 | EasyPermissions.requestPermissions(
165 | this,
166 | "you need to accept read storage permissions to use this optional.",
167 | Constants.REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSIONS,
168 | Manifest.permission.READ_EXTERNAL_STORAGE
169 | )
170 | } else {
171 | EasyPermissions.requestPermissions(
172 | this,
173 | "you need to accept read storage permissions to use this optional.",
174 | Constants.REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSIONS,
175 | Manifest.permission.READ_EXTERNAL_STORAGE
176 | )
177 | }
178 | }
179 |
180 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
181 | override fun onPermissionsGranted(requestCode: Int, perms: MutableList) {
182 | openGallery()
183 | }
184 |
185 | @RequiresApi(Build.VERSION_CODES.Q)
186 | override fun onPermissionsDenied(requestCode: Int, perms: MutableList) {
187 | if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
188 | AppSettingsDialog.Builder(this).build().show()
189 | } else {
190 | requestPermissions()
191 | }
192 | }
193 |
194 | override fun onRequestPermissionsResult(
195 | requestCode: Int,
196 | permissions: Array,
197 | grantResults: IntArray
198 | ) {
199 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
200 | EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
201 | }
202 |
203 | private fun openGallery() {
204 | CropImage.startPickImageActivity(requireContext(), this@RegisterFragment)
205 | }
206 |
207 | fun cropImage(uri: Uri?) {
208 | uri?.let { myuri ->
209 | CropImage.activity(uri)
210 | .setCropShape(CropImageView.CropShape.OVAL)
211 | .setMultiTouchEnabled(true)
212 | .setGuidelines(CropImageView.Guidelines.ON)
213 | .start(requireContext(), this)
214 | }
215 |
216 | }
217 |
218 | @SuppressLint("CheckResult")
219 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
220 | super.onActivityResult(requestCode, resultCode, data)
221 | Log.i("here", "onActivityResult: ")
222 | when (requestCode) {
223 | CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE -> {
224 | if (resultCode == Activity.RESULT_OK) {
225 | val uri = CropImage.getPickImageResultUri(requireContext(), data)
226 | cropImage(uri)
227 | }
228 | }
229 | CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE -> {
230 | val result = CropImage.getActivityResult(data)
231 | if (resultCode == Activity.RESULT_OK) {
232 | binding.userImage.setImageURI(result.uri)
233 | imageUserUri = result.uri.toString()
234 | }
235 | }
236 |
237 | }
238 |
239 | }
240 |
241 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/fragments/SplashFragment.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.fragments
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.os.Handler
6 | import android.util.Log
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.Toast
11 | import androidx.fragment.app.Fragment
12 | import androidx.lifecycle.lifecycleScope
13 | import androidx.navigation.NavOptions
14 | import androidx.navigation.fragment.findNavController
15 | import com.developers.noteappktorserver.R
16 | import com.developers.noteappktorserver.data.local.DataStoreManager
17 | import com.developers.noteappktorserver.databinding.FragmentSplashBinding
18 |
19 | import dagger.hilt.android.AndroidEntryPoint
20 | import kotlinx.coroutines.delay
21 | import kotlinx.coroutines.flow.collect
22 | import kotlinx.coroutines.launch
23 | import javax.inject.Inject
24 |
25 | @AndroidEntryPoint
26 | class SplashFragment : Fragment() {
27 | private var _binding: FragmentSplashBinding? = null
28 | private val binding get() = _binding!!
29 |
30 | @Inject
31 | lateinit var dataStoreManager: DataStoreManager
32 |
33 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
34 | super.onViewCreated(view, savedInstanceState)
35 |
36 | binding.tvNoteApp.animate().translationY(-1400f).setDuration(2700).setStartDelay(0)
37 | // binding.animationView.animate().translationX(2000f).setDuration(2700).setStartDelay(2900)
38 |
39 |
40 |
41 | Handler().postDelayed({
42 | checkUserStatsAndNavigate(savedInstanceState)
43 |
44 | }, 5000)
45 |
46 |
47 | }
48 |
49 | private fun checkUserStatsAndNavigate(savedInstanceState: Bundle?) {
50 | lifecycleScope.launchWhenStarted {
51 | dataStoreManager.infoUser.collect {userInfo->
52 | val navOptions = NavOptions.Builder()
53 | .setPopUpTo(R.id.splashFragment, true)
54 | .build()
55 |
56 | if (userInfo.token.isNotEmpty()) {
57 | findNavController().navigate(
58 | R.id.action_splashFragment_to_homeFragment,
59 | savedInstanceState,
60 | navOptions
61 | )
62 | } else {
63 | findNavController().navigate(
64 | R.id.action_splashFragment_to_loginFragment,
65 | savedInstanceState,
66 | navOptions
67 | )
68 | }
69 | }
70 | }
71 | }
72 |
73 |
74 | override fun onCreateView(
75 | inflater: LayoutInflater,
76 | container: ViewGroup?,
77 | savedInstanceState: Bundle?
78 | ): View? {
79 | _binding = FragmentSplashBinding.inflate(inflater, container, false)
80 |
81 | return binding.root
82 | }
83 |
84 |
85 | override fun onDestroyView() {
86 | super.onDestroyView()
87 | _binding = null
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/viewmodels/AuthenticationViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.viewmodels
2 |
3 | import android.content.Context
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.developers.noteappktorserver.entities.MyResponse
7 | import com.developers.noteappktorserver.entities.User
8 | import com.developers.noteappktorserver.helpers.Event
9 | import com.developers.noteappktorserver.helpers.MyValidation
10 | import com.developers.noteappktorserver.qualifiers.MainThread
11 | import com.developers.noteappktorserver.repositories.AuthenticationRepository
12 | import com.developers.shopapp.helpers.Resource
13 | import com.google.android.material.textfield.TextInputLayout
14 | import dagger.hilt.android.lifecycle.HiltViewModel
15 | import dagger.hilt.android.qualifiers.ApplicationContext
16 | import kotlinx.coroutines.CoroutineDispatcher
17 | import kotlinx.coroutines.flow.MutableStateFlow
18 | import kotlinx.coroutines.launch
19 | import javax.inject.Inject
20 |
21 | @HiltViewModel
22 | class AuthenticationViewModel @Inject constructor(
23 | @ApplicationContext val context: Context,
24 | private val repository: AuthenticationRepository,
25 | @MainThread
26 | private val dispatcher: CoroutineDispatcher
27 |
28 | ) : ViewModel() {
29 |
30 |
31 | private val _loginUserStatus =
32 | MutableStateFlow>>>(Event(Resource.Init()))
33 | val authLoginUserStatus: MutableStateFlow>>> = _loginUserStatus
34 |
35 | private val _createAccountStatus =
36 | MutableStateFlow>>>(Event(Resource.Init()))
37 | val createAccountStatus: MutableStateFlow>>> = _createAccountStatus
38 |
39 |
40 |
41 | // private val _logoutStatus = MutableStateFlow>>(Event(Resource.Init()))
42 | // val logoutStatus: MutableStateFlow>> = _logoutStatus
43 | //
44 | // private val _verifyEmailStatus = MutableStateFlow>>(Event(Resource.Init()))
45 | // val verifyEmailStatus: MutableStateFlow>> = _verifyEmailStatus
46 | //
47 | // private val _verifyCodeStatus = MutableStateFlow>>(Event(Resource.Init()))
48 | // val verifyCodeStatus: MutableStateFlow>> = _verifyCodeStatus
49 | //
50 | // private val _resetPasswordStatus = MutableStateFlow>>(Event(Resource.Init()))
51 | // val resetPasswordStatus: MutableStateFlow>> = _resetPasswordStatus
52 |
53 |
54 | fun loginUser(
55 | inputTextLayoutEmail: TextInputLayout,
56 | inputTextLayoutPassword: TextInputLayout
57 | ) {
58 | viewModelScope.launch(dispatcher) {
59 | val email = inputTextLayoutEmail.editText!!.text.toString()
60 | val password = inputTextLayoutPassword.editText!!.text.toString()
61 | when {
62 | email.isEmpty() -> {
63 | _loginUserStatus.emit(Event(Resource.Error("E-mail is require")))
64 | inputTextLayoutEmail.isHelperTextEnabled = true
65 | inputTextLayoutEmail.helperText = "Require*"
66 | return@launch
67 | }
68 |
69 | !MyValidation.isValidEmail(email = email) -> {
70 | _loginUserStatus.emit(Event(Resource.Error("E-mail is not valid")))
71 | inputTextLayoutEmail.isHelperTextEnabled = true
72 | inputTextLayoutEmail.helperText = "not valid"
73 | }
74 | password.isEmpty() -> {
75 | _loginUserStatus.emit(Event(Resource.Error("Password is require")))
76 | inputTextLayoutPassword.isHelperTextEnabled = true
77 | inputTextLayoutPassword.helperText = "Require*"
78 | return@launch
79 | }
80 | !MyValidation.validatePass(context, inputTextLayoutPassword) -> {
81 | _loginUserStatus.emit(Event(Resource.Error(inputTextLayoutPassword.helperText.toString())))
82 | }
83 | else -> {
84 | _loginUserStatus.emit(Event(Resource.Loading()))
85 | val result = repository.loginUser(email, password)
86 | _loginUserStatus.emit(Event(result))
87 | }
88 | }
89 | }
90 |
91 | }
92 |
93 | fun createAccount(
94 | inputTextLayoutUserName: TextInputLayout,
95 | inputTextLayoutEmail: TextInputLayout,
96 | inputTextLayoutPassword: TextInputLayout,
97 | imageUserUri: String
98 | ) {
99 | viewModelScope.launch(dispatcher) {
100 | val username = inputTextLayoutUserName.editText!!.text.toString()
101 | val email = inputTextLayoutEmail.editText!!.text.toString()
102 | val password = inputTextLayoutPassword.editText!!.text.toString()
103 | when {
104 | imageUserUri.isEmpty() -> {
105 | _createAccountStatus.emit(Event(Resource.Error("Please Selected Your image profile")))
106 | return@launch
107 | }
108 | username.isEmpty() -> {
109 | _createAccountStatus.emit(Event(Resource.Error("Username is require")))
110 | inputTextLayoutUserName.isHelperTextEnabled = true
111 | inputTextLayoutUserName.helperText = "Require*"
112 | return@launch
113 | }
114 |
115 | email.isEmpty() -> {
116 | _createAccountStatus.emit(Event(Resource.Error("E-mail is require")))
117 | inputTextLayoutEmail.isHelperTextEnabled = true
118 | inputTextLayoutEmail.helperText = "Require*"
119 | return@launch
120 | }
121 |
122 | !MyValidation.isValidEmail(email = email) -> {
123 | _createAccountStatus.emit(Event(Resource.Error("E-mail is not valid")))
124 | inputTextLayoutEmail.isHelperTextEnabled = true
125 | inputTextLayoutEmail.helperText = "not valid"
126 | return@launch
127 | }
128 |
129 |
130 | password.isEmpty() -> {
131 | _createAccountStatus.emit(Event(Resource.Error("Password is require")))
132 | inputTextLayoutPassword.isHelperTextEnabled = true
133 | inputTextLayoutPassword.helperText = "Require*"
134 | return@launch
135 | }
136 | !MyValidation.validatePass(context, inputTextLayoutPassword) -> {
137 | _createAccountStatus.emit(Event(Resource.Error(inputTextLayoutPassword.helperText.toString())))
138 | return@launch
139 | }
140 | else -> {
141 | _createAccountStatus.emit(Event(Resource.Loading()))
142 | val user=User(
143 | username = username,
144 | email = email,
145 | password = password,
146 | image = imageUserUri
147 | )
148 | val result = repository.createAccount(
149 | user
150 | )
151 | _createAccountStatus.emit(Event(result))
152 | return@launch
153 | }
154 | }
155 | }
156 |
157 |
158 | }
159 |
160 |
161 | //
162 | // fun logout() {
163 | // viewModelScope.launch(dispatcher) {
164 | // _logoutStatus.emit(Event(Resource.Loading()))
165 | // val result = repository.logout()
166 | // _logoutStatus.emit(Event(result))
167 | // }
168 | // }
169 | //
170 | // fun verifyEmail(inputTextLayoutEmail: TextInputLayout) {
171 | // viewModelScope.launch(dispatcher) {
172 | // val email = inputTextLayoutEmail.editText!!.text.toString()
173 | // when {
174 | // email.isEmpty() -> {
175 | // _loginUserStatus.emit(Event(Resource.Error("E-mail is require")))
176 | // inputTextLayoutEmail.isHelperTextEnabled = true
177 | // inputTextLayoutEmail.helperText = "Require*"
178 | // }
179 | //
180 | // !MyValidation.isValidEmail(email = email) -> {
181 | // _loginUserStatus.emit(Event(Resource.Error("E-mail is not valid")))
182 | // inputTextLayoutEmail.isHelperTextEnabled = true
183 | // inputTextLayoutEmail.helperText = "not valid"
184 | // }
185 | // else -> {
186 | // _verifyEmailStatus.emit(Event(Resource.Loading()))
187 | // val result = repository.verifyEmail(email)
188 | // _verifyEmailStatus.emit(Event(result))
189 | // }
190 | // }
191 | // }
192 | //
193 | // }
194 | //
195 | // fun verifyCode(email: String, codeEmail: PinView) {
196 | // viewModelScope.launch(dispatcher) {
197 | // val code = codeEmail.text.toString()
198 | // when {
199 | // code.isEmpty() -> {
200 | // _verifyCodeStatus.emit(Event(Resource.Error("Code is require")))
201 | // }
202 | //
203 | // code.length<4 -> {
204 | // _verifyCodeStatus.emit(Event(Resource.Error("Code content 4 numbers")))
205 | // }
206 | // else -> {
207 | // _verifyCodeStatus.emit(Event(Resource.Loading()))
208 | // val result = repository.verifyCode(email,code)
209 | // _verifyCodeStatus.emit(Event(result))
210 | // }
211 | // }
212 | // }
213 | //
214 | // }
215 | //
216 | // fun resetPassword(inputTextLayoutPassword: TextInputLayout, email: String, code: String) {
217 | // viewModelScope.launch {
218 | // val password=inputTextLayoutPassword.editText?.text.toString()
219 | // when{
220 | // password.isEmpty() -> {
221 | // _resetPasswordStatus.emit(Event(Resource.Error("Password is require")))
222 | // inputTextLayoutPassword.isHelperTextEnabled = true
223 | // inputTextLayoutPassword.helperText = "Require*"
224 | // }
225 | // !MyValidation.validatePass(context, inputTextLayoutPassword) -> {
226 | // _resetPasswordStatus.emit(Event(Resource.Error(inputTextLayoutPassword.helperText.toString())))
227 | // }
228 | // else ->{
229 | // _resetPasswordStatus.emit(Event(Resource.Loading()))
230 | // val result = repository.resetPassword(password,email,code)
231 | // _resetPasswordStatus.emit(Event(result))
232 | // }
233 | // }
234 | // }
235 | // }
236 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/ui/viewmodels/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.ui.viewmodels
2 |
3 | import android.content.Context
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.developers.noteappktorserver.entities.MyResponse
7 | import com.developers.noteappktorserver.entities.Note
8 | import com.developers.noteappktorserver.entities.User
9 | import com.developers.noteappktorserver.helpers.Event
10 | import com.developers.noteappktorserver.qualifiers.MainThread
11 | import com.developers.noteappktorserver.repositories.AuthenticationRepository
12 | import com.developers.noteappktorserver.repositories.HomeRepository
13 | import com.developers.noteappktorserver.repositories.NoteRepository
14 | import com.developers.shopapp.helpers.Resource
15 | import dagger.hilt.android.lifecycle.HiltViewModel
16 | import dagger.hilt.android.qualifiers.ApplicationContext
17 | import kotlinx.coroutines.CoroutineDispatcher
18 | import kotlinx.coroutines.flow.MutableStateFlow
19 | import kotlinx.coroutines.launch
20 | import javax.inject.Inject
21 |
22 | @HiltViewModel
23 | class HomeViewModel@Inject constructor(
24 | @ApplicationContext val context: Context,
25 | private val repository: HomeRepository,
26 | private val noteRepository: NoteRepository,
27 | private val authRepository: AuthenticationRepository,
28 | @MainThread
29 | private val dispatcher: CoroutineDispatcher
30 |
31 | ) : ViewModel() {
32 |
33 | private val _notesStatus =
34 | MutableStateFlow>>>>(Event(Resource.Init()))
35 | val notesStatus: MutableStateFlow>>>> = _notesStatus
36 |
37 | private val _deleteNoteStatus =
38 | MutableStateFlow>>>(Event(Resource.Init()))
39 | val deleteNoteStatus: MutableStateFlow>>> = _deleteNoteStatus
40 | private val _userInfoStatus =
41 | MutableStateFlow>>>(Event(Resource.Init()))
42 | val userInfoStatus: MutableStateFlow>>> = _userInfoStatus
43 |
44 | init {
45 | getNotes()
46 | myProfile()
47 | }
48 |
49 | private fun myProfile(){
50 | viewModelScope.launch {
51 | userInfoStatus.emit(Event(Resource.Loading()))
52 |
53 | val result=authRepository.getProfile();
54 | userInfoStatus.emit(Event(result))
55 |
56 | }
57 | }
58 |
59 | fun getNotes(){
60 | viewModelScope.launch(dispatcher) {
61 | _notesStatus.emit(Event(Resource.Loading()))
62 | val result=repository.getNotes()
63 | _notesStatus.emit(Event(result))
64 | }
65 | }
66 |
67 | fun searchNote(toString: String) {
68 |
69 | }
70 |
71 | fun deleteNote(noteId: Int) {
72 | viewModelScope.launch(dispatcher) {
73 | _deleteNoteStatus.emit(Event(Resource.Loading()))
74 | val result= noteRepository.deleteNote(noteId)
75 | _deleteNoteStatus.emit(Event(result))
76 | }
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/utils/BaseEXT.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.utils
2 |
3 | import android.content.Context
4 | import android.net.ConnectivityManager
5 | import androidx.appcompat.app.AppCompatDelegate
6 | import dagger.hilt.android.qualifiers.ApplicationContext
7 | import kotlinx.coroutines.flow.Flow
8 | import kotlinx.coroutines.flow.flow
9 | import okhttp3.Call
10 | import okhttp3.ResponseBody
11 | import retrofit2.HttpException;
12 | import java.io.IOException
13 | import java.net.SocketTimeoutException
14 | import java.text.SimpleDateFormat
15 | import java.util.*
16 |
17 | fun isNetworkConnected(@ApplicationContext context: Context): Flow = flow {
18 | val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
19 | cm?.let {
20 | val activeNetwork = cm.activeNetworkInfo
21 | emit(activeNetwork != null && activeNetwork.isConnectedOrConnecting)
22 | }
23 |
24 | emit(false)
25 | }
26 |
27 | fun setupTheme(isDarkMode: Boolean) {
28 | if (isDarkMode) {
29 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
30 | } else {
31 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
32 | }
33 | }
34 |
35 | fun errorMessageHandler(call: Call, t: Throwable): Flow =flow{
36 | if (t is SocketTimeoutException) {
37 | emit( "Connection timeout, Please try again!")
38 | } else if (t is HttpException) {
39 | val body: ResponseBody = (t as HttpException).response()?.errorBody()!!
40 | try {
41 | emit( body.toString())
42 | } catch (e: IOException) {
43 | e.printStackTrace()
44 | }
45 | } else if (t is IOException) {
46 | emit( "Request timeout, Please try again!")
47 | } else {
48 | //Call was cancelled by user
49 | if (call.isCanceled()) {
50 | emit( "Call was cancelled forcefully, Please try again!")
51 | } else {
52 | emit( "Network Problem, Please try again!")
53 | }
54 | }
55 | emit( "Network Problem, Please try again!")
56 | }
57 |
58 | fun dateFormatter(Date: String?): Long {
59 |
60 | Date?.let {
61 |
62 | val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm")
63 | val date: Date = formatter.parse(Date)
64 | return date.time
65 | }
66 | return 0
67 | }
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/utils/FragmentEXT.kt:
--------------------------------------------------------------------------------
1 | package com.developers.shopapp.utils
2 |
3 | import android.app.Activity
4 | import androidx.appcompat.app.AppCompatDelegate
5 | import androidx.fragment.app.Fragment
6 | import com.google.android.material.snackbar.Snackbar
7 |
8 | fun Fragment.snackbar(message:String){
9 | Snackbar.make(
10 | requireView(),
11 | message,
12 | Snackbar.LENGTH_LONG
13 | ).show()
14 |
15 | }
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/utils/KeyBordEXT.kt:
--------------------------------------------------------------------------------
1 | package com.developers.shopapp.utils
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.inputmethod.InputMethodManager
6 |
7 | fun View.hideKeyboard() {
8 | val inputManager =
9 | context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
10 | inputManager.hideSoftInputFromWindow(windowToken, 0)
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/utils/NoteUtility.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.utils
2 |
3 | import android.Manifest
4 | import android.content.Context
5 | import android.os.Build
6 | import androidx.annotation.RequiresApi
7 | import pub.devrel.easypermissions.EasyPermissions
8 |
9 | object NoteUtility {
10 |
11 |
12 | fun hasReadExternalStoragePermissions(context: Context) =
13 | when {
14 | Build.VERSION.SDK_INT < Build.VERSION_CODES.Q -> {
15 | EasyPermissions.hasPermissions(
16 | context,
17 | Manifest.permission.READ_EXTERNAL_STORAGE
18 | )
19 | }
20 | else -> {
21 | EasyPermissions.hasPermissions(
22 | context,
23 | Manifest.permission.READ_EXTERNAL_STORAGE
24 | )
25 | }
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/developers/noteappktorserver/utils/constants.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver.utils
2 |
3 | import android.content.Context
4 | import androidx.datastore.preferences.core.stringPreferencesKey
5 | import java.util.*
6 |
7 |
8 | object Constants {
9 | val ACTION_LOGIN_FRAGMENT_AFTER_LOGOUT: String="ACTION_LOGIN_FRAGMENT_AFTER_LOGOUT"
10 | const val TAG = "GAMALRAGAB"
11 | const val REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSIONS=123
12 | const val USERS_INFO_FILE: String = "USER_INFO"
13 | const val BASE_URL = "http://45da-197-38-125-238.ngrok.io/v1/"
14 | val USER_TOKEN = stringPreferencesKey("USER_TOKEN")
15 | val USER_EMAIL = stringPreferencesKey("USER_EMAIL")
16 | val USER_PASSWORD = stringPreferencesKey("USER_PASSWORD")
17 | const val IMAGE_URL =
18 | "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxEQEBEQDw4QEBATDhAVFg8TEBAVEBARGBIWFhYSFRMYHSgjGBsmJxYZITEhMSorOi4uFx80ODMtNystLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOYA2wMBIgACEQEDEQH/xAAcAAEAAQUBAQAAAAAAAAAAAAAABwECAwYIBQT/xABGEAACAQMBAgsEBwQHCQAAAAAAAQIDBBEFEiEGBxMXIjFBUmGT4lFxgZEUIzJCYqHBcqKx0RYzU1SCg5IVJENjc7KzwvD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AnEAAAAAAAAAAAAAAAAAAACmQKgAAAAAAAAAAAAAAAAAAAAAAAAAAebruuW9lSdW5qqnHqS65zl3YR65Mpwi1qlY21S5rPowW6PbObeIwXi2c5cI9er39eVe4ll71GC+xSh2Qiv4vtA3nXON+4m3GyoQox/tKq26j8VFNKP5mq3PDvVKjzK/rLwgqcF+7FGuAD1anCS9l9q+uX/nT/mYf9tXX97ufPq/zPgAHo09eu4vMby5T/wCvU/mbRwd40L62ko3EvplLtU8KtHxjUS3+5p+9GjADpXgxwvtNQj9RVSqJZlQnhVo+Oz2rxWT30cn0K0qc41KcpQnBpxnFtSi12prqJp4t+MP6W1a3jjG5/wCHVW6NwsdTXZP+P5ASOAAAAAAAAAAAAAAAAAAAAAAFGBDnHjqzlWoWifRhDlZLscpZjH5JP5kXmzcZV7y2q3b7IVI0l/lwUX+e0ayAAAAAAAAALoTcWpRk4yTTjJPEoyTypJ+1dZaAOm+B+sfTbKhcP7c6aU0uypHoz/NZ+J7JG/EfduVlWpN/1dy8L2KUVL+OSSAAAAAAAAAAAAAAAAAAAAAFs3hN+xMDlrWqu3dXM31yuriXzqyZ8RluXmc37ZzfzkzEAAAAAAAAAAAEscQ1XpX0PC3l/wCRfoiXCF+Iqb+lXcex21N/FVGv1JoAAAAAAAAAAAAAAAAAAAAUZUowOXeElk7e8uqL+5c1Uv2XNyi/k0zzjbuNWtRnqleVCe1uhGruaSrwWzJZfXhKK+DNRAAAAAAAAAAACVeIi26d7V/BQgvfmcn+hL5E3ExrFrRpytp1krq4uZONPZnlqNNYzJLC6n2ksgAAAAAAAAAAAAAAAAAAAKMqAOZ+HFq6WpXsH/eqkl+zUfKL/vR4ZIPHVp/J38KyW6tbxz+1B7L/ACcfkR8AAAAAAAAAAAG1cV9Bz1W1S+66k37o05fzXzOiiF+I3Tdq5uLlrdToqlF/iqSUpfJQX+omgAAAAAAAAAAAAAAAAAAAAAA0Hjl0l1rDl4R2p21RTeOvkpdGb+GVL3RZBJ1jVpqScZJSjJNNPqae5pnPHGNwZjp15sUs8hVhylNP7m9qVPPbjd8JIDVQAAAAAAAAwbpxX8FaeoXFSVwnKhQVOUodlScm9mD/AA9Ftrt3ICUeKzSPo2m0tqOJ1s1pbt/S+yn8MG3lEsbkVAAAAAAAAAAAAAAAAAAAAAABGfHhpjnbULmKzyNVxk/ZCoks/NIkww3dtCrTnTqRjOE4uMoSWYyTWGmgOUQZ76hydWrT7lapDx6M3H9DAAAAAAACduJnS3R091ZRxK4rSqb+vk0lCHw3N/4iFNIt+Vubek1lVLq3g17VOrGLXybOp6cFFKMUlFJJJLCSXUkgLgAAAAAAAAAAAAAAAAAAAAAAAD4da1GNrb1rif2aVKc2vbsptR+O5fE+yc0k22kkm231Je1kMcYfGJC7pVbO2hLk3UincbSxVjF5ezH2Nr8gI6vLqVapOrUxt1KkpyUViKlJ5eF7N5hAAAAAAAPo0+7lQrUq8EnOlVhUipfZcoSUlnwyjp7RNQjc29G4h9mrSjP3NrejlklDiy4e0bWjCyuttLl5KFbdycITw0pvsw29/YmgJkBRMqAAAAAAAAAAAAAAAAAAPL1rhBa2cdq5uKdP8LeZv3QW9geofDq+r0LSnytzWhSh2OT3yfsiuuT8ERnrvHCt8bG2b/51fcvfGkt/za9xGOq6nWuqsq1xVlVqP70nuiu7FfdXggNy4e8Y1S+Ura1TpWr3Sk91WuvY+7Dw7e32GggAAAAAAAAAAABJPALjLlbKFtfZnQSShXWXUpLsjNfej49a8eyY7C9pV6catGpGrTkt04STi/kcpnoaNrVzZz5S1rzpNvek+hP9qL3MDqQERaDxwtYhfWzfZy1D+MqUv0fwJI0ThHaXkc21xCp+DOJr3we9AeqAAAAAAAAD5dS1ClbUp1q9SNOlBZlN9S8PF+BFmv8AHBJ5jYW6XWlWrZ+apJ/xYEt1Kiim5NRS623hL4mma/xm6fa5jTqO6qrPQo4cU/xVH0V8MkK6zwjvLx/71c1Ki7mdmmvBU44X5HlAbvwg4zr+5zGlJWlN9lJ/WteNV718MGlVJuTcpylOT65Sk5Sfi5Pey0AAAAAAAAAAAAAAAAAAAALoTcWpRlKMl1Si3GS90lvRaAN04P8AGZf2uI1Jq7prsrN8ol4Vet/HJJGgcaFhc4jVm7So/u1f6tvwqro/PBAYA6xpVYySlCSlF9Uk00/ii85d0fX7uzebW5qUvwppwfvhLMX8iQNA44KkWo31vGa/tqPRl73Te75Ne4CYgfFpGq0bujGvb1FUpSziS7GnhxkuxrqaPtAijj2vZKFnQTajKdWpJZ+04qMY5/1NkRG/8dN7ymoRprqo28V8ZNyf6GgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASvxFX72rq2b3YhVivHfGWP3SXTnfis1DkNVt8vo1eUov/FFuP70Y/M6IA5o4c3vL6leVM5X0icF7oYh/6nhF1Sbk3JvLlJtv2tvLf5loAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGazuXSqU6scp06kJrHXmMlL9Dqe0uFUpwqRfRnCMl7msnKRM3Anh3QpafbUq88VKcJQfujOUY/kkBqPNTqfct/P9I5qdT7lv5/pJ8AEB81Op9y38/wBI5qdT7lv5/pJ8AEB81Op9y38/0jmp1PuW/n+knwsrVNmMpNNqMW8JZbws4S7WBA3NTqfct/P9I5qdT7lv5/pJWlwoxOlPkavITt5TkvqXOk1WhT2ptVMY6W9LL8DLdcJklT5KhVqSnKn0fqliEq/It5lNLOV+a8cBEnNTqfct/P8ASOanU+5b+f6SVqXC2KX1ttXjJ3FzBQiqUm4Uqzpupum/DK685wmt59dPhFCUopULjZnXnSjUaoqDlGbhKWXUzjKx1ZfYmBD3NTqfct/P9I5qdT7lv5/pJZocKVsKVW2rwf10pJci1To06mw6ssVHuz2LL6Mt2C294UKLt5qnUjQqXFSntyjB8vilVceSxLKzKC3y2d3hvAijmp1PuW/n+kc1Op9y38/0k23mpKnKnDkqtSc1KWxDk8whHG1KTlJLC2l1Nv2Jnn/0optxjG3uZSnh04pUc1oPa6cG6iSXR+80963ARFzU6n3Lfz/SOanU+5b+f6SZdN1+lXpzqxhWhGFOFTpQTlOlOG3CcYwbbyuzr8C/V9QqUoUp06cZQnXt4TcpOLjCrVhTTjHG+XTW7d1P3MIX5qdT7lv5/pHNTqfct/P9JL9TUrjl5UfqaadOpOE5RqSjGMZpb3tRU21vaWNndnJit9WunG3lKFBxqyilFKoqlSMpvpxi29hRjsyeW85xu7QiXmp1PuW/n+kc1Op9y38/0kq3XCCvTpSlOnSpSjc1KcpN1KlKlCNHlIubik3J7o9iTfbuznhq11KcEqNL6yg5xpOclUp/VRkpVZdUY7TcMYzuz7UgiPmp1PuW/n+kc1Op9y38/wBJK8tWunSU4O32nXdKC5Oq43D2sKpB7a2Y42s/a+w2s7j0LG6ryuKtKcqU6dOEcyhTnCSqSeY0985J4isvq+1H4BDHNTqfct/P9I5qdT7lv5/pJ8AEB81Op9y38/0jmp1PuW/n+knwAQHzU6n3Lfz/AElearVO7Q8/0k9gAAAAAAFtSKaafU0097W5+KAA82Gg2yi48m2nGUW5VKspSUpqctqbk222k85zuLf6PW2Zvk5JzabarVk1ipyi2MS6C2t+FjrZUAXPQrfLahOLdSdTMa1eL2py2proyWIye9x6m97RfU0ehJRi4PZhVdRRVSoouo6nKNyipYmtrfh5XgABinwftnjNJvpzljla2HtyUpRa2sODaT2H0crqK/7AtnnNLKcpy2XUquCc4yjLZg5Yimpy3JJZeesoAMtbSKM9najNuLyny1ZSWUk47SlnZeysx6n2ott9Dt4T240ukpJpudR7GNrEYJyezHpS6Kwt/UUAH0WOnUqCxShsLk6UOuT6FOOzBb2+pFuo6bTuIxjV5RxjOM0oVq1PpRalFt05LOGk1nqaTAAwPQbZ8pmm3ykZxknUquOzN5moxcsQ2vvYxtduTJX0ilOtGu1UVSMVFOFxcQjsp52XTjJRaz2Nb+0AC2jolCKmsVJKpUjOSncXFRSnFrDxOb3blu6nhewsr8H7ec6s5KtmsmqijdXUYzTjsY2IzUVu3dW4ADNaaTSpbGyqj5NycOUrVqrhtRUXh1JPCwsY7MvHWz6be3jT2thY2pylLe23J9bbf/24qAMoAAAAAAAP/9k="
19 |
20 |
21 | const val MIN_TITLENOTE_LENGTH=3
22 | const val MAX_TITLENOTE_LENGTH=50
23 |
24 | const val MIN_SUBTITLE_LENGTH=3
25 | const val MAX_SUBTITLE_LENGTH=40
26 | const val SEARCH_TIME_DELAY= 500L
27 |
28 |
29 |
30 | private const val SECOND_MILLIS = 1000
31 | private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
32 | private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
33 | private const val DAY_MILLIS = 24 * HOUR_MILLIS
34 |
35 | fun getTimeAgo(time: Long, ctx: Context?): String? {
36 | var time = time
37 | if (time < 1000000000000L) {
38 | // if timestamp given in seconds, convert to millis
39 | time *= 1000
40 | }
41 | val now: Long = Date().time
42 | if (time > now || time <= 0) {
43 | return null
44 | }
45 |
46 | // TODO: localize
47 | val diff = now - time
48 | return if (diff < MINUTE_MILLIS) {
49 | "just now"
50 | } else if (diff < 2 * MINUTE_MILLIS) {
51 | "a minute ago"
52 | } else if (diff < 50 * MINUTE_MILLIS) {
53 | " ${diff / MINUTE_MILLIS} minutes ago"
54 | } else if (diff < 90 * MINUTE_MILLIS) {
55 | "an hour ago"
56 | } else if (diff < 24 * HOUR_MILLIS) {
57 | " ${diff / HOUR_MILLIS} hours ago"
58 | } else if (diff < 48 * HOUR_MILLIS) {
59 | "yesterday"
60 | } else {
61 | "${diff / DAY_MILLIS} days ago"
62 | }
63 | }
64 |
65 | private var suffixes: NavigableMap = TreeMap()
66 |
67 | fun init() {
68 | suffixes[1_000L] = "k"
69 | suffixes[1_000_000L] = "M"
70 | suffixes[1_000_000_000L] = "G"
71 | suffixes[1_000_000_000_000L] = "T"
72 | suffixes[1_000_000_000_000_000L] = "P"
73 | suffixes[1_000_000_000_000_000_000L] = "E"
74 | }
75 |
76 | fun format(value: Long): String {
77 | init()
78 | //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
79 | if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1)
80 | if (value < 0) return "-" + format(-value)
81 | if (value < 1000) return java.lang.Long.toString(value) //deal with easy case
82 | val e = suffixes.floorEntry(value)
83 | val divideBy = e.key
84 | val suffix = e.value
85 | val truncated = value / (divideBy / 10) //the number part of the output times 10
86 | val hasDecimal = truncated < 100 && truncated / 10.0 != (truncated / 10).toDouble()
87 | return if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix
88 | }
89 |
90 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/back_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/emai_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/lock_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/logout.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/user_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-hdpi/back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/emai_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-hdpi/emai_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/lock_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-hdpi/lock_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-hdpi/logout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/user_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-hdpi/user_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-mdpi/back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/emai_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-mdpi/emai_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_error.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_image.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/lock_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-mdpi/lock_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-mdpi/logout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/user_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-mdpi/user_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xhdpi/back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/emai_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xhdpi/emai_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/lock_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xhdpi/lock_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xhdpi/logout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/user_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xhdpi/user_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xxhdpi/back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/emai_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xxhdpi/emai_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_copy.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_done.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/lock_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xxhdpi/lock_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/logout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xxhdpi/logout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/user_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/drawable-xxhdpi/user_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_add_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_bottom_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_default_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
9 |
12 |
13 |
14 | -
20 |
22 |
26 |
27 |
28 |
29 | -
35 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_note2.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
9 |
12 |
13 |
14 | -
20 |
22 |
26 |
27 |
28 |
29 | -
35 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_note3.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
9 |
12 |
13 |
14 | -
20 |
22 |
26 |
27 |
28 |
29 | -
35 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_note4.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
9 |
12 |
13 |
14 | -
20 |
22 |
26 |
27 |
28 |
29 | -
35 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_note5.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
9 |
12 |
13 |
14 | -
20 |
22 |
26 |
27 |
28 |
29 | -
35 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_save_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/card_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_text_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_circle_outline.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_image.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_link.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_alert.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_delete_forever_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_web.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/font/brandon_medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/font/brandon_medium.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/israr_syria.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/font/israr_syria.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/poppins.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/font/poppins_bold.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/font/rta_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/font/rta_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/uber_move.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/font/uber_move.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/uber_move_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/font/uber_move_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_create_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
21 |
22 |
35 |
36 |
50 |
51 |
69 |
70 |
81 |
82 |
104 |
105 |
114 |
115 |
116 |
130 |
131 |
143 |
144 |
157 |
158 |
169 |
170 |
189 |
190 |
200 |
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
36 |
37 |
47 |
48 |
64 |
65 |
72 |
73 |
88 |
89 |
90 |
91 |
102 |
103 |
114 |
126 |
127 |
128 |
140 |
141 |
150 |
151 |
158 |
159 |
167 |
168 |
176 |
185 |
186 |
187 |
188 |
189 |
202 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_container_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
19 |
20 |
28 |
29 |
40 |
41 |
53 |
54 |
67 |
78 |
79 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_dialog_add_url.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
17 |
18 |
29 |
30 |
45 |
46 |
65 |
66 |
67 |
68 |
84 |
85 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_persistent_bottom_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
33 |
34 |
43 |
44 |
51 |
52 |
61 |
62 |
63 |
70 |
71 |
80 |
81 |
82 |
89 |
90 |
99 |
100 |
101 |
108 |
109 |
118 |
119 |
120 |
127 |
128 |
137 |
138 |
139 |
148 |
149 |
150 |
151 |
163 |
164 |
180 |
181 |
197 |
198 |
212 |
213 |
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/navigation/main_nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
17 |
20 |
21 |
26 |
29 |
32 |
33 |
38 |
41 |
44 |
45 |
50 |
53 |
56 |
57 |
62 |
65 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
11 | #292929
12 |
13 | #292929
14 |
15 | #FDBE3B
16 |
17 | #DBDBDB
18 |
19 | #7B7B7B
20 |
21 | #2F2D2E
22 |
23 | #A4A4A4
24 |
25 | #CECECE
26 |
27 | #333333
28 |
29 | #FAFAFA
30 |
31 | #1F1F1F
32 |
33 | #FDBE3B
34 |
35 | #2196F3
36 |
37 | #3A52Fc
38 |
39 | #000000
40 |
41 | #FF4842
42 |
43 | #333333
44 |
45 | #FFFFFFFF
46 |
47 |
48 |
49 | #ffffff
50 | #ffffff
51 | #ffffff
52 | #3BFFFFFF
53 | #BB86FC
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/font_certs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @array/com_google_android_gms_fonts_certs_dev
5 | - @array/com_google_android_gms_fonts_certs_prod
6 |
7 |
8 | -
9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
10 |
11 |
12 |
13 | -
14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/preloaded_fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @font/poppins
5 | - @font/poppins_bold
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | NoteAppKtorServer
3 |
4 | One Number Needed at Least
5 | Password should include 1Capital letter, 1 Number, and min 8 character, special character are not allowed
6 | Please , enter your password
7 | 1 Capital letter Needed At Least
8 | Password must > 8 characters
9 | Special characters are not allowed
10 | My Note
11 |
12 | Search notes
13 |
14 | Note Title
15 |
16 | Note Subtitle
17 |
18 | Type Note Here...
19 |
20 | Add Miscellaneous
21 |
22 |
23 |
24 |
25 | Pick Color
26 |
27 |
28 |
29 | Add Image
30 |
31 | Add URL
32 |
33 | Copy
34 |
35 | Delete Note
36 |
37 | Add Url
38 |
39 | Delete Note
40 | Successfully Deleted Note
41 |
42 | Delete Url
43 |
44 | Delete Image
45 |
46 | Are you sure you want to delete this note?
47 |
48 | Are you sure you want to delete this url?
49 |
50 | Are you sure you want to delete this image?
51 |
52 | Enter Url
53 |
54 | Cancel
55 |
56 | Add
57 |
58 | Confirm
59 | The title must not be empty
60 | The subtitle must not be empty
61 | Successfully Saved Note
62 | Permission denied
63 | The title can\'t have less than %d characters
64 |
65 | The title can\'t have more than %d characters
66 |
67 | The subtitle can\'t have less than %d characters
68 |
69 | The subtitle can\'t have more than %d characters
70 | [Permission]]]>
71 | Url must not empty
72 | Please, Enter a valid url
73 | Content note must be not empty
74 | Successfully Updated Note
75 | Successfully Copied Note
76 | No Notes
77 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
28 |
--------------------------------------------------------------------------------
/app/src/test/java/com/developers/noteappktorserver/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.developers.noteappktorserver
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:7.0.2"
9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
10 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5"
11 | classpath "com.google.dagger:hilt-android-gradle-plugin:2.39.1"
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | task clean(type: Delete) {
18 | delete rootProject.buildDir
19 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gamalragab21/NoteAppWithApiKtor/70c72cbd073439eae23437b25540981ab6901887/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 24 19:05:28 EET 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
3 | repositories {
4 | google()
5 | mavenCentral()
6 | maven { url 'https://jitpack.io' }
7 | jcenter() // Warning: this repository is going to shut down soon
8 | }
9 | }
10 | rootProject.name = "NoteAppKtorServer"
11 | include ':app'
12 |
--------------------------------------------------------------------------------