├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kluivert │ │ └── knote │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── ic_knote-playstore.png │ ├── ic_knote_icon-playstore.png │ ├── java │ │ └── com │ │ │ └── kluivert │ │ │ └── knote │ │ │ ├── Knote.kt │ │ │ ├── adapter │ │ │ ├── NoteAdapter.kt │ │ │ └── SlideAdapter.kt │ │ │ ├── data │ │ │ ├── dao │ │ │ │ └── NoteDao.kt │ │ │ ├── dtbase │ │ │ │ └── KnoteDatabase.kt │ │ │ ├── entities │ │ │ │ ├── Note.kt │ │ │ │ └── SlideModel.kt │ │ │ ├── repo │ │ │ │ └── NoteRepository.kt │ │ │ └── viewModel │ │ │ │ └── NoteViewModel.kt │ │ │ ├── di │ │ │ └── NoteModule.kt │ │ │ ├── ui │ │ │ └── activities │ │ │ │ ├── CreateNoteActivity.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── SlideActivity.kt │ │ │ └── utils │ │ │ ├── DividerItemDecoration.java │ │ │ ├── KnoteDiffUtil.kt │ │ │ ├── KnoteListener.kt │ │ │ ├── SnackExtension.kt │ │ │ └── ToastIt.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── add_image.png │ │ ├── background_delete.xml │ │ ├── bold.png │ │ ├── button_done_background.xml │ │ ├── button_slide_background.xml │ │ ├── calendar.png │ │ ├── color_layout.xml │ │ ├── color_layout1.xml │ │ ├── color_layout2.xml │ │ ├── color_layout3.xml │ │ ├── color_layout4.xml │ │ ├── dummypic.jpg │ │ ├── ic_arrow_back.xml │ │ ├── ic_cancel.xml │ │ ├── ic_delete.xml │ │ ├── ic_done.xml │ │ ├── ic_knote_background.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_layout_add.xml │ │ ├── ic_link.xml │ │ ├── ic_search.xml │ │ ├── ic_warning.xml │ │ ├── imgsearch.png │ │ ├── kletter.png │ │ ├── linear_grey_background.xml │ │ ├── microphone.png │ │ ├── moon.png │ │ ├── more.png │ │ ├── noteditors_background.xml │ │ ├── pencil.png │ │ ├── product.png │ │ ├── redmicro.png │ │ ├── slideone.png │ │ ├── slidethree.png │ │ ├── slidetwo.png │ │ ├── sun.png │ │ ├── tintdone.xml │ │ └── web.png │ │ ├── font │ │ └── poppins.xml │ │ ├── layout │ │ ├── activity_create_note.xml │ │ ├── activity_main.xml │ │ ├── activity_slide.xml │ │ ├── color_layout.xml │ │ ├── item_slide.xml │ │ ├── layout_note_editor.xml │ │ ├── layout_web.xml │ │ └── note_item.xml │ │ ├── menu │ │ └── note_item_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_knote_icon.xml │ │ └── ic_knote_icon_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_knote_icon.png │ │ ├── ic_knote_icon_background.png │ │ ├── ic_knote_icon_foreground.png │ │ └── ic_knote_icon_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_knote_icon.png │ │ ├── ic_knote_icon_background.png │ │ ├── ic_knote_icon_foreground.png │ │ └── ic_knote_icon_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_knote_icon.png │ │ ├── ic_knote_icon_background.png │ │ ├── ic_knote_icon_foreground.png │ │ └── ic_knote_icon_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_knote_icon.png │ │ ├── ic_knote_icon_background.png │ │ ├── ic_knote_icon_foreground.png │ │ └── ic_knote_icon_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_knote_icon.png │ │ ├── ic_knote_icon_background.png │ │ ├── ic_knote_icon_foreground.png │ │ └── ic_knote_icon_round.png │ │ ├── values-night │ │ ├── colors.xml │ │ └── strings.xml │ │ └── values │ │ ├── colors.xml │ │ ├── font_certs.xml │ │ ├── preloaded_fonts.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── kluivert │ └── knote │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── editnoteday.png ├── editnotenight.png ├── mainemptyscreen.png ├── notelistday.png ├── notelistnight.png ├── slideone.png ├── slidethree.png └── slidetwo.png └── 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 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kluivert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Knote 2 | 3 | 4 | 5 | Knote is a standard note taking app with Mvvm architecture 6 | 7 | 8 | 9 | ### Features 10 | 11 | - Adding an image to note 12 | - Using google text to speech for quick note reading 13 | - Recording voice notes 14 | - Adding web links 15 | - Using OCR for quick note taking 16 | 17 | ### Libraries and thirdparties 18 | 19 | - Room db 20 | - Coil 21 | - LiveData 22 | - Google mobile vision 23 | - Google text to speech 24 | - Koin 25 | - Coroutines 26 | 27 | 28 | 29 | Intro slide one | Intro slide two | Intro slide three | empty list 30 | --- | --- | --- | --- 31 | | | | 32 | 33 |

⚪⚫ Light and Dark themes


34 | 35 |

36 | 37 | 38 |

39 | 40 | 41 | 42 | 43 | 44 | 45 | ### Todos 46 | 47 | - Write More Tests 48 | - Improve Performance 49 | 50 | License 51 | ---- 52 | 53 | MIT 54 | 55 | 56 | **Free Software, Hell Yeah!** 57 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'androidx.navigation.safeargs.kotlin' 5 | apply plugin: 'kotlin-kapt' 6 | 7 | 8 | 9 | android { 10 | compileSdkVersion 29 11 | buildToolsVersion "29.0.3" 12 | 13 | defaultConfig { 14 | applicationId "com.kluivert.knote" 15 | minSdkVersion 22 16 | targetSdkVersion 29 17 | versionCode 1 18 | versionName "1.0" 19 | 20 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 21 | } 22 | 23 | buildFeatures { 24 | viewBinding true 25 | } 26 | 27 | 28 | buildTypes { 29 | release { 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | compileOptions{ 36 | sourceCompatibility JavaVersion.VERSION_1_8 37 | targetCompatibility JavaVersion.VERSION_1_8 38 | } 39 | kotlinOptions{ 40 | jvmTarget = JavaVersion.VERSION_1_8.toString() 41 | } 42 | 43 | 44 | } 45 | 46 | dependencies { 47 | 48 | def room_version = "2.2.5" 49 | def lifecycle_version = "2.2.0" 50 | def koin_version= "2.1.6" 51 | 52 | implementation fileTree(dir: "libs", include: ["*.jar"]) 53 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 54 | implementation 'androidx.core:core-ktx:1.3.1' 55 | implementation 'androidx.appcompat:appcompat:1.2.0' 56 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 57 | testImplementation 'junit:junit:4.13' 58 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 59 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 60 | 61 | 62 | //External dependencies 63 | 64 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 65 | implementation "androidx.viewpager2:viewpager2:1.0.0" 66 | implementation 'com.google.android.material:material:1.3.0-alpha02' 67 | implementation 'com.mikhaellopez:circularimageview:4.2.0' 68 | implementation "androidx.cardview:cardview:1.0.0" 69 | implementation("io.coil-kt:coil:0.11.0") 70 | implementation 'com.github.bumptech.glide:glide:4.11.0' 71 | annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' 72 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 73 | implementation 'com.github.zhpanvip:viewpagerindicator:1.0.4' 74 | implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0' 75 | implementation 'androidx.navigation:navigation-ui-ktx:2.3.0' 76 | implementation 'com.intuit.sdp:sdp-android:1.0.6' 77 | implementation 'com.intuit.ssp:ssp-android:1.0.6' 78 | implementation 'com.github.GrenderG:Toasty:1.4.2' 79 | implementation 'com.google.android.gms:play-services-vision:20.1.1' 80 | 81 | //DI 82 | implementation "org.koin:koin-android:$koin_version" 83 | 84 | // Koin AndroidX Scope feature 85 | implementation "org.koin:koin-androidx-scope:$koin_version" 86 | 87 | // Koin AndroidX ViewModel feature 88 | implementation "org.koin:koin-androidx-viewmodel:$koin_version" 89 | 90 | implementation "androidx.room:room-runtime:$room_version" 91 | kapt "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor 92 | 93 | // optional - Kotlin Extensions and Coroutines support for Room 94 | implementation "androidx.room:room-ktx:$room_version" 95 | implementation "androidx.room:room-testing:$room_version" 96 | 97 | // ViewModel 98 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" 99 | // LiveData 100 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" 101 | // Lifecycles only (without ViewModel or LiveData) 102 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" 103 | implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" 104 | 105 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72" 106 | api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8" 107 | api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8" 108 | 109 | 110 | } -------------------------------------------------------------------------------- /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/kluivert/knote/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote 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.kluivert.knote", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/ic_knote-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/ic_knote-playstore.png -------------------------------------------------------------------------------- /app/src/main/ic_knote_icon-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/ic_knote_icon-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/Knote.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote 2 | 3 | import android.app.Application 4 | import com.kluivert.knote.di.appModule 5 | import com.kluivert.knote.di.viewModelModule 6 | import kotlinx.coroutines.InternalCoroutinesApi 7 | import org.koin.android.ext.koin.androidContext 8 | import org.koin.core.context.startKoin 9 | 10 | 11 | class Knote : Application() { 12 | 13 | @InternalCoroutinesApi 14 | override fun onCreate() { 15 | super.onCreate() 16 | 17 | startKoin { 18 | androidContext(this@Knote) 19 | modules(listOf(appModule, viewModelModule)) 20 | } 21 | 22 | 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/adapter/NoteAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.adapter 2 | 3 | import android.graphics.Color 4 | import android.os.Looper 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.Filter 9 | import android.widget.Toast 10 | import androidx.appcompat.widget.PopupMenu 11 | import androidx.core.os.HandlerCompat.postDelayed 12 | import androidx.recyclerview.widget.DiffUtil 13 | import androidx.recyclerview.widget.RecyclerView 14 | import coil.api.load 15 | import com.google.android.gms.tasks.Task 16 | import com.kluivert.knote.R 17 | import com.kluivert.knote.data.entities.Note 18 | import com.kluivert.knote.data.viewModel.NoteViewModel 19 | import com.kluivert.knote.databinding.NoteItemBinding 20 | import com.kluivert.knote.ui.activities.MainActivity 21 | import com.kluivert.knote.utils.KnoteDiffUtil 22 | import com.kluivert.knote.utils.KnoteListener 23 | import es.dmoral.toasty.Toasty 24 | import kotlinx.android.synthetic.main.note_item.view.* 25 | import kotlinx.coroutines.GlobalScope 26 | import kotlinx.coroutines.InternalCoroutinesApi 27 | import kotlinx.coroutines.launch 28 | import org.koin.android.ext.android.inject 29 | import org.koin.java.KoinJavaComponent.inject 30 | import java.io.File 31 | import java.sql.Time 32 | import java.util.* 33 | import java.util.logging.Handler 34 | import kotlin.collections.ArrayList 35 | import kotlin.coroutines.coroutineContext 36 | 37 | 38 | class NoteAdapter( 39 | 40 | var noteList: MutableList = mutableListOf(), 41 | var listener: KnoteListener, 42 | var noteSource: MutableList = mutableListOf() 43 | 44 | ) : RecyclerView.Adapter() { 45 | 46 | 47 | fun updateListItems(newList: MutableList) { 48 | 49 | val diffCallback = KnoteDiffUtil(noteList, newList) 50 | val diffResult = DiffUtil.calculateDiff(diffCallback) 51 | 52 | noteList.clear() 53 | noteList.addAll(newList) 54 | 55 | diffResult.dispatchUpdatesTo(this) 56 | } 57 | 58 | inner class NoteAdapterViewHolder(itemView : NoteItemBinding):RecyclerView.ViewHolder(itemView.root) 59 | 60 | 61 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteAdapterViewHolder { 62 | val view : NoteItemBinding = NoteItemBinding.inflate(LayoutInflater.from(parent.context),parent,false) 63 | return NoteAdapterViewHolder(view) 64 | 65 | } 66 | 67 | override fun getItemCount(): Int { 68 | return noteList.size 69 | } 70 | 71 | 72 | override fun onBindViewHolder(holder: NoteAdapterViewHolder, position: Int) { 73 | 74 | 75 | holder.itemView.apply { 76 | val current = noteList[position] 77 | tvTitleItem.text = current.noteTitle 78 | tvTitleItem.setTextColor(Color.parseColor(current.color)) 79 | tvDescItem.text = current.noteContent 80 | 81 | if (current.noteImage.isBlank()){ 82 | imgContentItem.visibility = View.GONE 83 | } 84 | 85 | imgContentItem.load(File(current.noteImage)) 86 | imgContentItem.visibility = View.VISIBLE 87 | 88 | tvOptionMore.setOnClickListener { 89 | 90 | val popupMenu = PopupMenu(context,tvOptionMore) 91 | popupMenu.menuInflater.inflate(R.menu.note_item_menu,popupMenu.menu) 92 | popupMenu.setOnMenuItemClickListener { item -> 93 | when(item.itemId) { 94 | R.id.miEdit -> listener.editlistener( 95 | noteList[position],position 96 | ) 97 | 98 | R.id.miDelete -> 99 | GlobalScope.launch { listener.deleteListener(noteList[position],position)} 100 | R.id.miShare -> 101 | Toasty.success(context,"Developer will work on this feature soon",Toast.LENGTH_SHORT,true).show() 102 | } 103 | true 104 | } 105 | popupMenu.show() 106 | 107 | } 108 | 109 | noteItem.setOnClickListener { 110 | listener.listener(noteList[position],position) 111 | } 112 | 113 | setOnItemClickListener { 114 | onClickItemListener?.let { it(current) } 115 | 116 | } 117 | 118 | } 119 | 120 | 121 | } 122 | 123 | 124 | fun filterList(filteredCourseList: ArrayList) { 125 | this.noteList = filteredCourseList 126 | notifyDataSetChanged(); 127 | } 128 | 129 | fun setData(noteModel : MutableList, pos : Int){ 130 | this.noteList = noteModel 131 | notifyItemInserted(pos) 132 | } 133 | 134 | 135 | private var onClickItemListener: ((Note) ->Unit)? = null 136 | fun setOnItemClickListener(listener : (Note) ->Unit){ 137 | onClickItemListener = listener 138 | } 139 | 140 | /*fun deleteNote( search : String){ 141 | val timer : Timer 142 | 143 | timer = object : Timer() { 144 | fun run() { 145 | if (search.trim().isEmpty()){ 146 | noteList = noteSource 147 | }else { 148 | val temp: ArrayList = arrayListOf() 149 | 150 | for (i in temp) { 151 | if (i.noteTitle.toLowerCase(Locale.ROOT) 152 | .contains(search.toLowerCase(Locale.ROOT)) || 153 | i.noteContent.toLowerCase(Locale.ROOT) 154 | .contains(search.toLowerCase(Locale.ROOT)) 155 | ) { 156 | temp.add(i) 157 | 158 | } 159 | } 160 | noteList = temp 161 | } 162 | 163 | } 164 | 165 | } 166 | 167 | }*/ 168 | 169 | 170 | 171 | } 172 | -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/adapter/SlideAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.adapter 2 | 3 | import android.transition.Slide 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.recyclerview.widget.DiffUtil 8 | import androidx.recyclerview.widget.RecyclerView 9 | import com.kluivert.knote.R 10 | import com.kluivert.knote.data.entities.SlideModel 11 | import kotlinx.android.synthetic.main.item_slide.view.* 12 | import java.util.zip.Inflater 13 | 14 | class SlideAdapter( 15 | private var slides : List 16 | 17 | ) : RecyclerView.Adapter(){ 18 | 19 | 20 | 21 | inner class SlideAdapterViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) 22 | 23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SlideAdapterViewHolder { 24 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_slide,parent,false) 25 | return SlideAdapterViewHolder(view) 26 | } 27 | 28 | override fun getItemCount(): Int { 29 | return slides.size 30 | } 31 | 32 | override fun onBindViewHolder(holder: SlideAdapterViewHolder, position: Int) { 33 | 34 | holder.itemView.apply { 35 | val current = slides[position] 36 | tvSlideTitle.text = current.slidetitle 37 | tvSlideDesc.text = current.slidedesc 38 | imgSlide.setImageResource(current.slideimage) 39 | 40 | } 41 | 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/dao/NoteDao.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.room.* 5 | import com.kluivert.knote.data.entities.Note 6 | 7 | @Dao 8 | interface NoteDao { 9 | 10 | @Insert(onConflict = OnConflictStrategy.REPLACE) 11 | suspend fun addNote(note : Note) 12 | 13 | @Query("SELECT * FROM knote_table ORDER BY id DESC") 14 | fun readNote() : LiveData> 15 | 16 | @Delete 17 | suspend fun deleteNote(note: Note) 18 | 19 | @Update 20 | suspend fun updateNote(note: Note) 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/dtbase/KnoteDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.dtbase 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import com.kluivert.knote.data.dao.NoteDao 8 | import com.kluivert.knote.data.entities.Note 9 | import kotlinx.coroutines.InternalCoroutinesApi 10 | import kotlinx.coroutines.internal.synchronized 11 | 12 | @InternalCoroutinesApi 13 | @Database(entities = [Note::class], version = 1, exportSchema = false) 14 | abstract class KnoteDatabase : RoomDatabase() { 15 | 16 | abstract fun noteDao() : NoteDao 17 | 18 | companion object{ 19 | 20 | @Volatile 21 | private var INSTANCE : KnoteDatabase? = null 22 | 23 | 24 | fun getDatabase(context: Context) : KnoteDatabase { 25 | val tempInst = 26 | INSTANCE 27 | 28 | if(tempInst != null){ 29 | return tempInst 30 | } 31 | 32 | synchronized(this){ 33 | var instance = Room.databaseBuilder(context.applicationContext, 34 | KnoteDatabase::class.java, 35 | "knote_database" 36 | ).build() 37 | INSTANCE = instance 38 | return instance 39 | 40 | } 41 | 42 | 43 | } 44 | 45 | 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/entities/Note.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.entities 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import java.io.Serializable 7 | 8 | @Entity(tableName = "knote_table") 9 | data class Note( 10 | @PrimaryKey(autoGenerate = true) 11 | var id : Int, 12 | 13 | @ColumnInfo(name = "title") 14 | val noteTitle : String, 15 | 16 | @ColumnInfo(name = "note_content") 17 | val noteContent : String, 18 | 19 | @ColumnInfo(name = "note_image") 20 | val noteImage : String, 21 | 22 | @ColumnInfo(name = "web_link") 23 | val webLink : String, 24 | 25 | @ColumnInfo(name = "color") 26 | val color : String, 27 | 28 | @ColumnInfo(name = "date_time") 29 | val dateTime : String 30 | 31 | ):Serializable -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/entities/SlideModel.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.entities 2 | 3 | data class SlideModel( 4 | val slideimage : Int, 5 | var slidetitle : String, 6 | var slidedesc : String 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/repo/NoteRepository.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.repo 2 | 3 | import androidx.lifecycle.LiveData 4 | import com.kluivert.knote.data.dao.NoteDao 5 | import com.kluivert.knote.data.entities.Note 6 | 7 | class NoteRepository(var noteDao: NoteDao) { 8 | 9 | val readNote : LiveData> = noteDao.readNote() 10 | 11 | suspend fun addNote(note: Note){ 12 | noteDao.addNote(note) 13 | } 14 | 15 | suspend fun deleteNote(note: Note){ 16 | noteDao.deleteNote(note) 17 | } 18 | 19 | suspend fun updateNote(note: Note){ 20 | noteDao.updateNote(note) 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/data/viewModel/NoteViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.data.viewModel 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.LiveData 5 | import androidx.lifecycle.ViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import com.kluivert.knote.data.dtbase.KnoteDatabase 8 | import com.kluivert.knote.data.entities.Note 9 | import com.kluivert.knote.data.repo.NoteRepository 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.InternalCoroutinesApi 12 | import kotlinx.coroutines.launch 13 | 14 | @InternalCoroutinesApi 15 | class NoteViewModel(context: Context) : ViewModel(){ 16 | 17 | val readNote : LiveData> 18 | var noteRepo : NoteRepository 19 | 20 | init { 21 | 22 | val noteDao = KnoteDatabase.getDatabase(context.applicationContext).noteDao() 23 | noteRepo = NoteRepository(noteDao) 24 | readNote = noteDao.readNote() 25 | 26 | } 27 | 28 | fun addNote(note: Note) { 29 | viewModelScope.launch (Dispatchers.IO){ 30 | noteRepo.addNote(note) 31 | } 32 | } 33 | 34 | 35 | fun updateNote(note: Note){ 36 | viewModelScope.launch (Dispatchers.IO){ 37 | noteRepo.updateNote(note) 38 | 39 | } 40 | } 41 | 42 | fun deleteNote(note: Note){ 43 | viewModelScope.launch(Dispatchers.IO) { 44 | noteRepo.deleteNote(note) 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/di/NoteModule.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.di 2 | 3 | import com.kluivert.knote.data.repo.NoteRepository 4 | import com.kluivert.knote.data.viewModel.NoteViewModel 5 | import kotlinx.coroutines.InternalCoroutinesApi 6 | import org.koin.androidx.viewmodel.dsl.viewModel 7 | import org.koin.dsl.module 8 | 9 | val appModule = module { 10 | 11 | single { NoteRepository(get()) } 12 | 13 | } 14 | 15 | @InternalCoroutinesApi 16 | val viewModelModule = module { 17 | 18 | viewModel { NoteViewModel(get()) } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/ui/activities/CreateNoteActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.ui.activities 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.app.Dialog 6 | import android.content.ContentResolver 7 | import android.content.DialogInterface 8 | import android.content.Intent 9 | import android.content.pm.PackageManager 10 | import android.content.res.ColorStateList 11 | import android.database.Cursor 12 | import android.graphics.* 13 | import android.graphics.drawable.BitmapDrawable 14 | import android.graphics.drawable.GradientDrawable 15 | import android.media.Image 16 | import android.net.Uri 17 | import android.os.Build 18 | import android.os.Bundle 19 | import android.provider.MediaStore 20 | import android.speech.tts.TextToSpeech 21 | import android.text.TextUtils 22 | import android.util.Patterns 23 | import android.view.LayoutInflater 24 | import android.view.View 25 | import android.widget.EditText 26 | import android.widget.ImageView 27 | import android.widget.TextView 28 | import android.widget.Toast 29 | import androidx.annotation.RequiresApi 30 | import androidx.appcompat.app.AlertDialog 31 | import androidx.appcompat.app.AppCompatActivity 32 | import androidx.appcompat.app.AppCompatDelegate 33 | import androidx.cardview.widget.CardView 34 | import androidx.constraintlayout.widget.ConstraintLayout 35 | import androidx.core.app.ActivityCompat 36 | import androidx.core.content.ContextCompat 37 | import androidx.core.content.withStyledAttributes 38 | import androidx.core.graphics.toColor 39 | import androidx.lifecycle.ViewModelProvider 40 | import com.google.android.gms.vision.Frame 41 | import com.google.android.gms.vision.text.TextRecognizer 42 | import com.google.android.material.bottomsheet.BottomSheetBehavior 43 | import com.kluivert.knote.R 44 | import com.kluivert.knote.data.entities.Note 45 | import com.kluivert.knote.data.viewModel.NoteViewModel 46 | import com.kluivert.knote.databinding.ActivityCreateNoteBinding 47 | import es.dmoral.toasty.Toasty 48 | import kotlinx.android.synthetic.main.activity_create_note.* 49 | import kotlinx.android.synthetic.main.activity_main.* 50 | import kotlinx.android.synthetic.main.color_layout.* 51 | import kotlinx.android.synthetic.main.color_layout.view.* 52 | import kotlinx.android.synthetic.main.color_layout.view.colorDefault 53 | import kotlinx.android.synthetic.main.layout_web.view.* 54 | import kotlinx.coroutines.InternalCoroutinesApi 55 | import org.koin.android.ext.android.get 56 | import org.koin.android.ext.android.inject 57 | import java.io.InputStream 58 | import java.lang.Exception 59 | import java.text.SimpleDateFormat 60 | import java.util.* 61 | import java.util.jar.Manifest 62 | import java.util.regex.Pattern 63 | 64 | @InternalCoroutinesApi 65 | class CreateNoteActivity : AppCompatActivity(), TextToSpeech.OnInitListener { 66 | 67 | private lateinit var createNoteBinding: ActivityCreateNoteBinding 68 | 69 | 70 | @RequiresApi(Build.VERSION_CODES.M) 71 | private var selectedColor: String = "#ef5059" 72 | private var REQUEST_IMAGE_CODE_PERMISSION = 1 73 | private var REQUEST_CODE_SELECT_IMAGE = 2 74 | private var REQUEST_CODE_SELECT_IMAGE_SEARCH = 3 75 | private var selectedImagePath: String = "" 76 | private var strurl: String = "" 77 | private var tts: TextToSpeech? = null 78 | 79 | private val noteViewModel by inject() 80 | 81 | private var alreadyAvailable: Note? = null 82 | 83 | 84 | @SuppressLint("ResourceAsColor", "CommitPrefEdits") 85 | @RequiresApi(Build.VERSION_CODES.M) 86 | override fun onCreate(savedInstanceState: Bundle?) { 87 | super.onCreate(savedInstanceState) 88 | createNoteBinding = ActivityCreateNoteBinding.inflate(layoutInflater) 89 | val createview = createNoteBinding.root 90 | setContentView(createview) 91 | 92 | tts = TextToSpeech(this, this) 93 | val darkModePrefs = getSharedPreferences(getString(R.string.app_name), 0) 94 | val editor = darkModePrefs.edit() 95 | val isNightModeOn: Boolean = darkModePrefs.getBoolean("NightMode", false) 96 | 97 | if (isNightModeOn) { 98 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 99 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE 100 | 101 | } else { 102 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 103 | 104 | 105 | } 106 | 107 | createNoteBinding.layoutList.findViewById(R.id.layoutList) 108 | 109 | noteEditor() 110 | 111 | createNoteBinding.tvDateTime.setText( 112 | SimpleDateFormat( 113 | "EEEE, dd MMMMM yyyy HH:mm a", 114 | Locale.getDefault() 115 | ).format(Date()) 116 | ) 117 | 118 | 119 | 120 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 121 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 122 | } 123 | 124 | if (intent.getBooleanExtra("isViewOrUpdate", false)) { 125 | alreadyAvailable = intent.getSerializableExtra("knote") as Note? 126 | viewOrUpdate() 127 | } 128 | 129 | createNoteBinding.imgBtnBack.setOnClickListener { 130 | onBackPressed() 131 | } 132 | 133 | 134 | 135 | 136 | createNoteBinding.imgRemoveWeb.setOnClickListener { 137 | createNoteBinding.tvUrl.text = null 138 | createNoteBinding.linlayoutWeb.visibility = View.GONE 139 | } 140 | 141 | createNoteBinding.imgRemoveImage.setOnClickListener { 142 | createNoteBinding.imgNote.setImageBitmap(null) 143 | createNoteBinding.imgNote.visibility = View.GONE 144 | createNoteBinding.imgRemoveImage.visibility = View.GONE 145 | selectedImagePath = "" 146 | } 147 | 148 | 149 | createNoteBinding.imgDone.setOnClickListener { 150 | 151 | val title = createNoteBinding.edTitle.text.toString().trim() 152 | val message = createNoteBinding.edNoteContent.text.toString().trim() 153 | 154 | 155 | 156 | if (createNoteBinding.linlayoutWeb.visibility == View.VISIBLE) { 157 | createNoteBinding.tvUrl.text = strurl 158 | } 159 | 160 | val note = Note( 161 | 0, 162 | title, 163 | message, 164 | selectedImagePath, 165 | strurl, 166 | selectedColor, 167 | tvDateTime.text.toString() 168 | ) 169 | 170 | if (alreadyAvailable != null) { 171 | note.id = alreadyAvailable!!.id 172 | } 173 | 174 | if (inputChecker(title, message)) { 175 | 176 | noteViewModel.addNote(note) 177 | Intent().apply { 178 | setResult(Activity.RESULT_OK, this) 179 | finish() 180 | } 181 | Toasty.success(this, "Saved", Toast.LENGTH_SHORT, true).show() 182 | 183 | } else { 184 | 185 | Toasty.error(this, "Enter details", Toast.LENGTH_SHORT, true).show() 186 | 187 | } 188 | } 189 | 190 | 191 | } 192 | 193 | private fun viewOrUpdate() { 194 | 195 | createNoteBinding.edTitle.setText(alreadyAvailable!!.noteTitle) 196 | createNoteBinding.edNoteContent.setText(alreadyAvailable!!.noteContent) 197 | createNoteBinding.tvUrl.text = alreadyAvailable!!.webLink 198 | createNoteBinding.tvDateTime.text = alreadyAvailable!!.dateTime 199 | createNoteBinding.edTitle.setTextColor(Color.parseColor(alreadyAvailable!!.color)) 200 | 201 | 202 | if (alreadyAvailable!!.noteImage.trim().isNotEmpty()) { 203 | createNoteBinding.imgNote.setImageBitmap(BitmapFactory.decodeFile(alreadyAvailable!!.noteImage)) 204 | createNoteBinding.imgNote.visibility = View.VISIBLE 205 | selectedImagePath = alreadyAvailable!!.noteImage 206 | createNoteBinding.imgRemoveImage.visibility = View.VISIBLE 207 | } 208 | 209 | if (alreadyAvailable!!.webLink.trim().isNotEmpty()) { 210 | createNoteBinding.tvUrl.text = alreadyAvailable!!.webLink 211 | createNoteBinding.linlayoutWeb.visibility = View.VISIBLE 212 | 213 | } 214 | 215 | 216 | } 217 | 218 | private fun inputChecker(title: String, noteContent: String): Boolean { 219 | return !(TextUtils.isEmpty(title) && TextUtils.isEmpty(noteContent)) 220 | } 221 | 222 | 223 | @SuppressLint("ResourceAsColor") 224 | @RequiresApi(Build.VERSION_CODES.M) 225 | private fun noteEditor() { 226 | val cardLayout: CardView = findViewById(R.id.layoutEditTools) 227 | val bottomSheetBehavior: BottomSheetBehavior = 228 | BottomSheetBehavior.from(cardLayout) 229 | cardLayout.findViewById(R.id.tvEditTools).setOnClickListener { 230 | if (bottomSheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED) { 231 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED 232 | } else { 233 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 234 | } 235 | } 236 | 237 | val imageColor = cardLayout.findViewById(R.id.colorDefault) 238 | val imageColor1 = cardLayout.findViewById(R.id.colorBlue) 239 | val imageColor2 = cardLayout.findViewById(R.id.colorYellow) 240 | val imageColor3 = cardLayout.findViewById(R.id.colorGreen) 241 | val imageColor4 = cardLayout.findViewById(R.id.colorPink) 242 | 243 | cardLayout.findViewById(R.id.viewColor).setOnClickListener { 244 | selectedColor = "#ef5059" 245 | createNoteBinding.edTitle.setTextColor(Color.parseColor(selectedColor)) 246 | imageColor.setImageResource(R.drawable.tintdone) 247 | imageColor1.setImageResource(0) 248 | imageColor2.setImageResource(0) 249 | imageColor3.setImageResource(0) 250 | imageColor4.setImageResource(0) 251 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 252 | 253 | } 254 | 255 | cardLayout.findViewById(R.id.viewColor1).setOnClickListener { 256 | selectedColor = "#2196F3" 257 | createNoteBinding.edTitle.setTextColor(Color.parseColor(selectedColor)) 258 | imageColor1.setImageResource(R.drawable.tintdone) 259 | imageColor.setImageResource(0) 260 | imageColor2.setImageResource(0) 261 | imageColor3.setImageResource(0) 262 | imageColor4.setImageResource(0) 263 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 264 | 265 | } 266 | 267 | cardLayout.findViewById(R.id.viewColor2).setOnClickListener { 268 | selectedColor = "#FFC107" 269 | createNoteBinding.edTitle.setTextColor(Color.parseColor(selectedColor)) 270 | imageColor2.setImageResource(R.drawable.tintdone) 271 | imageColor1.setImageResource(0) 272 | imageColor.setImageResource(0) 273 | imageColor3.setImageResource(0) 274 | imageColor4.setImageResource(0) 275 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 276 | 277 | } 278 | 279 | cardLayout.findViewById(R.id.viewColor3).setOnClickListener { 280 | selectedColor = "#4CAF50" 281 | createNoteBinding.edTitle.setTextColor(Color.parseColor(selectedColor)) 282 | imageColor3.setImageResource(R.drawable.tintdone) 283 | imageColor1.setImageResource(0) 284 | imageColor2.setImageResource(0) 285 | imageColor.setImageResource(0) 286 | imageColor4.setImageResource(0) 287 | 288 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 289 | } 290 | 291 | cardLayout.findViewById(R.id.viewColor4).setOnClickListener { 292 | selectedColor = "#E91E63" 293 | createNoteBinding.edTitle.setTextColor(Color.parseColor(selectedColor)) 294 | imageColor4.setImageResource(R.drawable.tintdone) 295 | imageColor.setImageResource(0) 296 | imageColor1.setImageResource(0) 297 | imageColor3.setImageResource(0) 298 | imageColor2.setImageResource(0) 299 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 300 | 301 | } 302 | 303 | 304 | if (alreadyAvailable != null && alreadyAvailable!!.color.trim().isNotEmpty()) { 305 | 306 | val sel = "#2196F3" 307 | if (Color.parseColor(alreadyAvailable!!.color).toString() == sel) { 308 | cardLayout.findViewById(R.id.viewColor1).performClick() 309 | } 310 | 311 | 312 | } 313 | 314 | cardLayout.findViewById(R.id.imgTextSpeech).setOnClickListener { 315 | cardLayout.findViewById(R.id.imgTextSpeech).setImageResource(R.drawable.redmicro) 316 | speakOut() 317 | 318 | } 319 | 320 | 321 | cardLayout.findViewById(R.id.imgInsert).setOnClickListener { 322 | 323 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 324 | if (ActivityCompat.checkSelfPermission( 325 | this, android.Manifest.permission.READ_EXTERNAL_STORAGE 326 | ) != PackageManager.PERMISSION_GRANTED 327 | ) { 328 | ActivityCompat.requestPermissions( 329 | this@CreateNoteActivity, 330 | arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 331 | REQUEST_IMAGE_CODE_PERMISSION 332 | ) 333 | } else { 334 | pickImage() 335 | } 336 | 337 | 338 | } 339 | 340 | cardLayout.findViewById(R.id.imgSearch).setOnClickListener { 341 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 342 | if (ActivityCompat.checkSelfPermission( 343 | this, android.Manifest.permission.READ_EXTERNAL_STORAGE 344 | ) != PackageManager.PERMISSION_GRANTED 345 | ) { 346 | ActivityCompat.requestPermissions( 347 | this@CreateNoteActivity, 348 | arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 349 | REQUEST_IMAGE_CODE_PERMISSION 350 | ) 351 | } else { 352 | pickImageSearch() 353 | } 354 | 355 | } 356 | 357 | 358 | cardLayout.findViewById(R.id.imgLink).setOnClickListener { 359 | bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED 360 | 361 | val mDialogView = LayoutInflater.from(this).inflate(R.layout.layout_web, null) 362 | 363 | val mBuilder = AlertDialog.Builder(this) 364 | .setView(mDialogView) 365 | val mAlertDialog = mBuilder.show() 366 | 367 | mDialogView.tvAddLink.setOnClickListener { 368 | val url = mDialogView.findViewById(R.id.edWeb) 369 | url.requestFocus() 370 | if (url.text.toString().trim().isEmpty()) { 371 | Toasty.warning(this, "Please enter url", Toast.LENGTH_SHORT, true).show() 372 | } else if (!Patterns.WEB_URL.matcher(url.text.toString()).matches()) { 373 | Toasty.warning(this, "Please enter correct url", Toast.LENGTH_SHORT, true) 374 | .show() 375 | } else { 376 | strurl = url.text.toString() 377 | createNoteBinding.tvUrl.text = strurl 378 | createNoteBinding.linlayoutWeb.visibility = View.VISIBLE 379 | mAlertDialog.dismiss() 380 | } 381 | 382 | 383 | } 384 | //cancel button click of custom layout 385 | mDialogView.tvCancel.setOnClickListener { 386 | 387 | mAlertDialog.dismiss() 388 | } 389 | 390 | } 391 | 392 | 393 | } 394 | 395 | 396 | @RequiresApi(Build.VERSION_CODES.M) 397 | 398 | override fun onBackPressed() { 399 | // super.onBackPressed() 400 | onBackPressedDialog() 401 | 402 | } 403 | 404 | fun pickImage() { 405 | 406 | Intent(Intent.ACTION_GET_CONTENT).also { 407 | it.type = "image/*" 408 | startActivityForResult(it, REQUEST_CODE_SELECT_IMAGE) 409 | } 410 | } 411 | 412 | fun pickImageSearch() { 413 | 414 | Intent(Intent.ACTION_GET_CONTENT).also { 415 | it.type = "image/*" 416 | startActivityForResult(it, REQUEST_CODE_SELECT_IMAGE_SEARCH) 417 | } 418 | } 419 | 420 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 421 | super.onActivityResult(requestCode, resultCode, data) 422 | if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_SELECT_IMAGE) { 423 | 424 | if (data != null) { 425 | val imageuri = data.data 426 | 427 | 428 | if (imageuri != null) { 429 | 430 | try { 431 | 432 | val inputStream: InputStream? = contentResolver.openInputStream(imageuri) 433 | val bitmap: Bitmap? = BitmapFactory.decodeStream(inputStream) 434 | createNoteBinding.imgNote.setImageBitmap(bitmap) 435 | createNoteBinding.imgNote.visibility = View.VISIBLE 436 | selectedImagePath = getImagePath(imageuri) 437 | createNoteBinding.imgRemoveImage.visibility = View.VISIBLE 438 | 439 | 440 | 441 | 442 | } catch (exception: Exception) { 443 | val message = exception.message.toString() 444 | Toasty.warning(this, message, Toast.LENGTH_SHORT, true).show() 445 | } 446 | } 447 | } 448 | 449 | 450 | }else if(resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_SELECT_IMAGE_SEARCH){ 451 | if (data != null){ 452 | val imageuri1 = data.data 453 | 454 | if (imageuri1 != null) { 455 | 456 | try { 457 | 458 | //ocr 459 | val inputStream1: InputStream? = contentResolver.openInputStream(imageuri1) 460 | val bitmap1: Bitmap? = BitmapFactory.decodeStream(inputStream1) 461 | createNoteBinding.imgNoteSearch.setImageBitmap(bitmap1) 462 | imgTextExtract() 463 | 464 | } catch (exception: Exception) { 465 | val message = exception.message.toString() 466 | Toasty.warning(this, message, Toast.LENGTH_SHORT, true).show() 467 | } 468 | } 469 | } 470 | 471 | 472 | } 473 | 474 | } 475 | 476 | fun imgTextExtract() { 477 | val bitmapDrawable = createNoteBinding.imgNoteSearch.drawable as BitmapDrawable 478 | val bitmaptext = bitmapDrawable.bitmap 479 | val recognizer = TextRecognizer.Builder(applicationContext).build() 480 | 481 | if (!recognizer.isOperational) { 482 | Toasty.error(this,"Error ",Toast.LENGTH_SHORT,true).show() 483 | } else { 484 | val frame = Frame.Builder().setBitmap(bitmaptext).build() 485 | val items = recognizer.detect(frame) 486 | val sb = StringBuilder() 487 | 488 | for (i in 0 until items.size()) { 489 | val myItem = items.valueAt(i) 490 | sb.append(myItem.value) 491 | //sb.append("\n") 492 | 493 | } 494 | createNoteBinding.edNoteContent.setText(sb).toString() 495 | } 496 | 497 | } 498 | 499 | fun getImagePath(uri: Uri): String { 500 | 501 | val filePath: String 502 | val cursor: Cursor? = contentResolver 503 | .query(uri, null, null, null, null) 504 | if (cursor == null) { 505 | filePath = uri.path.toString() 506 | } else { 507 | cursor.moveToFirst() 508 | val index = cursor.getColumnIndex("_data") 509 | filePath = cursor.getString(index) 510 | cursor.close() 511 | } 512 | return filePath 513 | 514 | } 515 | 516 | override fun onRequestPermissionsResult( 517 | requestCode: Int, 518 | permissions: Array, 519 | grantResults: IntArray 520 | ) { 521 | super.onRequestPermissionsResult(requestCode, permissions, grantResults) 522 | 523 | if (requestCode == REQUEST_IMAGE_CODE_PERMISSION && grantResults.isNotEmpty()) { 524 | if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 525 | pickImage() 526 | } else { 527 | Toasty.warning(this, "Permission denied", Toast.LENGTH_SHORT, true).show() 528 | } 529 | 530 | } 531 | 532 | } 533 | 534 | private fun onBackPressedDialog() { 535 | val alert = AlertDialog.Builder(this) 536 | .setTitle("Exit the note") 537 | .setMessage("Do you want to exit the note?") 538 | .setIcon(R.drawable.ic_warning) 539 | .setPositiveButton("Yes") { _, _ -> 540 | Intent().apply { 541 | setResult(Activity.RESULT_OK, this) 542 | finish() 543 | } 544 | } 545 | .setNegativeButton("No") { _, _ -> 546 | 547 | }.create() 548 | alert.show() 549 | 550 | } 551 | 552 | override fun onInit(status: Int) { 553 | 554 | if (status == TextToSpeech.SUCCESS) { 555 | 556 | val result = tts!!.setLanguage(Locale.US) 557 | 558 | if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { 559 | 560 | } else { 561 | val cardLayout: CardView = findViewById(R.id.layoutEditTools) 562 | val bottomSheetBehavior: BottomSheetBehavior = 563 | BottomSheetBehavior.from(cardLayout) 564 | cardLayout.findViewById(R.id.imgTextSpeech).isEnabled = true 565 | } 566 | 567 | } else { 568 | 569 | } 570 | 571 | 572 | } 573 | 574 | private fun speakOut() { 575 | val text = createNoteBinding.edNoteContent.text.toString() 576 | if (text.isEmpty()){ 577 | Toasty.error(this,"No texts", Toast.LENGTH_SHORT,true).show() 578 | } 579 | tts!!.speak(text, TextToSpeech.QUEUE_FLUSH, null,"") 580 | } 581 | 582 | public override fun onDestroy() { 583 | 584 | if (tts != null) { 585 | tts!!.stop() 586 | tts!!.shutdown() 587 | } 588 | super.onDestroy() 589 | } 590 | 591 | 592 | } 593 | -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/ui/activities/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.ui.activities 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.os.Build 6 | import android.os.Bundle 7 | import android.text.Editable 8 | import android.text.TextWatcher 9 | import android.view.View 10 | import android.widget.Toast 11 | import androidx.annotation.RequiresApi 12 | import androidx.appcompat.app.AppCompatActivity 13 | import androidx.appcompat.app.AppCompatDelegate 14 | import androidx.constraintlayout.widget.ConstraintLayout 15 | import androidx.lifecycle.Observer 16 | import androidx.recyclerview.widget.LinearLayoutManager 17 | import com.kluivert.knote.R 18 | import com.kluivert.knote.adapter.NoteAdapter 19 | import com.kluivert.knote.data.entities.Note 20 | import com.kluivert.knote.data.viewModel.NoteViewModel 21 | import com.kluivert.knote.databinding.ActivityMainBinding 22 | import com.kluivert.knote.utils.DividerItemDecoration 23 | import com.kluivert.knote.utils.KnoteListener 24 | import es.dmoral.toasty.Toasty 25 | import kotlinx.android.synthetic.main.activity_main.* 26 | import kotlinx.coroutines.InternalCoroutinesApi 27 | import org.koin.android.ext.android.inject 28 | import java.text.SimpleDateFormat 29 | import java.util.* 30 | import kotlin.collections.ArrayList 31 | 32 | 33 | @InternalCoroutinesApi 34 | 35 | const val ADD_NOTE_CODE = 1 36 | const val UPDATE_NOTE_CODE = 2 37 | class MainActivity : AppCompatActivity(), KnoteListener { 38 | 39 | private lateinit var mainBinding : ActivityMainBinding 40 | @InternalCoroutinesApi 41 | private val noteViewModel by inject() 42 | private lateinit var adapter : NoteAdapter 43 | private lateinit var constraintLayout: ConstraintLayout 44 | var notelist: MutableList = mutableListOf() 45 | private var noteClicked : Int = -1 46 | 47 | @RequiresApi(Build.VERSION_CODES.O) 48 | @SuppressLint("ResourceType") 49 | @InternalCoroutinesApi 50 | override fun onCreate(savedInstanceState: Bundle?) { 51 | super.onCreate(savedInstanceState) 52 | mainBinding = ActivityMainBinding.inflate(layoutInflater) 53 | val view = mainBinding.root 54 | setContentView(view) 55 | 56 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 57 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 58 | } 59 | 60 | 61 | mainBinding.fabAddBtn.setOnClickListener { 62 | startActivityForResult( 63 | Intent(applicationContext,CreateNoteActivity::class.java), 64 | ADD_NOTE_CODE 65 | ) 66 | 67 | } 68 | 69 | mainBinding.imgProfile.setOnClickListener { 70 | Toasty.success(this,"Developer will work on this feature soon", 71 | Toast.LENGTH_SHORT,true).show() 72 | } 73 | 74 | val darkModePrefs = getSharedPreferences(getString(R.string.app_name),0) 75 | val editor = darkModePrefs.edit() 76 | val isNightModeOn : Boolean = darkModePrefs.getBoolean("NightMode",false) 77 | 78 | if (isNightModeOn){ 79 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 80 | imgTheme.setImageResource(R.drawable.sun) 81 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE 82 | }else{ 83 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 84 | imgTheme.setImageResource(R.drawable.moon) 85 | 86 | } 87 | 88 | mainBinding.imgTheme.setOnClickListener { 89 | 90 | if (isNightModeOn){ 91 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 92 | editor.putBoolean("NightMode",false) 93 | editor.apply() 94 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE 95 | imgTheme.setImageResource(R.drawable.sun) 96 | }else{ 97 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 98 | editor.putBoolean("NightMode",true) 99 | editor.apply() 100 | 101 | imgTheme.setImageResource(R.drawable.moon) 102 | } 103 | 104 | } 105 | 106 | adapter = NoteAdapter(notelist,this) 107 | mainBinding.noteRecycler.adapter = adapter 108 | mainBinding.noteRecycler.layoutManager = LinearLayoutManager(this) 109 | mainBinding.noteRecycler.addItemDecoration(DividerItemDecoration(this,LinearLayoutManager.VERTICAL)) 110 | 111 | noteViewModel.readNote.observe(this, Observer { 112 | if (it.isEmpty()){ 113 | mainBinding.emptyLayout.visibility = View.VISIBLE 114 | }else{ 115 | mainBinding.emptyLayout.visibility = View.GONE 116 | } 117 | adapter.updateListItems(it.toMutableList()) 118 | adapter.notifyDataSetChanged() 119 | }) 120 | mainBinding.noteRecycler.smoothScrollToPosition(0) 121 | 122 | mainBinding.edSearchBar.addTextChangedListener(object : TextWatcher { 123 | override fun afterTextChanged(p0: Editable?) { 124 | filter(p0.toString()) 125 | } 126 | 127 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 128 | 129 | } 130 | 131 | override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 132 | 133 | } 134 | }) 135 | 136 | val monthName = arrayOf( 137 | "January", "February", 138 | "March", "April", "May", "June", "July", 139 | "August", "September", "October", "November", 140 | "December" 141 | ) 142 | val cal = Calendar.getInstance() 143 | val month = monthName[cal[Calendar.MONTH]] 144 | 145 | mainBinding.tvMonth.setText(month) 146 | 147 | 148 | } 149 | 150 | 151 | 152 | @InternalCoroutinesApi 153 | override fun listener(note: Note, position: Int) { 154 | 155 | noteClicked = position 156 | Intent(applicationContext,CreateNoteActivity::class.java).also { 157 | it.putExtra("isViewOrUpdate",true) 158 | it.putExtra("knote",note) 159 | startActivityForResult(it, UPDATE_NOTE_CODE) 160 | } 161 | } 162 | 163 | @InternalCoroutinesApi 164 | override fun editlistener(note: Note, position: Int) { 165 | noteClicked = position 166 | Intent(applicationContext,CreateNoteActivity::class.java).also { 167 | it.putExtra("isViewOrUpdate",true) 168 | it.putExtra("knote",note) 169 | startActivityForResult(it, UPDATE_NOTE_CODE) 170 | } 171 | } 172 | 173 | @InternalCoroutinesApi 174 | override suspend fun deleteListener(note: Note, position: Int) { 175 | noteViewModel.deleteNote(note) 176 | } 177 | 178 | fun filter(text: String) { 179 | 180 | val filteredCourseAry: ArrayList = ArrayList() 181 | 182 | val noteSearch : MutableList = notelist 183 | 184 | for (eachNote in noteSearch) { 185 | if (eachNote.noteTitle.toLowerCase(Locale.ROOT).contains(text.toLowerCase(Locale.ROOT)) || eachNote.noteContent.toLowerCase( 186 | Locale.ROOT 187 | ).contains(text.toLowerCase( 188 | Locale.ROOT 189 | ) 190 | ) 191 | || eachNote.noteContent.toLowerCase(Locale.ROOT).contains(text.toLowerCase(Locale.ROOT)) || eachNote.noteContent.toLowerCase( 192 | Locale.ROOT 193 | ).contains(text.toLowerCase( 194 | Locale.ROOT 195 | ) 196 | ) ) { 197 | filteredCourseAry.add(eachNote) 198 | } 199 | } 200 | 201 | 202 | adapter.filterList(filteredCourseAry); 203 | } 204 | } 205 | 206 | 207 | -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/ui/activities/SlideActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.ui.activities 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Build 6 | import androidx.appcompat.app.AppCompatActivity 7 | import android.os.Bundle 8 | import android.view.View 9 | import androidx.annotation.RequiresApi 10 | import androidx.viewpager2.widget.ViewPager2 11 | import com.kluivert.knote.R 12 | import com.kluivert.knote.adapter.SlideAdapter 13 | import com.kluivert.knote.data.entities.SlideModel 14 | import com.kluivert.knote.databinding.ActivitySlideBinding 15 | import com.zhpan.indicator.enums.IndicatorSlideMode 16 | import com.zhpan.indicator.enums.IndicatorStyle 17 | 18 | class SlideActivity : AppCompatActivity() { 19 | 20 | private lateinit var slideBinding : ActivitySlideBinding 21 | 22 | @RequiresApi(Build.VERSION_CODES.M) 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | slideBinding = ActivitySlideBinding.inflate(layoutInflater) 26 | val view = slideBinding.root 27 | setContentView(view) 28 | 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 30 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 31 | } 32 | 33 | var slideList = mutableListOf( 34 | SlideModel(R.drawable.slideone,"Organise your thoughts","Built specifically for you at your comfort"), 35 | SlideModel(R.drawable.slidetwo,"Beautiful user interface and experience","Knote cares about design and simplicity"), 36 | SlideModel(R.drawable.slidethree,"Take notes with ease","Note taking has never been better, Knote makes it easy") 37 | ) 38 | 39 | val adapter = SlideAdapter(slideList) 40 | slideBinding.slidePager.adapter = adapter 41 | 42 | slideBinding.indicatorView 43 | .setSliderColor(R.color.colorSlideInAct,R.color.colorSlideAct) 44 | .setSliderWidth(resources.getDimension(R.dimen._8sdp)) 45 | .setSliderHeight(resources.getDimension(R.dimen._8sdp)) 46 | .setSlideMode(IndicatorSlideMode.WORM) 47 | .setIndicatorStyle(IndicatorStyle.ROUND_RECT) 48 | .setupWithViewPager(slideBinding.slidePager) 49 | 50 | slideBinding.slidePager.orientation = ViewPager2.ORIENTATION_HORIZONTAL 51 | 52 | slideBinding.slidePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){ 53 | 54 | override fun onPageScrollStateChanged(state: Int) { 55 | super.onPageScrollStateChanged(state) 56 | } 57 | 58 | override fun onPageScrolled( 59 | position: Int, 60 | positionOffset: Float, 61 | positionOffsetPixels: Int 62 | ) { 63 | super.onPageScrolled(position, positionOffset, positionOffsetPixels) 64 | 65 | 66 | if (position==0){ 67 | slideBinding.btnNext.visibility = View.INVISIBLE 68 | }else if(position == 1){ 69 | slideBinding.btnNext.visibility = View.INVISIBLE 70 | } else if (position==2){ 71 | slideBinding.btnNext.text = getString(R.string.finish) 72 | slideBinding.btnNext.visibility = View.VISIBLE 73 | 74 | slideBinding.btnNext.setOnClickListener { 75 | Intent(this@SlideActivity,MainActivity::class.java).also { 76 | it.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP 77 | startActivity(it) 78 | finish() 79 | } 80 | } 81 | 82 | } 83 | 84 | } 85 | 86 | override fun onPageSelected(position: Int) { 87 | super.onPageSelected(position) 88 | } 89 | }) 90 | 91 | } 92 | 93 | override fun onResume() { 94 | super.onResume() 95 | val prefs = "slide" 96 | val sharedPreferences = getSharedPreferences("slideprefs",Context.MODE_PRIVATE) 97 | if(!sharedPreferences.getBoolean(prefs,false)){ 98 | val editor = sharedPreferences.edit() 99 | editor.putBoolean(prefs,true) 100 | editor.apply() 101 | }else { 102 | Intent(this@SlideActivity, MainActivity::class.java).also { 103 | startActivity(it) 104 | } 105 | } 106 | 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/utils/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.LinearLayout; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | import androidx.recyclerview.widget.LinearLayoutManager; 15 | import androidx.recyclerview.widget.RecyclerView; 16 | 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.Objects; 20 | 21 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 22 | public static final int HORIZONTAL = LinearLayout.HORIZONTAL; 23 | public static final int VERTICAL = LinearLayout.VERTICAL; 24 | 25 | private static final String TAG = "DividerItem"; 26 | private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; 27 | 28 | private Drawable mDivider; 29 | 30 | /** 31 | * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}. 32 | */ 33 | private int mOrientation; 34 | 35 | private final Rect mBounds = new Rect(); 36 | 37 | /** 38 | * Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a 39 | * {@link LinearLayoutManager}. 40 | * 41 | * @param context Current context, it will be used to access resources. 42 | * @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}. 43 | */ 44 | public DividerItemDecoration(Context context, int orientation) { 45 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 46 | mDivider = a.getDrawable(0); 47 | if (mDivider == null) { 48 | Log.w(TAG, "@android:attr/listDivider was not set in the theme used for this " 49 | + "DividerItemDecoration. Please set that attribute all call setDrawable()"); 50 | } 51 | a.recycle(); 52 | setOrientation(orientation); 53 | } 54 | 55 | /** 56 | * Sets the orientation for this divider. This should be called if 57 | * {@link RecyclerView.LayoutManager} changes orientation. 58 | * 59 | * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} 60 | */ 61 | public void setOrientation(int orientation) { 62 | if (orientation != HORIZONTAL && orientation != VERTICAL) { 63 | throw new IllegalArgumentException( 64 | "Invalid orientation. It should be either HORIZONTAL or VERTICAL"); 65 | } 66 | mOrientation = orientation; 67 | } 68 | 69 | /** 70 | * Sets the {@link Drawable} for this divider. 71 | * 72 | * @param drawable Drawable that should be used as a divider. 73 | */ 74 | public void setDrawable(@NonNull Drawable drawable) { 75 | mDivider = drawable; 76 | } 77 | 78 | /** 79 | * @return the {@link Drawable} for this divider. 80 | */ 81 | @Nullable 82 | public Drawable getDrawable() { 83 | return mDivider; 84 | } 85 | 86 | @Override 87 | public void onDraw(@NotNull Canvas c, RecyclerView parent, @NotNull RecyclerView.State state) { 88 | if (parent.getLayoutManager() == null || mDivider == null) { 89 | return; 90 | } 91 | if (mOrientation == VERTICAL) { 92 | drawVertical(c, parent); 93 | } else { 94 | drawHorizontal(c, parent); 95 | } 96 | } 97 | 98 | private void drawVertical(Canvas canvas, RecyclerView parent) { 99 | canvas.save(); 100 | final int left; 101 | final int right; 102 | //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. 103 | if (parent.getClipToPadding()) { 104 | left = parent.getPaddingLeft(); 105 | right = parent.getWidth() - parent.getPaddingRight(); 106 | canvas.clipRect(left, parent.getPaddingTop(), right, 107 | parent.getHeight() - parent.getPaddingBottom()); 108 | } else { 109 | left = 0; 110 | right = parent.getWidth(); 111 | } 112 | 113 | final int childCount = parent.getChildCount(); 114 | for (int i = 0; i < childCount; i++) { 115 | final View child = parent.getChildAt(i); 116 | parent.getDecoratedBoundsWithMargins(child, mBounds); 117 | final int bottom = mBounds.bottom + Math.round(child.getTranslationY()); 118 | final int top = bottom - mDivider.getIntrinsicHeight(); 119 | mDivider.setBounds(left, top, right, bottom); 120 | mDivider.draw(canvas); 121 | } 122 | canvas.restore(); 123 | } 124 | 125 | private void drawHorizontal(Canvas canvas, RecyclerView parent) { 126 | canvas.save(); 127 | final int top; 128 | final int bottom; 129 | //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. 130 | if (parent.getClipToPadding()) { 131 | top = parent.getPaddingTop(); 132 | bottom = parent.getHeight() - parent.getPaddingBottom(); 133 | canvas.clipRect(parent.getPaddingLeft(), top, 134 | parent.getWidth() - parent.getPaddingRight(), bottom); 135 | } else { 136 | top = 0; 137 | bottom = parent.getHeight(); 138 | } 139 | 140 | final int childCount = parent.getChildCount(); 141 | for (int i = 0; i < childCount; i++) { 142 | final View child = parent.getChildAt(i); 143 | Objects.requireNonNull(parent.getLayoutManager()).getDecoratedBoundsWithMargins(child, mBounds); 144 | final int right = mBounds.right + Math.round(child.getTranslationX()); 145 | final int left = right - mDivider.getIntrinsicWidth(); 146 | mDivider.setBounds(left, top, right, bottom); 147 | mDivider.draw(canvas); 148 | } 149 | canvas.restore(); 150 | } 151 | 152 | @Override 153 | public void getItemOffsets(Rect outRect, @NotNull View view, @NotNull RecyclerView parent, 154 | @NotNull RecyclerView.State state) { 155 | if (mDivider == null) { 156 | outRect.set(0, 0, 0, 0); 157 | return; 158 | } 159 | if (mOrientation == VERTICAL) { 160 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 161 | } else { 162 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/utils/KnoteDiffUtil.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.utils 2 | 3 | import androidx.recyclerview.widget.DiffUtil 4 | import com.kluivert.knote.data.entities.Note 5 | 6 | class KnoteDiffUtil( 7 | private val oldList: MutableList, 8 | private val newList: MutableList 9 | ) : DiffUtil.Callback() { 10 | 11 | 12 | override fun getOldListSize() = oldList.size 13 | 14 | 15 | override fun getNewListSize() = newList.size 16 | 17 | 18 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) 19 | = oldList[oldItemPosition].id == newList[newItemPosition].id 20 | 21 | 22 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { 23 | return oldList[oldItemPosition] == newList[newItemPosition] 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/utils/KnoteListener.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.utils 2 | 3 | import com.kluivert.knote.data.entities.Note 4 | 5 | interface KnoteListener { 6 | 7 | fun listener(note : Note, position : Int) 8 | 9 | fun editlistener(note : Note, position : Int) 10 | 11 | suspend fun deleteListener(note : Note, position: Int) 12 | 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/utils/SnackExtension.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.utils 2 | 3 | import android.view.View 4 | import androidx.annotation.StringRes 5 | import com.google.android.material.snackbar.Snackbar 6 | 7 | 8 | inline fun View.snack(@StringRes messageRes: Int, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) { 9 | snack(resources.getString(messageRes), length, f) 10 | } 11 | 12 | inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) { 13 | val snack = Snackbar.make(this, message, length) 14 | snack.f() 15 | snack.show() 16 | } 17 | 18 | fun Snackbar.action(@StringRes actionRes: Int, color: Int? = null, listener: (View) -> Unit) { 19 | action(view.resources.getString(actionRes), color, listener) 20 | } 21 | 22 | fun Snackbar.action(action: String, color: Int? = null, listener: (View) -> Unit) { 23 | setAction(action, listener) 24 | color?.let { setActionTextColor(color) } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kluivert/knote/utils/ToastIt.kt: -------------------------------------------------------------------------------- 1 | package com.kluivert.knote.utils 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.widget.Toast 7 | 8 | private var toast: Toast? = null 9 | 10 | inline fun Context.startActivity() { 11 | startActivity(Intent(this, T::class.java)) 12 | } 13 | 14 | fun Context.toastIt(message: String) { 15 | toast?.cancel() 16 | toast = Toast.makeText(this, message, Toast.LENGTH_LONG) 17 | .apply { show() } 18 | } -------------------------------------------------------------------------------- /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/add_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/add_image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_delete.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/bold.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_done_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_slide_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/calendar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_layout1.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_layout2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_layout3.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_layout4.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dummypic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/dummypic.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cancel.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_knote_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /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_layout_add.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_link.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/imgsearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/imgsearch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/kletter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/kletter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/linear_grey_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/microphone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/moon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/noteditors_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/pencil.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/product.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/redmicro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/redmicro.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/slideone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/slideone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/slidethree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/slidethree.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/slidetwo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/slidetwo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/sun.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/tintdone.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edkluivert/Knote/894f9517f5661f61372da545c7b11c38b5dee904/app/src/main/res/drawable/web.png -------------------------------------------------------------------------------- /app/src/main/res/font/poppins.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_create_note.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 23 | 24 | 35 | 36 | 37 | 49 | 50 | 51 | 61 | 62 | 80 | 81 | 93 | 94 | 103 | 104 | 112 | 113 | 114 | 115 | 116 | 126 | 127 | 141 | 142 | 152 | 153 | 154 | 166 | 167 | 182 | 183 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 24 | 25 | 32 | 33 | 43 | 44 | 45 | 46 | 47 | 48 | 58 | 59 | 60 | 74 | 75 | 88 | 89 | 90 | 91 | 107 | 108 | 116 | 117 | 132 | 133 | 134 | 135 | 136 | 146 | 147 | 157 | 158 | 166 | 167 | 168 | 169 | 182 | 183 | 199 | 200 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_slide.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 15 | 16 | 24 |