├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values-v21 │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── xml │ │ │ │ ├── file_paths.xml │ │ │ │ └── pref_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable │ │ │ │ ├── ic_forward_white_24dp.xml │ │ │ │ ├── side_nav_bar.xml │ │ │ │ ├── ic_add_white_24dp.xml │ │ │ │ ├── ic_menu_send.xml │ │ │ │ ├── ic_check_white_24dp.xml │ │ │ │ ├── ic_close_white_24dp.xml │ │ │ │ ├── ic_menu_slideshow.xml │ │ │ │ ├── ic_menu_gallery.xml │ │ │ │ ├── ic_menu_manage.xml │ │ │ │ ├── ic_block_white_24dp.xml │ │ │ │ ├── ic_assignment_black_24dp.xml │ │ │ │ ├── ic_menu_camera.xml │ │ │ │ ├── ic_menu_share.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── menu │ │ │ │ ├── items.xml │ │ │ │ ├── menu_note.xml │ │ │ │ └── activity_items_drawer.xml │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── array.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── layout │ │ │ │ ├── dialog_changephoto.xml │ │ │ │ ├── layout_settings_toolbar.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── content_note_list.xml │ │ │ │ ├── content_items.xml │ │ │ │ ├── activity_note_list.xml │ │ │ │ ├── app_bar_items.xml │ │ │ │ ├── nav_header_items.xml │ │ │ │ ├── activity_items.xml │ │ │ │ ├── layout_account_toolbar.xml │ │ │ │ ├── content_main.xml │ │ │ │ ├── item_course.xml │ │ │ │ ├── item_note.xml │ │ │ │ └── fragment_account.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── jwhh │ │ │ │ └── notekeeper │ │ │ │ ├── IItems.kt │ │ │ │ ├── NoteKeeperData.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── Constants.kt │ │ │ │ ├── NoteListActivity.kt │ │ │ │ ├── CourseRecyclerAdapter.kt │ │ │ │ ├── NoteRecyclerAdapter.kt │ │ │ │ ├── DataManager.kt │ │ │ │ ├── PreferenceHelper.kt │ │ │ │ ├── NoteActivity.kt │ │ │ │ ├── ChangePhotoDialog.kt │ │ │ │ ├── SettingsFragment.kt │ │ │ │ ├── ItemsActivity.kt │ │ │ │ └── AccountFragment.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── jwhh │ │ │ └── notekeeper │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── jwhh │ │ └── notekeeper │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .idea ├── modules.xml ├── runConfigurations.xml ├── gradle.xml └── misc.xml ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/NoteKeeper/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/IItems.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | 4 | interface IItems { 5 | 6 | fun inflateAccountFragment() 7 | 8 | fun onBackPressed() 9 | 10 | fun showSettingsAppBar() 11 | 12 | fun hideSettingsAppBar() 13 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 18 13:13:05 PDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /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/drawable/ic_forward_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/NoteKeeperData.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | data class CourseInfo (val courseId: String, val title: String) { 4 | override fun toString(): String { 5 | return title 6 | } 7 | } 8 | 9 | data class NoteInfo(var course: CourseInfo? = null, var title: String? = null, var text: String? = null) 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_send.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.support.v7.app.AppCompatActivity 4 | import android.os.Bundle 5 | 6 | class MainActivity : AppCompatActivity() { 7 | 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | setContentView(R.layout.activity_main) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/menu/items.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #333333 4 | #222222 5 | @color/pluralsight_orange 6 | #f05a28 7 | #f2f2f2 8 | #ffffffff 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/test/java/com/jwhh/notekeeper/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 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 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_slideshow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_gallery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_manage.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | 16dp 5 | 16dp 6 | 8dp 7 | 176dp 8 | 9 | 8dp 10 | 4dp 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_block_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_assignment_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_note.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | never 5 | 1 hour 6 | 2 hours 7 | 5 hours 8 | 12 hours 9 | 24 hours 10 | 3 days 11 | 7 days 12 | 13 | 14 | 15 | 0 16 | 1 17 | 2 18 | 5 19 | 12 20 | 24 21 | 72 22 | 168 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/jwhh/notekeeper/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.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.getTargetContext() 22 | assertEquals("com.jwhh.notekeeper", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | const val NOTE_POSITION = "NOTE_POSITION" 4 | const val POSITION_NOT_SET = -1 5 | const val PERMISSION_REQUEST_CODE = 9104 //random number 6 | const val CAMERA_REQUEST_CODE = 5467 //random number 7 | const val PICKFILE_REQUEST_CODE = 8352 //random number 8 | 9 | 10 | /* 11 | Fragments 12 | */ 13 | const val FRAGMENT_SETTINGS = "Settings Fragment" 14 | const val FRAGMENT_ACCOUNT = "Account Fragment" 15 | 16 | 17 | /* 18 | SharedPreferences 19 | */ 20 | const val PREFERENCES_PROFILE_IMAGE = "com.jwhh.notekeeper_preferences_profile_image" 21 | const val PREFERENCES_NAME = "com.jwhh.notekeeper_preferences_name" 22 | const val PREFERENCES_USERNAME = "com.jwhh.notekeeper_preferences_username" 23 | const val PREFERENCES_EMAIL = "com.jwhh.notekeeper_preferences_email" 24 | const val PREFERENCES_PHONE_NUMBER = "com.jwhh.notekeeper_preferences_phone_number" 25 | const val PREFERENCES_GENDER = "com.jwhh.notekeeper_preferences_gender" -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_changephoto.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 16 | 17 | 18 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_settings_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/menu/activity_items_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 15 | 16 | 17 | 18 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_note_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_items.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 24 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/NoteListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.widget.ArrayAdapter 7 | 8 | import kotlinx.android.synthetic.main.activity_note_list.* 9 | import kotlinx.android.synthetic.main.content_note_list.* 10 | 11 | class NoteListActivity : AppCompatActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_note_list) 16 | setSupportActionBar(toolbar) 17 | 18 | fab.setOnClickListener { view -> 19 | val activityIntent = Intent(this, NoteActivity::class.java) 20 | startActivity(activityIntent) 21 | } 22 | 23 | listNotes.adapter = ArrayAdapter(this, 24 | android.R.layout.simple_list_item_1, 25 | DataManager.notes) 26 | 27 | listNotes.setOnItemClickListener{parent, view, position, id -> 28 | val activityIntent = Intent(this, NoteActivity::class.java) 29 | activityIntent.putExtra(NOTE_POSITION, position) 30 | startActivity(activityIntent) 31 | } 32 | 33 | 34 | } 35 | 36 | override fun onResume() { 37 | super.onResume() 38 | (listNotes.adapter as ArrayAdapter).notifyDataSetChanged() 39 | } 40 | } 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_note_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_items.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 36 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 27 9 | defaultConfig { 10 | applicationId "com.jwhh.notekeeper" 11 | minSdkVersion 21 12 | targetSdkVersion 27 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(dir: 'libs', include: ['*.jar']) 27 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 28 | implementation 'com.android.support:appcompat-v7:27.1.0' 29 | implementation 'com.android.support.constraint:constraint-layout:1.1.2' 30 | testImplementation 'junit:junit:4.12' 31 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 32 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 33 | 34 | //cardview support 35 | implementation 'com.android.support:cardview-v7:27.1.0' 36 | 37 | //support design 38 | implementation 'com.android.support:design:27.1.0' 39 | 40 | //glide 41 | implementation 'com.github.bumptech.glide:glide:4.7.1' 42 | annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1' 43 | 44 | //circle image view 45 | implementation 'de.hdodenhof:circleimageview:2.2.0' 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nav_header_items.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 22 | 23 | 29 | 30 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/CourseRecyclerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.support.design.widget.Snackbar 6 | import android.support.v7.widget.RecyclerView 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.widget.TextView 11 | 12 | class CourseRecyclerAdapter(val context: Context) : RecyclerView.Adapter() 13 | { 14 | private val layoutInflater = LayoutInflater.from(context) 15 | private val courses = DataManager.courses.values.toList() 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 18 | val itemView = layoutInflater.inflate(R.layout.item_course, parent, false) 19 | return ViewHolder(itemView) 20 | } 21 | 22 | override fun getItemCount(): Int { 23 | return DataManager.courses.size 24 | } 25 | 26 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 27 | val course = courses[position] 28 | holder.textCourse.text = course?.title 29 | holder.currentPosition = position 30 | } 31 | 32 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 33 | val textCourse: TextView = itemView.findViewById(R.id.textCourse) 34 | var currentPosition = 0; 35 | 36 | init { 37 | itemView.setOnClickListener {v -> 38 | Snackbar.make(v, courses[currentPosition].title, 39 | Snackbar.LENGTH_LONG).show() 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/NoteRecyclerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.support.v7.widget.RecyclerView 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.TextView 10 | 11 | class NoteRecyclerAdapter(val context: Context) : RecyclerView.Adapter() 12 | { 13 | private val layoutInflater = LayoutInflater.from(context) 14 | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 16 | val itemView = layoutInflater.inflate(R.layout.item_note, parent, false) 17 | return ViewHolder(itemView) 18 | } 19 | 20 | override fun getItemCount(): Int { 21 | return DataManager.notes.size 22 | } 23 | 24 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 25 | val note = DataManager.notes[position] 26 | holder.textCourse.text = note.course?.title 27 | holder.textTitle.text = note.title 28 | holder.currentPosition = position 29 | } 30 | 31 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 32 | val textCourse: TextView = itemView.findViewById(R.id.textCourse) 33 | val textTitle: TextView = itemView.findViewById(R.id.textTitle) 34 | var currentPosition = 0; 35 | 36 | init { 37 | itemView.setOnClickListener { 38 | val intent = Intent(context, NoteActivity::class.java) 39 | intent.putExtra(NOTE_POSITION, currentPosition) 40 | context.startActivity(intent) 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_items.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 21 | 22 | 26 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_account_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 27 | 28 | 33 | 34 | 41 | 42 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 34 | 35 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_course.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 19 | 20 | 31 | 32 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 22 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/DataManager.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | object DataManager { 4 | val courses = HashMap() 5 | val notes = ArrayList() 6 | 7 | init { 8 | initializeCourses() 9 | initializeNotes() 10 | } 11 | 12 | private fun initializeCourses() { 13 | var course = CourseInfo("android_intents", "Android Programming with Intents") 14 | courses.set(course.courseId, course) 15 | 16 | course = CourseInfo(courseId = "android_async", title = "Android Async Programming and Services") 17 | courses.set(course.courseId, course) 18 | 19 | course = CourseInfo(title = "Java Fundamentals: The Java Language", courseId = "java_lang") 20 | courses.set(course.courseId, course) 21 | 22 | course = CourseInfo("java_core", "Java Fundamentals: The Core Platform") 23 | courses.set(course.courseId, course) 24 | } 25 | 26 | private fun initializeNotes() { 27 | 28 | var course = courses["android_intents"]!! 29 | var note = NoteInfo(course, "Dynamic intent resolution", 30 | "Wow, intents allow components to be resolved at runtime") 31 | notes.add(note) 32 | note = NoteInfo(course, "Delegating intents", 33 | "PendingIntents are powerful; they delegate much more than just a component invocation") 34 | notes.add(note) 35 | 36 | course = courses["android_async"]!! 37 | note = NoteInfo(course, "Service default threads", 38 | "Did you know that by default an Android Service will tie up the UI thread?") 39 | notes.add(note) 40 | note = NoteInfo(course, "Long running operations", 41 | "Foreground Services can be tied to a notification icon") 42 | notes.add(note) 43 | 44 | course = courses["java_lang"]!! 45 | note = NoteInfo(course, "Parameters", 46 | "Leverage variable-length parameter lists") 47 | notes.add(note) 48 | note = NoteInfo(course, "Anonymous classes", 49 | "Anonymous classes simplify implementing one-use types") 50 | notes.add(note) 51 | 52 | course = courses["java_core"]!! 53 | note = NoteInfo(course, "Compiler options", 54 | "The -jar option isn't compatible with with the -cp option") 55 | notes.add(note) 56 | note = NoteInfo(course, "Serialization", 57 | "Remember to include SerialVersionUID to assure version compatibility") 58 | notes.add(note) 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_note.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 19 | 20 | 31 | 32 | 43 | 44 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/PreferenceHelper.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.preference.PreferenceManager 6 | import android.text.Editable 7 | 8 | 9 | object PreferenceHelper{ 10 | 11 | fun defaultPrefs(context: Context): SharedPreferences 12 | = PreferenceManager.getDefaultSharedPreferences(context) 13 | 14 | fun customPrefs(context: Context, name: String): SharedPreferences 15 | = context.getSharedPreferences(name, Context.MODE_PRIVATE) 16 | 17 | inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit){ 18 | val editor = this.edit() 19 | operation(editor) // do the work needed 20 | editor.apply() 21 | } 22 | 23 | operator fun SharedPreferences.set(key: String, value: Any) { 24 | when (value) { 25 | is Editable -> { 26 | if(!value.toString().equals("")){ 27 | edit({ it.putString(key, value.toString()) }) 28 | } 29 | 30 | } 31 | is String -> { 32 | if(!value.equals("")){ 33 | edit({ it.putString(key, value) }) 34 | } 35 | } 36 | is Int -> edit({ it.putInt(key, value) }) 37 | is Boolean -> edit({ it.putBoolean(key, value) }) 38 | is Float -> edit({ it.putFloat(key, value) }) 39 | is Long -> edit({ it.putLong(key, value) }) 40 | else -> throw UnsupportedOperationException("Unsupported Operation") 41 | } 42 | } 43 | 44 | operator inline fun SharedPreferences.get(key: String, defaultValue: T? = null): T? { 45 | return when (T::class) { 46 | String::class -> getString(key, defaultValue as? String) as T? 47 | Int::class -> getInt(key, defaultValue as? Int ?: -1) as T? 48 | Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T? 49 | Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T? 50 | Long::class -> getLong(key, defaultValue as? Long ?: -1) as T? 51 | else -> throw UnsupportedOperationException("Unsupported Operation") 52 | } 53 | } 54 | 55 | 56 | /* 57 | WANT MORE INFORMATION? 58 | 1) https://kotlinlang.org/docs/reference/lambdas.html 59 | 2) https://kotlinlang.org/docs/reference/keyword-reference.html 60 | 3) https://kotlinlang.org/docs/reference/extensions.html 61 | 4) https://kotlinlang.org/docs/reference/object-declarations.html 62 | 5) https://kotlinlang.org/docs/reference/operator-overloading.html 63 | 64 | */ 65 | 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 28 | 29 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 54 | 55 | 60 | 61 | 62 | 63 | 64 | 67 | 68 | 71 | 72 | 76 | 79 | 80 | 81 | 82 | 85 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/NoteActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.Menu 6 | import android.view.MenuItem 7 | import android.widget.ArrayAdapter 8 | 9 | import kotlinx.android.synthetic.main.activity_main.* 10 | import kotlinx.android.synthetic.main.content_main.* 11 | 12 | class NoteActivity : AppCompatActivity() { 13 | private var notePosition = POSITION_NOT_SET 14 | private var isNewNote = false 15 | private var isCancelling = false 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_main) 20 | setSupportActionBar(toolbar) 21 | 22 | val adapterCourses = ArrayAdapter(this, 23 | android.R.layout.simple_spinner_item, 24 | DataManager.courses.values.toList()) 25 | adapterCourses.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) 26 | 27 | spinnerCourses.adapter = adapterCourses 28 | 29 | notePosition = savedInstanceState?.getInt(NOTE_POSITION, POSITION_NOT_SET) ?: 30 | intent.getIntExtra(NOTE_POSITION, POSITION_NOT_SET) 31 | 32 | if(notePosition != POSITION_NOT_SET) 33 | displayNote() 34 | else { 35 | isNewNote = true 36 | DataManager.notes.add(NoteInfo()) 37 | notePosition = DataManager.notes.lastIndex 38 | } 39 | } 40 | 41 | override fun onSaveInstanceState(outState: Bundle?) { 42 | super.onSaveInstanceState(outState) 43 | outState?.putInt(NOTE_POSITION, notePosition) 44 | } 45 | 46 | private fun displayNote() { 47 | val note = DataManager.notes[notePosition] 48 | textNoteTitle.setText(note.title) 49 | textNoteText.setText(note.text) 50 | 51 | val coursePosition = DataManager.courses.values.indexOf(note.course) 52 | spinnerCourses.setSelection(coursePosition) 53 | } 54 | 55 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 56 | // Inflate the menu; this adds items to the action bar if it is present. 57 | menuInflater.inflate(R.menu.menu_note, menu) 58 | return true 59 | } 60 | 61 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 62 | // Handle action bar item clicks here. The action bar will 63 | // automatically handle clicks on the Home/Up button, so long 64 | // as you specify a parent activity in AndroidManifest.xml. 65 | return when (item.itemId) { 66 | R.id.action_cancel -> { 67 | isCancelling = true 68 | finish() 69 | true 70 | } 71 | R.id.action_next -> { 72 | moveNext() 73 | true 74 | } 75 | else -> super.onOptionsItemSelected(item) 76 | } 77 | } 78 | 79 | private fun moveNext() { 80 | saveNote() 81 | ++notePosition 82 | displayNote() 83 | invalidateOptionsMenu() 84 | } 85 | 86 | override fun onPrepareOptionsMenu(menu: Menu?): Boolean { 87 | if(notePosition >= DataManager.notes.lastIndex) { 88 | val menuItem = menu?.findItem(R.id.action_next) 89 | if(menuItem != null) { 90 | menuItem.icon = getDrawable(R.drawable.ic_block_white_24dp) 91 | menuItem.isEnabled = false 92 | } 93 | } 94 | 95 | return super.onPrepareOptionsMenu(menu) 96 | } 97 | 98 | override fun onPause() { 99 | super.onPause() 100 | when { 101 | isCancelling -> { 102 | if(isNewNote) 103 | DataManager.notes.removeAt(notePosition) 104 | } 105 | else -> saveNote() 106 | } 107 | } 108 | 109 | private fun saveNote() { 110 | val note = DataManager.notes[notePosition] 111 | note.title = textNoteTitle.text.toString() 112 | note.text = textNoteText.text.toString() 113 | note.course = spinnerCourses.selectedItem as CourseInfo 114 | } 115 | } 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | NoteKeeper 3 | Settings 4 | NoteListActivity 5 | ItemsActivity 6 | Open navigation drawer 7 | Close navigation drawer 8 | Android Studio 9 | android.studio@android.com 10 | Navigation header 11 | 12 | Name 13 | Username 14 | Private information 15 | Email address 16 | Phone number 17 | Gender 18 | 19 | John Doe 20 | John.Doe 21 | John.Doe@defaultemail.com 22 | 16048555555 23 | 24 | 25 | Change Photo 26 | Account 27 | Settings 28 | 29 | 30 | Male 31 | Female 32 | Not Specified 33 | 34 | 35 | 36 | 37 | Settings 38 | 39 | Ringtone 40 | Silent 41 | 42 | Edit account settings 43 | Account Settings 44 | key_account_settings 45 | 46 | My Notes 47 | Auto upload 48 | Upload the notes when wifi is available 49 | 50 | Notifications 51 | Choose notification sound 52 | About 53 | At Pluralsight we\'re a team of dedicated authors aiming to make tech skills easier to keep up with. 54 | 3.5 55 | Questions? Concerns? Send us feedback! 56 | https://www.pluralsight.com/contact 57 | Send Feedback 58 | FAQ 59 | View frequently asked questions 60 | https://help.pluralsight.com/help 61 | Privacy Policy 62 | https://www.pluralsight.com/privacy 63 | Terms & Conditions 64 | https://www.pluralsight.com/terms 65 | Version 66 | Choose email client 67 | Default Storage 68 | New message notification 69 | Vibrate 70 | Vibrate on new notification 71 | key_upload_over_wifi 72 | key_gallery_name 73 | key_upload_quality 74 | notifications_new_message 75 | key_notifications_new_message_ringtone 76 | key_vibrate 77 | key_send_feedback 78 | 79 | 80 | Data 81 | Data Backup Frequency 82 | If wifi is not available, how often do you want to backup your data? 83 | key_backup_frequency 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/ChangePhotoDialog.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.net.Uri 7 | import android.os.Bundle 8 | import android.os.Environment 9 | import android.provider.MediaStore 10 | import android.support.v4.app.DialogFragment 11 | import android.support.v4.app.Fragment 12 | import android.support.v4.content.FileProvider 13 | import android.util.Log 14 | import android.view.LayoutInflater 15 | import android.view.View 16 | import android.view.ViewGroup 17 | import android.widget.TextView 18 | import java.io.File 19 | import java.io.IOException 20 | import java.text.SimpleDateFormat 21 | import java.util.* 22 | 23 | 24 | class ChangePhotoDialog: DialogFragment() { 25 | 26 | private val TAG = "ChangePhotoDialog" 27 | 28 | interface OnPhotoReceivedListener { 29 | fun setImageUri(imageUri: Uri?) 30 | } 31 | 32 | private var onPhotoReceived: OnPhotoReceivedListener? = null 33 | private var mCurrentPhotoPath: String? = null 34 | 35 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 36 | val view = inflater.inflate(R.layout.dialog_changephoto, container, false) 37 | 38 | //Initialize the textview for choosing an image from memory 39 | val selectPhoto = view.findViewById(R.id.dialogChoosePhoto) as TextView 40 | selectPhoto.setOnClickListener { 41 | Log.d(TAG, "onClick: accessing phones memory.") 42 | val intent = Intent(Intent.ACTION_GET_CONTENT) 43 | intent.type = "image/*" 44 | startActivityForResult(intent, PICKFILE_REQUEST_CODE) 45 | } 46 | 47 | //Initialize the textview for choosing an image from memory 48 | val takePhoto = view.findViewById(R.id.dialogOpenCamera) as TextView 49 | takePhoto.setOnClickListener { 50 | Log.d(TAG, "onClick: starting camera") 51 | val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) 52 | 53 | if (cameraIntent.resolveActivity(activity!!.packageManager) != null) { 54 | // Create the File where the photo should go 55 | var photoFile: File? = null 56 | try { 57 | photoFile = createImageFile() 58 | } catch (ex: IOException) { 59 | // Error occurred while creating the File 60 | Log.d(TAG, "onClick: error: " + ex.message) 61 | } 62 | 63 | // Continue only if the File was successfully created 64 | if (photoFile != null) { 65 | val photoURI = FileProvider.getUriForFile(activity!!, 66 | "com.jwhh.notekeeper.fileprovider", 67 | photoFile) 68 | cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI) 69 | startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE) 70 | } 71 | } 72 | } 73 | 74 | 75 | return view 76 | } 77 | 78 | @Throws(IOException::class) 79 | private fun createImageFile(): File { 80 | // Create an image file name 81 | val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) 82 | val imageFileName = "JPEG_" + timeStamp + "_" 83 | val storageDir = activity!!.getExternalFilesDir(Environment.DIRECTORY_PICTURES) 84 | val image = File.createTempFile( 85 | imageFileName, /* prefix */ 86 | ".jpg", /* suffix */ 87 | storageDir /* directory */ 88 | ) 89 | 90 | // Save a file: path for use with ACTION_VIEW intents 91 | mCurrentPhotoPath = image.absolutePath 92 | return image 93 | } 94 | 95 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 96 | super.onActivityResult(requestCode, resultCode, data) 97 | 98 | Log.d(TAG,"PhotoReceivedListener: " + onPhotoReceived) 99 | /* 100 | Results when selecting new image from phone memory 101 | */ 102 | if (requestCode == PICKFILE_REQUEST_CODE && resultCode == Activity.RESULT_OK) { 103 | val selectedImageUri = data!!.data 104 | Log.d(TAG, "onActivityResult: image: " + selectedImageUri!!) 105 | 106 | //send the bitmap and fragment to the interface 107 | onPhotoReceived!!.setImageUri(selectedImageUri) 108 | dialog.dismiss() 109 | 110 | } else if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) { 111 | 112 | Log.d(TAG, "onActivityResult: image uri: " + mCurrentPhotoPath!!) 113 | onPhotoReceived!!.setImageUri(Uri.fromFile(File(mCurrentPhotoPath!!))) 114 | dialog.dismiss() 115 | } 116 | else{ 117 | dialog.dismiss() 118 | } 119 | } 120 | 121 | override fun onAttachFragment(childFragment: Fragment?) { 122 | super.onAttachFragment(childFragment) 123 | } 124 | 125 | 126 | override fun onAttach(context: Context?) { 127 | super.onAttach(context) 128 | try { 129 | onPhotoReceived = context as OnPhotoReceivedListener 130 | } catch (e: ClassCastException) { 131 | Log.e(TAG, "onAttach: ClassCastException", e.cause) 132 | } 133 | } 134 | } 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.preference.Preference 6 | import android.preference.PreferenceFragment 7 | import android.support.v4.content.ContextCompat 8 | import android.support.v7.app.AppCompatActivity 9 | import android.support.v7.widget.Toolbar 10 | import android.util.Log 11 | import android.view.* 12 | import kotlinx.android.synthetic.main.activity_main.* 13 | 14 | class SettingsFragment: PreferenceFragment(), 15 | Preference.OnPreferenceClickListener, 16 | Preference.OnPreferenceChangeListener 17 | { 18 | 19 | private val TAG = "SettingsFragment" 20 | 21 | private var iItems: IItems? = null 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | 26 | // Load the preferences from an XML resource 27 | addPreferencesFromResource(R.xml.pref_main) 28 | 29 | // Set Preference Click Listener 30 | val accountPreference: Preference = findPreference(getString(R.string.key_account_settings)) 31 | accountPreference.setOnPreferenceClickListener {onPreferenceClick(it)} 32 | 33 | // set Preference Change Listeners 34 | val galleryNamePreference: Preference = preferenceManager.findPreference(getString(R.string.key_gallery_name)) 35 | galleryNamePreference.setOnPreferenceChangeListener(this) 36 | 37 | val uploadWifiPreference: Preference = preferenceManager.findPreference(getString(R.string.key_upload_over_wifi)) 38 | uploadWifiPreference.setOnPreferenceChangeListener(this) 39 | 40 | val notificationsNewMessagePreference: Preference = preferenceManager.findPreference(getString(R.string.key_notifications_new_message)) 41 | notificationsNewMessagePreference.setOnPreferenceChangeListener(this) 42 | 43 | val notificationsRingtonePreference: Preference = preferenceManager.findPreference(getString(R.string.key_notifications_new_message_ringtone)) 44 | notificationsRingtonePreference.setOnPreferenceChangeListener(this) 45 | 46 | val vibratePreference: Preference = preferenceManager.findPreference(getString(R.string.key_vibrate)) 47 | vibratePreference.setOnPreferenceChangeListener(this) 48 | 49 | val backupFrequencyPreference: Preference = preferenceManager.findPreference(getString(R.string.key_backup_frequency)) 50 | backupFrequencyPreference.setOnPreferenceChangeListener(this) 51 | } 52 | 53 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View { 54 | val view: View = super.onCreateView(inflater, container, savedInstanceState) 55 | view.setBackgroundColor(ContextCompat.getColor(activity, R.color.white)) 56 | 57 | iItems!!.showSettingsAppBar() 58 | 59 | val activity = activity as AppCompatActivity 60 | activity.setSupportActionBar(activity.findViewById(R.id.settings_toolbar) as Toolbar) 61 | val actionBar = activity.supportActionBar!! 62 | actionBar.setDisplayHomeAsUpEnabled(true) 63 | actionBar.setTitle(R.string.fragment_settings) 64 | setHasOptionsMenu(true) 65 | 66 | return view 67 | } 68 | 69 | override fun onPreferenceChange(preference: Preference?, key: Any?): Boolean { 70 | printToLog("Preference change detected") 71 | when(key){ 72 | getString(R.string.key_gallery_name) -> updatePreferenceSuccess(getString(R.string.key_gallery_name)) 73 | getString(R.string.key_upload_over_wifi) -> updatePreferenceSuccess(getString(R.string.key_upload_over_wifi)) 74 | getString(R.string.key_notifications_new_message) -> updatePreferenceSuccess(getString(R.string.key_notifications_new_message)) 75 | getString(R.string.key_notifications_new_message_ringtone) -> updatePreferenceSuccess(getString(R.string.key_notifications_new_message_ringtone)) 76 | getString(R.string.key_vibrate) -> updatePreferenceSuccess(getString(R.string.key_vibrate)) 77 | getString(R.string.key_backup_frequency) -> updatePreferenceSuccess(getString(R.string.key_backup_frequency)) 78 | } 79 | 80 | return true // Update the state of the preference with the new value 81 | } 82 | 83 | fun updatePreferenceSuccess(key: String?){ 84 | 85 | // If this was a real application we would send the updates to server here 86 | uploadPreferencesToServer() 87 | 88 | printToLog("successfully updated preferences. key: " + key) 89 | 90 | } 91 | 92 | private fun uploadPreferencesToServer(){ 93 | // Code for uploading updated preferences to server 94 | } 95 | 96 | override fun onPreferenceClick(preference: Preference?): Boolean { 97 | 98 | if(preference!!.key.equals(getString(R.string.key_account_settings))){ 99 | iItems!!.inflateAccountFragment() 100 | } 101 | 102 | return true 103 | } 104 | 105 | override fun onPrepareOptionsMenu(menu: Menu?) { 106 | // Disable the 3 dots in the action bar 107 | val menuItem: MenuItem = menu!!.findItem(R.id.action_settings) 108 | menuItem.setVisible(false) 109 | super.onPrepareOptionsMenu(menu) 110 | } 111 | 112 | override fun onOptionsItemSelected(item: MenuItem?): Boolean { 113 | 114 | if(item!!.itemId == android.R.id.home){ 115 | iItems!!.onBackPressed() 116 | } 117 | return super.onOptionsItemSelected(item) 118 | } 119 | 120 | override fun onAttach(context: Context?) { 121 | super.onAttach(context) 122 | try { 123 | iItems = (context as IItems) 124 | }catch (e: ClassCastException){ 125 | printToLog(e.message) 126 | } 127 | } 128 | 129 | private fun printToLog(message: String?){ 130 | Log.d(TAG, message) 131 | } 132 | } -------------------------------------------------------------------------------- /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/java/com/jwhh/notekeeper/ItemsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.app.FragmentTransaction 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import android.support.design.widget.Snackbar 8 | import android.support.design.widget.NavigationView 9 | import android.support.v4.view.GravityCompat 10 | import android.support.v7.app.ActionBarDrawerToggle 11 | import android.support.v7.app.AppCompatActivity 12 | import android.support.v7.widget.GridLayoutManager 13 | import android.support.v7.widget.LinearLayoutManager 14 | import android.util.Log 15 | import android.view.Menu 16 | import android.view.MenuItem 17 | import android.view.View 18 | import kotlinx.android.synthetic.main.activity_items.* 19 | import kotlinx.android.synthetic.main.app_bar_items.* 20 | import kotlinx.android.synthetic.main.content_items.* 21 | import kotlinx.android.synthetic.main.layout_settings_toolbar.* 22 | 23 | class ItemsActivity : AppCompatActivity(), 24 | NavigationView.OnNavigationItemSelectedListener, 25 | IItems, 26 | ChangePhotoDialog.OnPhotoReceivedListener 27 | { 28 | 29 | private val TAG = "ItemsActivity" 30 | 31 | var accountFragment: AccountFragment? = null 32 | 33 | var settingsFragment: SettingsFragment? = null 34 | 35 | val noteLayoutManager by lazy { 36 | LinearLayoutManager(this) 37 | } 38 | 39 | val noteRecyclerAdapter by lazy { 40 | NoteRecyclerAdapter(this) 41 | } 42 | 43 | val courseLayoutManager by lazy { 44 | GridLayoutManager(this, 2) 45 | } 46 | 47 | val courseRecyclerAdapter by lazy { 48 | CourseRecyclerAdapter(this) 49 | } 50 | 51 | override fun onCreate(savedInstanceState: Bundle?) { 52 | super.onCreate(savedInstanceState) 53 | setContentView(R.layout.activity_items) 54 | setSupportActionBar(toolbar) 55 | 56 | fab.setOnClickListener { view -> 57 | val activityIntent = Intent(this, NoteActivity::class.java) 58 | startActivity(activityIntent) 59 | } 60 | 61 | val toggle = ActionBarDrawerToggle( 62 | this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) 63 | drawer_layout.addDrawerListener(toggle) 64 | toggle.syncState() 65 | 66 | nav_view.setNavigationItemSelectedListener(this) 67 | 68 | displayNotes() 69 | } 70 | 71 | override fun onResume() { 72 | super.onResume() 73 | noteRecyclerAdapter.notifyDataSetChanged() 74 | } 75 | 76 | fun displayNotes() { 77 | recyclerItems.layoutManager = noteLayoutManager 78 | recyclerItems.adapter = noteRecyclerAdapter 79 | nav_view.menu.findItem(R.id.nav_notes).isChecked = true 80 | } 81 | 82 | fun displayCourses() { 83 | recyclerItems.layoutManager = courseLayoutManager 84 | recyclerItems.adapter = courseRecyclerAdapter 85 | nav_view.menu.findItem(R.id.nav_courses).isChecked = true 86 | } 87 | 88 | override fun onBackPressed() { 89 | if (drawer_layout.isDrawerOpen(GravityCompat.START)) { 90 | drawer_layout.closeDrawer(GravityCompat.START) 91 | } 92 | else { 93 | super.onBackPressed() 94 | } 95 | 96 | correctSettingsToolbarVisibilty() 97 | } 98 | 99 | fun correctSettingsToolbarVisibilty(){ 100 | if(settingsFragment != null){ 101 | if(settingsFragment!!.isVisible){ 102 | showSettingsAppBar() 103 | } 104 | else{ 105 | hideSettingsAppBar() 106 | } 107 | return 108 | } 109 | hideSettingsAppBar() 110 | } 111 | 112 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 113 | // Inflate the menu; this adds items to the action bar if it is present. 114 | menuInflater.inflate(R.menu.items, menu) 115 | return true 116 | } 117 | 118 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 119 | // Handle action bar item clicks here. The action bar will 120 | // automatically handle clicks on the Home/Up button, so long 121 | // as you specify a parent activity in AndroidManifest.xml. 122 | return when (item.itemId) { 123 | R.id.action_settings -> { 124 | inflateSettingsFragment() 125 | true 126 | } 127 | else -> super.onOptionsItemSelected(item) 128 | } 129 | } 130 | 131 | override fun inflateAccountFragment(){ 132 | if(accountFragment == null){ 133 | accountFragment = AccountFragment() 134 | } 135 | val transaction: android.support.v4.app.FragmentTransaction = supportFragmentManager.beginTransaction() 136 | transaction.replace(R.id.account_container, accountFragment, FRAGMENT_ACCOUNT) 137 | transaction.addToBackStack(FRAGMENT_ACCOUNT) 138 | transaction.commit() 139 | } 140 | 141 | fun inflateSettingsFragment(){ 142 | printToLog("Inflating Settings Fragment") 143 | if(settingsFragment == null){ 144 | settingsFragment = SettingsFragment() 145 | } 146 | val transaction: FragmentTransaction = fragmentManager.beginTransaction() 147 | transaction.replace(R.id.settings_container, settingsFragment, FRAGMENT_SETTINGS) 148 | transaction.addToBackStack(FRAGMENT_SETTINGS) 149 | transaction.commit() 150 | } 151 | 152 | override fun setImageUri(imageUri: Uri?) { 153 | accountFragment!!.setImageUri(imageUri) 154 | } 155 | 156 | override fun showSettingsAppBar() { 157 | settings_app_bar.visibility = View.VISIBLE 158 | } 159 | 160 | override fun hideSettingsAppBar() { 161 | settings_app_bar.visibility = View.GONE 162 | } 163 | 164 | override fun onNavigationItemSelected(item: MenuItem): Boolean { 165 | // Handle navigation view item clicks here. 166 | when (item.itemId) { 167 | R.id.nav_notes -> { 168 | displayNotes() 169 | } 170 | R.id.nav_courses -> { 171 | displayCourses() 172 | } 173 | R.id.nav_share -> { 174 | showSnackbar("Don't you think you've shared enough") 175 | } 176 | R.id.nav_send -> { 177 | showSnackbar("Send") 178 | } 179 | } 180 | 181 | drawer_layout.closeDrawer(GravityCompat.START) 182 | return true 183 | } 184 | 185 | private fun showSnackbar(message: String) { 186 | Snackbar.make(recyclerItems, message, Snackbar.LENGTH_LONG).show() 187 | } 188 | 189 | private fun printToLog(message: String?){ 190 | Log.d(TAG, message) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_account.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 19 | 20 | 21 | 22 | 25 | 26 | 30 | 31 | 34 | 35 | 43 | 44 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 70 | 71 | 79 | 80 | 81 | 82 | 86 | 87 | 95 | 96 | 97 | 98 | 106 | 107 | 108 | 113 | 114 | 122 | 123 | 124 | 125 | 129 | 130 | 138 | 139 | 140 | 141 | 142 | 148 | 149 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwhh/notekeeper/AccountFragment.kt: -------------------------------------------------------------------------------- 1 | package com.jwhh.notekeeper 2 | 3 | import android.Manifest 4 | import android.annotation.SuppressLint 5 | import android.content.Context 6 | import android.content.SharedPreferences 7 | import android.content.pm.PackageManager 8 | import android.net.Uri 9 | import android.os.* 10 | 11 | 12 | import android.support.design.widget.Snackbar 13 | import android.support.v4.app.ActivityCompat 14 | import android.support.v4.app.Fragment 15 | import android.support.v4.content.ContextCompat 16 | import android.support.v7.app.AppCompatActivity 17 | import android.support.v7.widget.Toolbar 18 | import android.telephony.PhoneNumberFormattingTextWatcher 19 | import android.util.Log 20 | import android.view.LayoutInflater 21 | import android.view.View 22 | import android.view.ViewGroup 23 | import android.view.inputmethod.InputMethodManager 24 | import android.widget.ImageButton 25 | import com.bumptech.glide.Glide 26 | import com.bumptech.glide.request.RequestOptions 27 | import com.jwhh.notekeeper.PreferenceHelper.set 28 | import com.jwhh.notekeeper.PreferenceHelper.get 29 | import kotlinx.android.synthetic.main.fragment_account.* 30 | import kotlinx.android.synthetic.main.layout_account_toolbar.* 31 | import java.util.* 32 | 33 | 34 | class AccountFragment : Fragment(), 35 | View.OnClickListener, 36 | SharedPreferences.OnSharedPreferenceChangeListener 37 | { 38 | private val TAG = "AccountFragment" 39 | 40 | private var isRunning: Boolean = false 41 | private var selectedImageUri: Uri? = null 42 | private var permissions: Boolean = false 43 | private var iItems: IItems? = null 44 | 45 | 46 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 47 | val rootView = inflater.inflate(R.layout.fragment_account, container, false) 48 | return rootView 49 | } 50 | 51 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 52 | input_phone_number.addTextChangedListener(PhoneNumberFormattingTextWatcher(Locale.getDefault().country)) 53 | 54 | initToolbar() 55 | initWidgetValues() 56 | initPermissions() 57 | enablePhotoSelection() 58 | } 59 | 60 | override fun onSharedPreferenceChanged(p0: SharedPreferences?, key: String?) { 61 | when(key){ 62 | PREFERENCES_NAME -> updatePreferenceSuccess(PREFERENCES_NAME) 63 | PREFERENCES_USERNAME -> updatePreferenceSuccess(PREFERENCES_USERNAME) 64 | PREFERENCES_PHONE_NUMBER -> updatePreferenceSuccess(PREFERENCES_PHONE_NUMBER) 65 | PREFERENCES_EMAIL -> updatePreferenceSuccess(PREFERENCES_EMAIL) 66 | PREFERENCES_GENDER -> updatePreferenceSuccess(PREFERENCES_GENDER) 67 | PREFERENCES_PROFILE_IMAGE -> updatePreferenceSuccess(PREFERENCES_PROFILE_IMAGE) 68 | } 69 | } 70 | 71 | fun updatePreferenceSuccess(key: String?){ 72 | showProgressBar() 73 | 74 | // Simulate uploading the new data to server 75 | if(!isRunning){ 76 | 77 | // If this was a real application we would send the updates to server here 78 | simulateUploadToServer() 79 | 80 | Snackbar.make(view!!, "sending updates to server", Snackbar.LENGTH_SHORT).show() 81 | printToLog("successfully updated shared preferences. key: " + key) 82 | } 83 | } 84 | 85 | private fun simulateUploadToServer(){ 86 | val handler = Handler(Looper.getMainLooper()) 87 | val start: Long = System.currentTimeMillis() 88 | val runnable: Runnable = object: Runnable{ 89 | override fun run() { 90 | handler.postDelayed(this, 100) 91 | isRunning = true 92 | val now: Long = System.currentTimeMillis() 93 | val difference: Long = now - start 94 | if(difference >= 1000){ 95 | printToLog("update finished") 96 | updateFinished() 97 | handler.removeCallbacks(this) 98 | isRunning = false 99 | } 100 | } 101 | } 102 | activity!!.runOnUiThread(runnable) 103 | } 104 | 105 | private fun updateFinished(){ 106 | hideProgressBar() 107 | selectedImageUri = null 108 | } 109 | 110 | private fun initPermissions(){ 111 | if (!permissions) { 112 | verifyPermissions() 113 | } 114 | } 115 | 116 | private fun enablePhotoSelection(){ 117 | change_photo.setOnClickListener(this) 118 | profile_image.setOnClickListener(this) 119 | } 120 | 121 | 122 | fun setProfileImage(url: String?){ 123 | val requestOptions: RequestOptions = RequestOptions() 124 | .placeholder(R.mipmap.ic_launcher_round) 125 | 126 | Glide.with(this) 127 | .setDefaultRequestOptions(requestOptions) 128 | .load(url) 129 | .into(profile_image) 130 | } 131 | 132 | fun setImageUri(imageUri: Uri?) { 133 | if (imageUri.toString() != "") { 134 | selectedImageUri = imageUri 135 | printToLog("getImagePath: got the image uri: " + selectedImageUri) 136 | 137 | val requestOptions: RequestOptions = RequestOptions() 138 | .placeholder(R.mipmap.ic_launcher_round) 139 | 140 | Glide.with(this) 141 | .setDefaultRequestOptions(requestOptions) 142 | .load(selectedImageUri) 143 | .into(profile_image) 144 | } 145 | } 146 | 147 | 148 | private fun inflateChangePhotoDialog(){ 149 | if(permissions){ 150 | val dialog = ChangePhotoDialog() 151 | val fm = activity!!.supportFragmentManager 152 | dialog.show(fm, getString(R.string.dialog_change_photo)) 153 | } 154 | else{ 155 | verifyPermissions() 156 | } 157 | 158 | } 159 | 160 | override fun onClick(widget: View?) { 161 | when(widget?.id){ 162 | 163 | R.id.close -> iItems!!.onBackPressed() 164 | 165 | R.id.save -> savePreferences() 166 | 167 | R.id.profile_image -> inflateChangePhotoDialog() 168 | 169 | R.id.change_photo -> inflateChangePhotoDialog() 170 | } 171 | 172 | } 173 | 174 | private fun initWidgetValues(){ 175 | 176 | val prefs: SharedPreferences = PreferenceHelper.defaultPrefs(context!!) 177 | 178 | // Option 1: Specify the type in the declaration 179 | val name: String? = prefs[PREFERENCES_NAME] 180 | input_name.setText(name) 181 | 182 | // Option 2: Specify the type indirectly by setting the default value 183 | val username = prefs[PREFERENCES_USERNAME, ""] 184 | input_username.setText(username) 185 | 186 | val email: String? = prefs[PREFERENCES_EMAIL] 187 | input_email_address.setText(email) 188 | 189 | val phoneNumber: String? = prefs[PREFERENCES_PHONE_NUMBER] 190 | input_phone_number.setText(phoneNumber) 191 | 192 | val gender: String? = prefs[PREFERENCES_GENDER] 193 | if(gender.equals("")){ 194 | gender_spinner.setSelection(0) 195 | } 196 | else{ 197 | val genderArray = resources.getStringArray(R.array.gender_array) 198 | val genderIndex: Int = genderArray.indexOf(gender) 199 | gender_spinner.setSelection(genderIndex) 200 | } 201 | 202 | val profileImageUrl: String? = prefs[PREFERENCES_PROFILE_IMAGE] 203 | setProfileImage(profileImageUrl) 204 | } 205 | 206 | fun savePreferences(){ 207 | view!!.hideKeyboard() 208 | 209 | // val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) 210 | // val editor: SharedPreferences.Editor = prefs.edit() 211 | // if(!input_name.text.toString().equals("")){ 212 | // val name: String? = input_name.text.toString() 213 | // printToLog("saving name: " + name) 214 | // editor.putString(PREFERENCES_NAME, name) 215 | // editor.apply() 216 | // 217 | // } 218 | 219 | 220 | val prefs: SharedPreferences = PreferenceHelper.defaultPrefs(context!!) 221 | 222 | // name 223 | printToLog("saving name: " + input_name.text.toString()) 224 | prefs[PREFERENCES_NAME] = input_name.text 225 | 226 | 227 | // username 228 | val username: String = input_username.text.toString().replace(" ", ".") 229 | printToLog("saving username: " + username) 230 | prefs[PREFERENCES_USERNAME] = username 231 | input_username.setText(username) // fix the username being displayed if necessary 232 | 233 | // Phone Number 234 | val phoneNumber: String = removeNumberFormatting(input_phone_number.text.toString()) 235 | printToLog("saving phone number: " + phoneNumber) 236 | prefs[PREFERENCES_PHONE_NUMBER] = phoneNumber 237 | 238 | // Email Address 239 | printToLog("saving email address: " + input_email_address.text.toString()) 240 | prefs[PREFERENCES_EMAIL] = input_email_address.text 241 | 242 | // Gender 243 | printToLog("saving gender: " + gender_spinner.selectedItem.toString()) 244 | prefs[PREFERENCES_GENDER] = gender_spinner.selectedItem 245 | 246 | 247 | if(selectedImageUri != null){ 248 | prefs[PREFERENCES_PROFILE_IMAGE] = selectedImageUri.toString() 249 | } 250 | } 251 | 252 | private fun removeNumberFormatting(number: String): String{ 253 | val regex = Regex("[^0-9]") 254 | return regex.replace(number, "") 255 | } 256 | 257 | override fun onAttach(context: Context?) { 258 | super.onAttach(context) 259 | try { 260 | iItems = (activity as ItemsActivity) 261 | }catch (e: ClassCastException){ 262 | printToLog(e.message) 263 | } 264 | } 265 | 266 | fun View.hideKeyboard() { 267 | printToLog("closing keyboard") 268 | val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 269 | imm.hideSoftInputFromWindow(windowToken, 0) 270 | } 271 | 272 | private fun showProgressBar(){ 273 | save.visibility = View.INVISIBLE 274 | progress_bar.visibility = View.VISIBLE 275 | } 276 | 277 | private fun hideProgressBar(){ 278 | progress_bar.visibility = View.INVISIBLE 279 | save.visibility = View.VISIBLE 280 | } 281 | 282 | 283 | private fun initToolbar() { 284 | close.setOnClickListener(this) 285 | save.setOnClickListener(this) 286 | } 287 | 288 | fun verifyPermissions() { 289 | Log.d(TAG, "verifyPermissions: asking user for permissions.") 290 | val permissionsArray = arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA) 291 | if (ContextCompat.checkSelfPermission(this.context!!, 292 | permissionsArray[0]) == PackageManager.PERMISSION_GRANTED 293 | && ContextCompat.checkSelfPermission(this.context!!, 294 | permissionsArray[1]) == PackageManager.PERMISSION_GRANTED){ 295 | permissions = true 296 | } else { 297 | ActivityCompat.requestPermissions( 298 | activity!!, 299 | permissionsArray, 300 | PERMISSION_REQUEST_CODE 301 | ) 302 | } 303 | } 304 | 305 | override fun onResume() { 306 | super.onResume() 307 | PreferenceHelper.defaultPrefs(context!!).registerOnSharedPreferenceChangeListener(this) 308 | } 309 | 310 | override fun onPause() { 311 | super.onPause() 312 | PreferenceHelper.defaultPrefs(context!!).unregisterOnSharedPreferenceChangeListener(this) 313 | } 314 | 315 | private fun printToLog(message: String?){ 316 | Log.d(TAG, message) 317 | } 318 | } 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | --------------------------------------------------------------------------------