commit 44b1a361f7c2e5339baafa3ef9d766328203d381 Author: hmalik144 Date: Fri Jan 24 13:48:13 2020 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..45b5654 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/h_mal.xml b/.idea/dictionaries/h_mal.xml new file mode 100644 index 0000000..f32ad56 --- /dev/null +++ b/.idea/dictionaries/h_mal.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..169fd0d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d5727af --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..eb27787 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,59 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 29 + defaultConfig { + applicationId "com.example.h_mal.superawesomefilereader" + minSdkVersion 24 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + dataBinding { + enabled = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' + + //Kotlin Coroutines + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0" + + // ViewModel and LiveData + implementation "androidx.lifecycle:lifecycle-extensions:2.1.0" + + //Kodein Dependency Injection + implementation "org.kodein.di:kodein-di-generic-jvm:6.2.1" + implementation "org.kodein.di:kodein-di-framework-android-x:6.2.1" + + //Android Room + implementation "androidx.room:room-runtime:2.2.0-rc01" + implementation "androidx.room:room-ktx:2.2.0-rc01" + kapt "androidx.room:room-compiler:2.2.0-rc01" + + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/example/h_mal/superawesomefilereader/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/h_mal/superawesomefilereader/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..81e8249 --- /dev/null +++ b/app/src/androidTest/java/com/example/h_mal/superawesomefilereader/ExampleInstrumentedTest.kt @@ -0,0 +1,56 @@ +package com.example.h_mal.superawesomefilereader + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.example.h_mal.superawesomefilereader.db.AnagramMapDao +import com.example.h_mal.superawesomefilereader.db.AppDatabase +import com.example.h_mal.superawesomefilereader.db.entities.AnagramMap +import kotlinx.coroutines.runBlocking +import org.junit.After + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* +import org.junit.Before +import java.io.IOException + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + + private lateinit var anagramMapDao: AnagramMapDao + private lateinit var db: AppDatabase + + @Before + fun createDb() { + val context = ApplicationProvider.getApplicationContext() + db = AppDatabase.invoke(context) + anagramMapDao = db.getMapDao() + } + + @After + @Throws(IOException::class) + fun closeDb() { + db.clearAllTables() + } + + @Test + @Throws(Exception::class) + fun addAndUpdateEntries() { + + val anagramPair = AnagramMap("abc", "bca") + val long = runBlocking { anagramMapDao.saveAnagramPair(anagramPair) } + assertEquals(long, (1).toLong()) + + val anagramPair2 = AnagramMap("abc", "cab") + val long2 = runBlocking { anagramMapDao.saveAnagramPair(anagramPair2) } + assertEquals(long2, (-1).toLong()) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..acdcb17 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/AppClass.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/AppClass.kt new file mode 100644 index 0000000..ee460a0 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/AppClass.kt @@ -0,0 +1,36 @@ +package com.example.h_mal.superawesomefilereader + +import android.app.Application +import com.example.h_mal.superawesomefilereader.db.AppDatabase +import com.example.h_mal.superawesomefilereader.repository.Repo +import com.example.h_mal.superawesomefilereader.ui.viewmodel.MainViewModelFactory +import org.kodein.di.Kodein +import org.kodein.di.KodeinAware +import org.kodein.di.android.x.androidXModule +import org.kodein.di.generic.bind +import org.kodein.di.generic.instance +import org.kodein.di.generic.provider +import org.kodein.di.generic.singleton + + +class AppClass : Application(), KodeinAware{ + + + override val kodein + = Kodein.lazy{ import(androidXModule(this@AppClass)) + + bind() from provider { + MainViewModelFactory( + instance() + ) + } + bind() from singleton { + Repo( + instance(), + instance() + ) + } + bind() from singleton { AppDatabase(instance()) } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AnagramMapDao.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AnagramMapDao.kt new file mode 100644 index 0000000..d632b2b --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AnagramMapDao.kt @@ -0,0 +1,38 @@ +package com.example.h_mal.superawesomefilereader.db + +import android.provider.SyncStateContract.Helpers.update +import androidx.lifecycle.LiveData +import androidx.room.* +import com.example.h_mal.superawesomefilereader.db.entities.AnagramMap +import com.example.h_mal.superawesomefilereader.db.entities.AnagramPairs +import java.lang.StringBuilder + + +@Dao +interface AnagramMapDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun saveAnagramPair(anagramMap : AnagramMap):Long + + @Query("UPDATE AnagramMap SET listOfAnagrams = (listOfAnagrams || ',' || (:s2)) WHERE word = (:s1)") + suspend fun update(s1: String, s2 : String) + + @Query("SELECT listOfAnagrams FROM AnagramMap") + fun getAnagramPairList() : LiveData> + + @Query("DELETE FROM AnagramMap") + suspend fun deleteAnagramPairs() + + @Query("SELECT * FROM AnagramMap WHERE word is (:firstWord) LIMIT 1") + suspend fun getItem(firstWord : String): AnagramMap? + + @Transaction + suspend fun upsert(anagramPairs : AnagramPairs) { + val item = saveAnagramPair(AnagramMap(anagramPairs.alphabeticOrderedWord, anagramPairs.word)) + + if (item.toInt() == -1){ + update(anagramPairs.alphabeticOrderedWord,anagramPairs.word) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AppDatabase.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AppDatabase.kt new file mode 100644 index 0000000..1d660e4 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/AppDatabase.kt @@ -0,0 +1,36 @@ +package com.example.h_mal.superawesomefilereader.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.example.h_mal.superawesomefilereader.db.entities.AnagramMap + +@Database( + entities = [AnagramMap::class], + version = 1 +) +abstract class AppDatabase : RoomDatabase() { + + abstract fun getMapDao(): AnagramMapDao + + companion object { + + @Volatile + private var instance: AppDatabase? = null + private val LOCK = Any() + + operator fun invoke(context: Context) = instance ?: synchronized(LOCK) { + instance ?: buildDatabase(context).also { + instance = it + } + } + + private fun buildDatabase(context: Context) = + Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "MyDatabase.db" + ).build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramMap.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramMap.kt new file mode 100644 index 0000000..4e6c998 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramMap.kt @@ -0,0 +1,11 @@ +package com.example.h_mal.superawesomefilereader.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class AnagramMap( + @PrimaryKey(autoGenerate = false) + val word: String, + val listOfAnagrams: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramPairs.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramPairs.kt new file mode 100644 index 0000000..55d1d25 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/db/entities/AnagramPairs.kt @@ -0,0 +1,11 @@ +package com.example.h_mal.superawesomefilereader.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class AnagramPairs( + @PrimaryKey(autoGenerate = false) + val word: String, + val alphabeticOrderedWord: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/repository/Repo.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/repository/Repo.kt new file mode 100644 index 0000000..2f6e235 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/repository/Repo.kt @@ -0,0 +1,71 @@ +package com.example.h_mal.superawesomefilereader.repository + +import android.content.Context +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.example.h_mal.superawesomefilereader.db.AppDatabase +import com.example.h_mal.superawesomefilereader.db.entities.AnagramPairs +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + + +class Repo ( + val database: AppDatabase, + context: Context +){ + + private val applicationContext = context.applicationContext + + private val words = MutableLiveData>() + + init { + words.observeForever { + + CoroutineScope(Dispatchers.IO).launch { + clearDb() + saveWords(it) + } + + } + } + + + + suspend fun startOperation(resourceId: Int) { + + return withContext(Dispatchers.IO){ + val s = textFileToStringList(resourceId) + words.postValue(s) + } + } + + + private suspend fun saveWords(quotes: List) { + CoroutineScope(Dispatchers.IO).launch { + + quotes.forEach { + val anagramPair = AnagramPairs(it,it.toAlphabeticOrder()) + database.getMapDao().upsert(anagramPair) + } + + } + } + + //get character of string to alphabetical order + fun String.toAlphabeticOrder() : String = String(this.toCharArray().sortedArray()) + + + //Get lines of strings from text file in raw resource + private fun textFileToStringList(resourceId: Int): List = + applicationContext.resources.openRawResource(resourceId).reader(Charsets.US_ASCII).readLines() + + //clear database of existing values + suspend fun clearDb() = database.getMapDao().deleteAnagramPairs() + + fun getWords(): LiveData> = database.getMapDao().getAnagramPairList() + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/ExecutionListener.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/ExecutionListener.kt new file mode 100644 index 0000000..734ff62 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/ExecutionListener.kt @@ -0,0 +1,7 @@ +package com.example.h_mal.superawesomefilereader.ui + +interface ExecutionListener { + fun onStarted() + fun onSuccess() + fun onFailure(message: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/MainActivity.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/MainActivity.kt new file mode 100644 index 0000000..47790ae --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/MainActivity.kt @@ -0,0 +1,71 @@ +package com.example.h_mal.superawesomefilereader.ui + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.widget.ArrayAdapter +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.example.h_mal.superawesomefilereader.ui.viewmodel.MainViewModelFactory +import com.example.h_mal.superawesomefilereader.R +import com.example.h_mal.superawesomefilereader.databinding.ActivityMainBinding +import com.example.h_mal.superawesomefilereader.ui.viewmodel.MainViewModel +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.kodein.di.KodeinAware +import org.kodein.di.android.kodein +import org.kodein.di.generic.instance + +class MainActivity : AppCompatActivity(), + ExecutionListener, KodeinAware { + + override val kodein by kodein() + private val factory : MainViewModelFactory by instance() + + lateinit var viewModel: MainViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, + R.layout.activity_main + ) + viewModel = ViewModelProviders.of(this,factory).get(MainViewModel::class.java) + binding.viewmodel = viewModel + + viewModel.callback = this + + + CoroutineScope(Dispatchers.Main).launch { + viewModel.item.await().observe(this@MainActivity, Observer { + if (!it.isNullOrEmpty()){ + val a = ArrayAdapter(this@MainActivity,android.R.layout.simple_list_item_1,it) + list_view.adapter = a + } + }) + } + } + + override fun onStarted() { + progress_circular.visibility = View.VISIBLE + } + + override fun onSuccess() { + progress_circular.visibility = View.GONE + } + + override fun onFailure(message: String) { + progress_circular.visibility = View.GONE + } + + override fun onDestroy() { + super.onDestroy() + CoroutineScope(Dispatchers.IO).launch { + viewModel.clear() + } + + } +} diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModel.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModel.kt new file mode 100644 index 0000000..5a5626f --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModel.kt @@ -0,0 +1,50 @@ +package com.example.h_mal.superawesomefilereader.ui.viewmodel + +import android.view.View +import androidx.lifecycle.ViewModel +import com.example.h_mal.superawesomefilereader.R +import com.example.h_mal.superawesomefilereader.repository.Repo +import com.example.h_mal.superawesomefilereader.ui.ExecutionListener +import kotlinx.coroutines.* + + +class MainViewModel( + private val repository : Repo +) : ViewModel() { + + val item by lazy { + GlobalScope.async(start = CoroutineStart.LAZY) { + repository.getWords() + } + } + + var callback : ExecutionListener? = null + + suspend fun clear() = repository.clearDb() + + //viewbind to button 1 for click event + fun onClick1(view : View){ + + executeAnagramSorting(R.raw.example1) + } + + //viewbind to button 2 for click event + fun onClick2(view : View){ + executeAnagramSorting(R.raw.example2) + } + + //viewbind execute repository operations + fun executeAnagramSorting(resId : Int){ + callback?.onStarted() + + CoroutineScope(Dispatchers.Default).launch { + repository.startOperation(resId) + withContext(Dispatchers.Main){ + callback?.onSuccess() + } + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModelFactory.kt b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModelFactory.kt new file mode 100644 index 0000000..0d52fe3 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/superawesomefilereader/ui/viewmodel/MainViewModelFactory.kt @@ -0,0 +1,17 @@ +package com.example.h_mal.superawesomefilereader.ui.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.h_mal.superawesomefilereader.repository.Repo + +@Suppress("UNCHECKED_CAST") +class MainViewModelFactory( + private val repository: Repo +) : ViewModelProvider.NewInstanceFactory(){ + + override fun create(modelClass: Class): T { + return MainViewModel( + repository + ) as T + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..7a8cc7d --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + +