├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── themes.xml │ │ │ │ └── colors.xml │ │ │ ├── drawable │ │ │ │ ├── heasort.png │ │ │ │ ├── mergesort.jpg │ │ │ │ ├── quicksort.jpg │ │ │ │ ├── bubblesort.PNG │ │ │ │ ├── insertionsort.jpg │ │ │ │ ├── selectionsort.jpg │ │ │ │ ├── ic_pause.xml │ │ │ │ ├── ic_forward.xml │ │ │ │ ├── ic_code.xml │ │ │ │ ├── ic_right_arrow.xml │ │ │ │ ├── ic_left_arrow.xml │ │ │ │ ├── ic_play.xml │ │ │ │ ├── ic_text.xml │ │ │ │ ├── ic_star.xml │ │ │ │ ├── ic_minus.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── font │ │ │ │ ├── worksans_bold.ttf │ │ │ │ ├── worksnas_light.ttf │ │ │ │ ├── worksnas_meduim.ttf │ │ │ │ └── worksans_regular.ttf │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── assets │ │ │ └── database │ │ │ │ ├── algorithm_db.db │ │ │ │ └── .idea │ │ │ │ ├── misc.xml │ │ │ │ ├── modules.xml │ │ │ │ └── workspace.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── algorithmsvisualizer │ │ │ │ ├── TabItem.kt │ │ │ │ ├── AlgorithmsApplication.kt │ │ │ │ ├── AlgorithmItemData.kt │ │ │ │ ├── data │ │ │ │ ├── model │ │ │ │ │ ├── AlgorithmGroup.kt │ │ │ │ │ ├── AlgorithmCode.kt │ │ │ │ │ └── Algorithm.kt │ │ │ │ └── db │ │ │ │ │ ├── relations │ │ │ │ │ ├── AlgorithmWithCodes.kt │ │ │ │ │ └── AlgorithmGroupWithAlgorithms.kt │ │ │ │ │ ├── AlgorithmDao.kt │ │ │ │ │ └── AlgorithmDatabase.kt │ │ │ │ ├── navigation │ │ │ │ ├── NavigationRout.kt │ │ │ │ └── Navigation.kt │ │ │ │ ├── algorithms │ │ │ │ ├── SortingAlgorithms.kt │ │ │ │ ├── Selection.kt │ │ │ │ ├── InsertionSort.kt │ │ │ │ ├── BubbleSort.kt │ │ │ │ ├── SelectionSort.kt │ │ │ │ ├── HeapSort.kt │ │ │ │ ├── QuickSort.kt │ │ │ │ └── MergeSort.kt │ │ │ │ ├── util │ │ │ │ └── Resource.kt │ │ │ │ ├── ui │ │ │ │ └── theme │ │ │ │ │ ├── Shape.kt │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Theme.kt │ │ │ │ │ └── Type.kt │ │ │ │ ├── repo │ │ │ │ ├── AlgorithmRepository.kt │ │ │ │ └── AlgorithmRepositoryImpl.kt │ │ │ │ ├── helper │ │ │ │ └── ArrayOperations.kt │ │ │ │ ├── di │ │ │ │ └── modules │ │ │ │ │ ├── AlgorithmVisualizerModule.kt │ │ │ │ │ └── AppModule.kt │ │ │ │ ├── events │ │ │ │ └── AppEvents.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── viewmodel │ │ │ │ ├── ScreensViewModel.kt │ │ │ │ └── AlgorithmViewModel.kt │ │ │ │ ├── AlgorithmGroupListScreen.kt │ │ │ │ ├── Common.kt │ │ │ │ ├── AlgorithmListScreen.kt │ │ │ │ └── AlgorithmVisualizerScreen.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── algorithmsvisualizer │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── example │ │ └── algorithmsvisualizer │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── .idea ├── .name ├── .gitignore ├── compiler.xml ├── vcs.xml ├── deploymentTargetDropDown.xml ├── gradle.xml └── misc.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── README.md ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Algorithms Visualizer -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Algorithms Visualizer 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/heasort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/heasort.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/mergesort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/mergesort.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/quicksort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/quicksort.jpg -------------------------------------------------------------------------------- /app/src/main/res/font/worksans_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/font/worksans_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable/bubblesort.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/bubblesort.PNG -------------------------------------------------------------------------------- /app/src/main/res/font/worksnas_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/font/worksnas_light.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/worksnas_meduim.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/font/worksnas_meduim.ttf -------------------------------------------------------------------------------- /app/src/main/assets/database/algorithm_db.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/assets/database/algorithm_db.db -------------------------------------------------------------------------------- /app/src/main/res/drawable/insertionsort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/insertionsort.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/selectionsort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/drawable/selectionsort.jpg -------------------------------------------------------------------------------- /app/src/main/res/font/worksans_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/font/worksans_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohammednawas8/Android-Algorithms-Visualizer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/assets/database/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/TabItem.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.compose.ui.graphics.painter.Painter 4 | 5 | data class TabItem( 6 | val icon: Painter, 7 | val title: String 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/AlgorithmsApplication.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import android.app.Application 4 | import dagger.hilt.android.HiltAndroidApp 5 | 6 | @HiltAndroidApp 7 | class AlgorithmsApplication : Application() { 8 | 9 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed May 25 20:43:03 EEST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/assets/database/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/AlgorithmItemData.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.compose.ui.graphics.painter.Painter 4 | import com.example.algorithmsvisualizer.data.model.Algorithm 5 | 6 | data class AlgorithmItemData( 7 | val image: Painter, 8 | val algorithm: Algorithm 9 | ) { 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/model/AlgorithmGroup.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.model 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | 6 | @Entity 7 | data class AlgorithmGroup( 8 | @PrimaryKey(autoGenerate = true) 9 | val groupId: Int = 0, 10 | val name: String, 11 | val count: Int 12 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/navigation/NavigationRout.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.navigation 2 | 3 | sealed class NavigationRout(val rout: String) { 4 | 5 | object AlgorithmListScreen: NavigationRout("als") 6 | object AlgorithmGroupListScreen: NavigationRout("agls") 7 | object AlgorithmVisualizerScreen: NavigationRout("alvls") 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/SortingAlgorithms.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | 4 | 5 | abstract class SortingAlgorithms() { 6 | 7 | abstract suspend fun sort( 8 | arr: Array, 9 | iChange: (Int) -> Unit, 10 | jChange: (Int) -> Unit, 11 | onSwap: (Array) -> Unit 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/util/Resource.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.util 2 | 3 | sealed class Resource( 4 | val data: T? = null, 5 | val message: String? = null 6 | ) { 7 | 8 | class Success(data: T) : Resource(data) 9 | class Error(message: String) : Resource(message = message) 10 | class Loading : Resource() 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/model/AlgorithmCode.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.model 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | 6 | @Entity(primaryKeys = ["code","algorithmId","programmingLanguage"]) 7 | data class AlgorithmCode( 8 | val code: String, 9 | val algorithmId: Int, 10 | val programmingLanguage: String 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.ui.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(0.dp) 11 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forward.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | maven { url "https://jitpack.io" } 14 | 15 | } 16 | } 17 | rootProject.name = "Algorithms Visualizer" 18 | include ':app' 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_code.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/algorithmsvisualizer/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 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 | } -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | #212f3a 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_right_arrow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AlgorithmsVisualizerProj 2 | Android app to simulate how popular algorithms work in a visual way. 3 | 4 | Looking foraward to build a similar app? 5 | you can watch my tutorial on YouTube: https://www.youtube.com/watch?v=RsJbpcmdRQs 6 | 7 | ![Untitled-1](https://user-images.githubusercontent.com/78867217/198827286-03d27144-3196-400d-af77-d66de43cd93a.jpg) 8 | 9 | 10 | https://github.com/mohammednawas8/AlgorithmsVisualizerProj/assets/109604722/9d0bf7f4-aae3-4850-9256-1a9e56d3ea0f 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_left_arrow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/model/Algorithm.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.model 2 | 3 | import androidx.compose.ui.graphics.painter.Painter 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity 8 | data class Algorithm( 9 | @PrimaryKey(autoGenerate = true) 10 | val algorithmId: Int, 11 | val name: String, 12 | val timeComplexity: String, 13 | val description: String, 14 | val groupId: Int, 15 | val title: String 16 | ) { 17 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_text.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_minus.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/db/relations/AlgorithmWithCodes.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.db.relations 2 | 3 | import androidx.room.Embedded 4 | import androidx.room.Relation 5 | import com.example.algorithmsvisualizer.data.model.Algorithm 6 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 7 | 8 | data class AlgorithmWithCodes( 9 | @Embedded val algorithm: Algorithm, 10 | @Relation( 11 | parentColumn = "algorithmId", 12 | entityColumn = "algorithmId" 13 | ) 14 | val codes: List 15 | ) 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/db/relations/AlgorithmGroupWithAlgorithms.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.db.relations 2 | 3 | import androidx.room.Embedded 4 | import androidx.room.Relation 5 | import com.example.algorithmsvisualizer.data.model.Algorithm 6 | import com.example.algorithmsvisualizer.data.model.AlgorithmGroup 7 | 8 | data class AlgorithmGroupWithAlgorithms( 9 | @Embedded val algorithmGroup: AlgorithmGroup, 10 | @Relation( 11 | parentColumn = "groupId", 12 | entityColumn = "groupId" 13 | ) 14 | val algorithms: List 15 | ) { 16 | } -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple200 = Color(0xFFBB86FC) 6 | val Purple500 = Color(0xFF6200EE) 7 | val Purple700 = Color(0xFF3700B3) 8 | val Teal200 = Color(0xFF03DAC5) 9 | 10 | 11 | //BackGround 12 | val BlueGray900 = Color(0xFF212f3a) 13 | //Surface 14 | val BlueGray850 = Color(0xFF253544) 15 | //OnSurface 16 | val Orange600 = Color(0xFFd17165) 17 | //Primary 18 | val Orange800 = Color(0xFFe96b56) 19 | //Prime 20 | val LightGrayBlue = Color(0xFF7b8996) 21 | //Secondary Variant 22 | val GrayBlue = Color(0xFF4E6A82) 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/Selection.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class Selection { 4 | 5 | fun sort(arr: Array) { 6 | val n = arr.size 7 | 8 | // One by one move boundary of unsorted subarray 9 | for (i in 0 until n - 1) { 10 | // Find the minimum element in unsorted array 11 | var min_idx = i 12 | for (j in i + 1 until n) 13 | if (arr[j] < arr[min_idx]) min_idx = j 14 | 15 | // Swap the found minimum element with the first 16 | // element 17 | val temp = arr[min_idx] 18 | arr[min_idx] = arr[i] 19 | arr[i] = temp 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/repo/AlgorithmRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.repo 2 | 3 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmGroupWithAlgorithms 4 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmWithCodes 5 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 6 | import com.example.algorithmsvisualizer.util.Resource 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | interface AlgorithmRepository { 10 | 11 | fun getAlgorithmGroupWithAlgorithms(): Flow> 12 | 13 | fun getAlgorithmWithAlgorithmCodes(): Flow> 14 | 15 | fun getAlgorithmCodesByAlgorithmId(algorithmId: Int): Flow> 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/InsertionSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class InsertionSort: SortingAlgorithms() { 4 | 5 | override suspend fun sort( 6 | arr: Array, 7 | iChange: (Int) -> Unit, 8 | jChange: (Int) -> Unit, 9 | onSwap: (Array) -> Unit, 10 | ) { 11 | for (i in 1 until arr.size) { 12 | iChange(i) 13 | var j = i - 1 14 | val key = arr[i] 15 | while (j >= 0 && key < arr[j]) { 16 | jChange(i) 17 | arr[j + 1] = arr[j] 18 | onSwap(arr) 19 | j -= 1 20 | } 21 | arr[j + 1] = key 22 | onSwap(arr) 23 | } 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/helper/ArrayOperations.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.helper 2 | 3 | import android.util.Log 4 | 5 | class ArrayOperations { 6 | 7 | companion object { 8 | 9 | // { 4 , 2 , 7 , 1 , 8 } 10 | fun deleteArrayElement(arr: Array, index: Int): Array { 11 | 12 | val mutableArray = arr.toMutableList() 13 | mutableArray.removeAt(index) 14 | val tempArr = Array(mutableArray.size, init = { 15 | 0 16 | }) 17 | mutableArray.forEachIndexed { i, item -> 18 | tempArr[i] = item 19 | } 20 | 21 | Log.d("ArrayOperations","deleteArrayElement i=$index") 22 | return tempArr 23 | } 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/algorithmsvisualizer/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.algorithmsvisualizer", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/repo/AlgorithmRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.repo 2 | 3 | import com.example.algorithmsvisualizer.data.db.AlgorithmDatabase 4 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class AlgorithmRepositoryImpl( 8 | private val database: AlgorithmDatabase 9 | ) : AlgorithmRepository { 10 | 11 | private val dao = database.algorithmDao 12 | 13 | @Override 14 | override fun getAlgorithmGroupWithAlgorithms() = dao.getAlgorithmGroupWithAlgorithms() 15 | 16 | @Override 17 | override fun getAlgorithmWithAlgorithmCodes() = dao.getAlgorithmWithAlgorithmCodes() 18 | 19 | override fun getAlgorithmCodesByAlgorithmId(algorithmId: Int) = 20 | database.algorithmDao.getAlgorithmCodesByAlgorithmId(algorithmId) 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/BubbleSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class BubbleSort: SortingAlgorithms() { 4 | 5 | override suspend fun sort( 6 | arr: Array, 7 | iChange: (Int) -> Unit, 8 | jChange: (Int) -> Unit, 9 | onSwap: (Array) -> Unit, 10 | ) { 11 | val n = arr.size 12 | for (i in 0 until n - 1){ 13 | iChange(i) 14 | for (j in 0 until n - i - 1) { 15 | jChange(j) 16 | if (arr[j] > arr[j + 1]) { 17 | // swap arr[j+1] and arr[j] 18 | val temp = arr[j] 19 | arr[j] = arr[j + 1] 20 | arr[j + 1] = temp 21 | onSwap(arr) 22 | } 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/di/modules/AlgorithmVisualizerModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.di.modules 2 | 3 | import com.example.algorithmsvisualizer.algorithms.* 4 | import dagger.Module 5 | import dagger.Provides 6 | import dagger.hilt.InstallIn 7 | import dagger.hilt.android.components.ViewModelComponent 8 | 9 | @Module 10 | @InstallIn(ViewModelComponent::class) 11 | object AlgorithmVisualizerModule { 12 | 13 | @Provides 14 | fun provideSelectionSort() = SelectionSort() 15 | 16 | @Provides 17 | fun provideInsertionSort() = InsertionSort() 18 | 19 | @Provides 20 | fun provideBubbleSort() = BubbleSort() 21 | 22 | @Provides 23 | fun provideMergeSort() = MergeSort() 24 | 25 | @Provides 26 | fun provideHeapSort() = HeapSort() 27 | 28 | @Provides 29 | fun provideQuickSort() = QuickSort() 30 | 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/events/AppEvents.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.events 2 | 3 | import com.example.algorithmsvisualizer.data.model.Algorithm 4 | 5 | sealed class AppEvents { 6 | 7 | //AlgorithmGroupList Screen events 8 | class AlgorithmGroupClick(val algorithmList: List) : AppEvents() 9 | 10 | //AlgorithmList Screen events 11 | class AlgorithmClick(val algorithm: Algorithm): AppEvents() 12 | 13 | //Algorithm Visualizer Screen events 14 | class SortAlgorithm(val algorithm: Algorithm, val arr:Array, val delay:Long): AppEvents() 15 | class DeleteItem(val index: Int) : AppEvents() 16 | class UpdateItem(val index: Int, val value: Int): AppEvents() 17 | object Pause: AppEvents() 18 | class IncreaseDelay(val increaseAmount: Long): AppEvents() 19 | class DecreaseDelay(val decreaseAmount: Long): AppEvents() 20 | object NextStep : AppEvents() 21 | object PreviousStep : AppEvents() 22 | class Initialization(val algorithm: Algorithm) : AppEvents() 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/di/modules/AppModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.di.modules 2 | 3 | import android.content.Context 4 | import com.example.algorithmsvisualizer.data.db.AlgorithmDatabase 5 | import com.example.algorithmsvisualizer.repo.AlgorithmRepository 6 | import com.example.algorithmsvisualizer.repo.AlgorithmRepositoryImpl 7 | import dagger.Module 8 | import dagger.Provides 9 | import dagger.hilt.InstallIn 10 | import dagger.hilt.android.qualifiers.ApplicationContext 11 | import dagger.hilt.components.SingletonComponent 12 | import javax.inject.Singleton 13 | 14 | @Module 15 | @InstallIn(SingletonComponent::class) 16 | object AppModule { 17 | 18 | @Provides 19 | @Singleton 20 | fun provideDatabase( 21 | @ApplicationContext context: Context 22 | ): AlgorithmDatabase = AlgorithmDatabase.getDatabaseInstance(context) 23 | 24 | @Provides 25 | @Singleton 26 | fun provideAlgorithmRepository( 27 | database: AlgorithmDatabase 28 | ): AlgorithmRepository = AlgorithmRepositoryImpl(database) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/SelectionSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class SelectionSort: SortingAlgorithms() { 4 | override suspend fun sort( 5 | arr: Array, 6 | iChange: (Int) -> Unit, 7 | jChange: (Int) -> Unit, 8 | onSwap: (Array) -> Unit, 9 | ) { 10 | 11 | val n = arr.size 12 | 13 | // One by one move boundary of unsorted subarray 14 | for (i in 0 until n - 1) { 15 | // Find the minimum element in unsorted array 16 | var min_idx = i 17 | iChange(i) 18 | for (j in i + 1 until n) { 19 | if (arr[j] < arr[min_idx]) min_idx = j 20 | jChange(j) 21 | } 22 | 23 | // Swap the found minimum element with the first 24 | // element 25 | val temp = arr[min_idx] 26 | arr[min_idx] = arr[i] 27 | arr[i] = temp 28 | onSwap(arr) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/db/AlgorithmDao.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.db 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Query 5 | import androidx.room.Transaction 6 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmGroupWithAlgorithms 7 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmWithCodes 8 | import com.example.algorithmsvisualizer.data.model.Algorithm 9 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 10 | import kotlinx.coroutines.flow.Flow 11 | 12 | @Dao 13 | interface AlgorithmDao { 14 | 15 | @Transaction 16 | @Query("SELECT * FROM AlgorithmGroup") 17 | fun getAlgorithmGroupWithAlgorithms(): Flow> 18 | 19 | @Transaction 20 | @Query("SELECT * FROM Algorithm WHERE Algorithm.groupId = :groupId") 21 | fun getAlgorithmsByGroupId(groupId: Int): Flow> 22 | 23 | @Transaction 24 | @Query("SELECT * FROM Algorithm") 25 | fun getAlgorithmWithAlgorithmCodes(): Flow> 26 | 27 | @Transaction 28 | @Query("SELECT * FROM AlgorithmCode WHERE algorithmId=:algorithmId") 29 | fun getAlgorithmCodesByAlgorithmId(algorithmId: Int): Flow> 30 | 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material.Surface 8 | import androidx.compose.ui.Modifier 9 | import androidx.navigation.compose.rememberNavController 10 | import com.example.algorithmsvisualizer.navigation.Navigation 11 | import com.example.algorithmsvisualizer.ui.theme.AlgorithmsVisualizerTheme 12 | import dagger.hilt.android.AndroidEntryPoint 13 | 14 | @AndroidEntryPoint 15 | class MainActivity : ComponentActivity() { 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | 20 | setContent { 21 | AlgorithmsVisualizerTheme { 22 | Surface(modifier = Modifier 23 | .fillMaxSize() 24 | ) { 25 | val navController = rememberNavController() 26 | Navigation(navController = navController, 27 | modifier = Modifier 28 | .fillMaxSize()) 29 | } 30 | } 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.ui.theme 2 | 3 | import androidx.compose.foundation.isSystemInDarkTheme 4 | import androidx.compose.material.MaterialTheme 5 | import androidx.compose.material.darkColors 6 | import androidx.compose.material.lightColors 7 | import androidx.compose.runtime.Composable 8 | 9 | private val DarkColorPalette = darkColors( 10 | background = BlueGray900, 11 | surface = BlueGray850, 12 | onSurface = LightGrayBlue, 13 | secondary = Orange800, 14 | primary = Orange600, 15 | secondaryVariant = GrayBlue 16 | 17 | ) 18 | 19 | private val LightColorPalette = lightColors( 20 | background = BlueGray900, 21 | surface = BlueGray850, 22 | onSurface = LightGrayBlue, 23 | secondary = Orange800, 24 | primary = Orange600, 25 | secondaryVariant = GrayBlue 26 | ) 27 | 28 | @Composable 29 | fun AlgorithmsVisualizerTheme( 30 | darkTheme: Boolean = isSystemInDarkTheme(), 31 | content: @Composable () -> Unit, 32 | ) { 33 | val colors = if (darkTheme) { 34 | DarkColorPalette 35 | } else { 36 | LightColorPalette 37 | } 38 | 39 | MaterialTheme( 40 | colors = colors, 41 | typography = Typography, 42 | shapes = Shapes, 43 | content = content 44 | ) 45 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/data/db/AlgorithmDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.data.db 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import com.example.algorithmsvisualizer.data.model.Algorithm 8 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 9 | import com.example.algorithmsvisualizer.data.model.AlgorithmGroup 10 | 11 | @Database(entities = [Algorithm::class, AlgorithmGroup::class, AlgorithmCode::class], version = 2) 12 | abstract class AlgorithmDatabase : RoomDatabase() { 13 | abstract val algorithmDao: AlgorithmDao 14 | 15 | companion object { 16 | @Volatile 17 | var INSTANCE: AlgorithmDatabase? = null 18 | 19 | @Synchronized 20 | fun getDatabaseInstance(context: Context): AlgorithmDatabase { 21 | synchronized(this) { 22 | if (INSTANCE == null) { 23 | INSTANCE = Room.databaseBuilder( 24 | context, 25 | AlgorithmDatabase::class.java, 26 | "algorithm_db" 27 | ).createFromAsset("database/algorithm_db.db").fallbackToDestructiveMigration().build() 28 | } 29 | return INSTANCE!! 30 | } 31 | 32 | } 33 | } 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.ui.theme 2 | 3 | import androidx.compose.material.MaterialTheme 4 | import androidx.compose.material.Typography 5 | import androidx.compose.ui.text.TextStyle 6 | import androidx.compose.ui.text.font.Font 7 | import androidx.compose.ui.text.font.FontFamily 8 | import androidx.compose.ui.text.font.FontWeight 9 | import androidx.compose.ui.unit.sp 10 | import com.example.algorithmsvisualizer.R 11 | 12 | 13 | val WorkSans = FontFamily( 14 | Font(R.font.worksans_bold, FontWeight.Bold), 15 | Font(R.font.worksans_regular, FontWeight.Normal), 16 | Font(R.font.worksnas_light, FontWeight.Light), 17 | Font(R.font.worksnas_meduim, FontWeight.Medium), 18 | ) 19 | 20 | val Typography = Typography( 21 | body1 = TextStyle( 22 | fontFamily = FontFamily.Default, 23 | fontWeight = FontWeight.Normal, 24 | fontSize = 18.sp, 25 | ), 26 | h2 = TextStyle( 27 | fontFamily = WorkSans, 28 | fontWeight = FontWeight.Medium, 29 | fontSize = 24.sp, 30 | ), 31 | h3 = TextStyle( 32 | fontFamily = WorkSans, 33 | fontWeight = FontWeight.Normal, 34 | fontSize = 12.sp 35 | ) 36 | /* Other default text styles to override 37 | button = TextStyle( 38 | fontFamily = FontFamily.Default, 39 | fontWeight = FontWeight.W500, 40 | fontSize = 14.sp 41 | ), 42 | caption = TextStyle( 43 | fontFamily = FontFamily.Default, 44 | fontWeight = FontWeight.Normal, 45 | fontSize = 12.sp 46 | ) 47 | */ 48 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/HeapSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class HeapSort : SortingAlgorithms() { 4 | 5 | 6 | override suspend fun sort( 7 | arr: Array, 8 | iChange: (Int) -> Unit, 9 | jChange: (Int) -> Unit, 10 | onSwap: (Array) -> Unit, 11 | ) { 12 | val n = arr.size 13 | 14 | // Build heap (rearrange array) 15 | for (i in n / 2 - 1 downTo 0) { 16 | heapify(arr, n, i) 17 | iChange(i) 18 | onSwap(arr) 19 | } 20 | // One by one extract an element from heap 21 | for (i in n - 1 downTo 1) { 22 | // Move current root to end 23 | val temp = arr[0] 24 | arr[0] = arr[i] 25 | arr[i] = temp 26 | iChange(i) 27 | // call max heapify on the reduced heap 28 | heapify(arr, i, 0) 29 | onSwap(arr) 30 | } 31 | } 32 | 33 | 34 | // To heapify a subtree rooted with node i which is 35 | // an index in arr[]. n is size of heap 36 | fun heapify(arr: Array, n: Int, i: Int) { 37 | var largest = i // Initialize largest as root 38 | val l = 2 * i + 1 // left = 2*i + 1 39 | val r = 2 * i + 2 // right = 2*i + 2 40 | 41 | // If left child is larger than root 42 | if (l < n && arr[l] > arr[largest]) largest = l 43 | 44 | // If right child is larger than largest so far 45 | if (r < n && arr[r] > arr[largest]) largest = r 46 | 47 | // If largest is not root 48 | if (largest != i) { 49 | val swap = arr[i] 50 | arr[i] = arr[largest] 51 | arr[largest] = swap 52 | 53 | // Recursively heapify the affected sub-tree 54 | heapify(arr, n, largest) 55 | } 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /app/src/main/assets/database/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 1657291245262 30 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/QuickSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | 4 | class QuickSort : SortingAlgorithms() { 5 | 6 | /** 7 | * The main function that implements QuickSort 8 | * arr[] --> Array to be sorted, 9 | * low --> Starting index, 10 | * high --> Ending index 11 | */ 12 | 13 | override suspend fun sort( 14 | arr: Array, 15 | iChange: (Int) -> Unit, 16 | jChange: (Int) -> Unit, 17 | onSwap: (Array) -> Unit, 18 | ) { 19 | sort(arr, 0, arr.size - 1, onSwap = onSwap) 20 | } 21 | 22 | suspend fun sort( 23 | arr: Array, 24 | low: Int, 25 | high: Int, 26 | onSwap: (Array) -> Unit, 27 | ) { 28 | if (low < high) { 29 | 30 | // pi is partitioning index, arr[p] 31 | // is now at right place 32 | val pi: Int = partition(arr, low, high, onSwap = { onSwap(arr) }) 33 | 34 | // Separately sort elements before 35 | // partition and after partition 36 | sort(arr, low, pi - 1, onSwap = { onSwap(arr) }) 37 | sort(arr, pi + 1, high, onSwap = { onSwap(arr) }) 38 | } 39 | } 40 | 41 | suspend fun partition(arr: Array, low: Int, high: Int, onSwap: () -> Unit): Int { 42 | 43 | // pivot 44 | val pivot = arr[high] 45 | 46 | // Index of smaller element and 47 | // indicates the right position 48 | // of pivot found so far 49 | var i = low - 1 50 | for (j in low until high) { 51 | 52 | // If current element is smaller 53 | // than the pivot 54 | if (arr[j] < pivot) { 55 | 56 | // Increment index of 57 | // smaller element 58 | i++ 59 | swap(arr, i, j) 60 | onSwap() 61 | } 62 | } 63 | swap(arr, i + 1, high) 64 | onSwap() 65 | return i + 1 66 | } 67 | 68 | // A utility function to swap two elements 69 | suspend fun swap(arr: Array, i: Int, j: Int) { 70 | val temp = arr[i] 71 | arr[i] = arr[j] 72 | arr[j] = temp 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/viewmodel/ScreensViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.viewmodel 2 | 3 | import android.util.Log 4 | import androidx.compose.runtime.collectAsState 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.lifecycle.ViewModel 7 | import androidx.lifecycle.viewModelScope 8 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmWithCodes 9 | import com.example.algorithmsvisualizer.data.model.Algorithm 10 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 11 | import com.example.algorithmsvisualizer.events.AppEvents 12 | import com.example.algorithmsvisualizer.repo.AlgorithmRepository 13 | import dagger.hilt.android.lifecycle.HiltViewModel 14 | import kotlinx.coroutines.flow.collect 15 | import kotlinx.coroutines.launch 16 | import javax.inject.Inject 17 | 18 | @HiltViewModel 19 | class ScreensViewModel @Inject constructor( 20 | private val algorithmRepository: AlgorithmRepository, 21 | ) : ViewModel() { 22 | 23 | val algorithmGroupWithAlgorithms = algorithmRepository.getAlgorithmGroupWithAlgorithms() 24 | 25 | 26 | var algorithmListState = mutableStateOf(emptyList()) 27 | private set 28 | 29 | val algorithmState = mutableStateOf( 30 | Algorithm( 31 | 0, "", "", "", 0,"" 32 | ) 33 | ) 34 | 35 | var algorithmCodes = mutableStateOf>(emptyList()) 36 | private set 37 | 38 | fun onAlgorithmGroupScreenAction(event: AppEvents) { 39 | when (event) { 40 | is AppEvents.AlgorithmGroupClick -> getAlgorithmList(event.algorithmList) 41 | } 42 | } 43 | 44 | fun onAlgorithmScreenAction(event: AppEvents) { 45 | when (event) { 46 | is AppEvents.AlgorithmClick -> { 47 | getAlgorithm(event.algorithm) 48 | getAlgorithmCodes(event.algorithm) 49 | } 50 | } 51 | } 52 | 53 | private fun getAlgorithmCodes(algorithm: Algorithm) = viewModelScope.launch { 54 | algorithmRepository.getAlgorithmCodesByAlgorithmId(algorithm.algorithmId).collect { 55 | algorithmCodes.value = it 56 | } 57 | } 58 | 59 | private fun getAlgorithm(algorithm: Algorithm) { 60 | algorithmState.value = algorithm 61 | 62 | } 63 | 64 | 65 | private fun getAlgorithmList(algorithmList: List) { 66 | algorithmListState.value = algorithmList 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/algorithms/MergeSort.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.algorithms 2 | 3 | class MergeSort : SortingAlgorithms() { 4 | 5 | // Merges two subarrays of arr[]. 6 | // First subarray is arr[l..m] 7 | // Second subarray is arr[m+1..r] 8 | 9 | override suspend fun sort( 10 | arr: Array, 11 | iChange: (Int) -> Unit, 12 | jChange: (Int) -> Unit, 13 | onSwap: (Array) -> Unit, 14 | ) { 15 | sort(arr, 0, arr.size - 1, onSwap = onSwap) 16 | } 17 | 18 | suspend fun sort( 19 | arr: Array, 20 | l: Int, 21 | r: Int, 22 | onSwap: (Array) -> Unit, 23 | ) { 24 | if (l < r) { 25 | val mid = l + (r - l) / 2 26 | sort(arr, l, mid, onSwap = { onSwap(arr) }) 27 | sort(arr, mid + 1, r, onSwap = { onSwap(arr) }) 28 | merge(arr, l, mid, r, onSwap = { onSwap(arr) }) 29 | } 30 | } 31 | 32 | 33 | private suspend fun merge( 34 | arr: Array, 35 | l: Int, m: Int, 36 | r: Int, 37 | onSwap: () -> Unit, 38 | ) { 39 | // Find sizes of two subarrays to be merged 40 | val n1 = m - l + 1 41 | val n2 = r - m 42 | 43 | /* Create temp arrays */ 44 | val L = Array(n1) { 0 } 45 | val R = Array(n2) { 0 } 46 | 47 | 48 | /** 49 | * Copy data to temp arrays 50 | */ 51 | 52 | for (i in 0 until n1) 53 | L[i] = arr[l + i] 54 | for (i in 0 until n2) 55 | R[i] = arr[m + 1 + i] 56 | 57 | /** 58 | * Merge the temp arrays 59 | * Initial indexes of first and second subarrays 60 | */ 61 | var i = 0 62 | var j = 0 63 | 64 | // Initial index of merged subarray array 65 | var k = l 66 | while (i < n1 && j < n2) { 67 | if (L[i] <= R[j]) { 68 | arr[k] = L[i] 69 | onSwap() 70 | i++ 71 | } else { 72 | arr[k] = R[j] 73 | onSwap() 74 | j++ 75 | } 76 | k++ 77 | } 78 | 79 | /* Copy remaining elements of L[] if any */ 80 | while (i < n1) { 81 | arr[k] = L[i] 82 | onSwap() 83 | i++ 84 | k++ 85 | } 86 | 87 | /* Copy remaining elements of R[] if any */ 88 | while (j < n2) { 89 | arr[k] = R[j] 90 | onSwap() 91 | j++ 92 | k++ 93 | } 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | id 'dagger.hilt.android.plugin' 6 | } 7 | 8 | android { 9 | compileSdk 31 10 | 11 | defaultConfig { 12 | applicationId "com.example.algorithmsvisualizer" 13 | minSdk 21 14 | targetSdk 31 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | vectorDrawables { 20 | useSupportLibrary true 21 | } 22 | } 23 | 24 | buildTypes { 25 | release { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 28 | } 29 | } 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | buildFeatures { 38 | compose true 39 | } 40 | composeOptions { 41 | kotlinCompilerExtensionVersion compose_version 42 | } 43 | packagingOptions { 44 | resources { 45 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 46 | } 47 | } 48 | } 49 | 50 | dependencies { 51 | 52 | implementation 'androidx.core:core-ktx:1.7.0' 53 | implementation "androidx.compose.ui:ui:$compose_version" 54 | implementation "androidx.compose.material:material:$compose_version" 55 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" 56 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' 57 | implementation 'androidx.activity:activity-compose:1.3.1' 58 | testImplementation 'junit:junit:4.13.2' 59 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 60 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 61 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" 62 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" 63 | apply plugin: 'kotlin-kapt' 64 | 65 | 66 | //Navigation 67 | def nav_version = "2.4.2" 68 | implementation "androidx.navigation:navigation-compose:$nav_version" 69 | 70 | 71 | //Room 72 | def roomVersion = "2.4.2" 73 | implementation("androidx.room:room-runtime:$roomVersion") 74 | annotationProcessor("androidx.room:room-compiler:$roomVersion") 75 | kapt("androidx.room:room-compiler:$roomVersion") 76 | implementation("androidx.room:room-ktx:$roomVersion") 77 | 78 | //KTX 79 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' 80 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' 81 | implementation "androidx.fragment:fragment-ktx:1.4.1" 82 | 83 | //Dagger hilt 84 | implementation "com.google.dagger:hilt-android:2.38.1" 85 | kapt "com.google.dagger:hilt-compiler:2.38.1" 86 | 87 | //hilt viewModel 88 | implementation 'androidx.hilt:hilt-navigation-compose:1.0.0' 89 | 90 | //compose html 91 | implementation 'com.github.ireward:compose-html:1.0.2' 92 | 93 | 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/navigation/Navigation.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.navigation 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.material.MaterialTheme 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.runtime.remember 7 | import androidx.compose.ui.Modifier 8 | import androidx.hilt.navigation.compose.hiltViewModel 9 | import androidx.navigation.NavHostController 10 | import androidx.navigation.NavType 11 | import androidx.navigation.compose.NavHost 12 | import androidx.navigation.compose.composable 13 | import androidx.navigation.navArgument 14 | import com.example.algorithmsvisualizer.AlgorithmGroupListScreen 15 | import com.example.algorithmsvisualizer.AlgorithmListScreen 16 | import com.example.algorithmsvisualizer.AlgorithmVisualizerScreen 17 | import com.example.algorithmsvisualizer.events.AppEvents 18 | import com.example.algorithmsvisualizer.viewmodel.AlgorithmViewModel 19 | import com.example.algorithmsvisualizer.viewmodel.ScreensViewModel 20 | 21 | @Composable 22 | fun Navigation( 23 | navController: NavHostController, 24 | modifier: Modifier = Modifier, 25 | screenViewModel: ScreensViewModel = hiltViewModel(), 26 | algorithmViewModel: AlgorithmViewModel = hiltViewModel(), 27 | ) { 28 | 29 | NavHost( 30 | navController = navController, 31 | startDestination = NavigationRout.AlgorithmGroupListScreen.rout, 32 | modifier = modifier 33 | .background(MaterialTheme.colors.background) 34 | .then(modifier) 35 | ) { 36 | 37 | composable(route = NavigationRout.AlgorithmGroupListScreen.rout) { 38 | 39 | AlgorithmGroupListScreen(screenViewModel) { algorithmGroupId, algorithmList -> 40 | screenViewModel.onAlgorithmGroupScreenAction(AppEvents.AlgorithmGroupClick( 41 | algorithmList)) 42 | 43 | navController.navigate(NavigationRout.AlgorithmListScreen.rout + "/$algorithmGroupId") 44 | } 45 | } 46 | 47 | composable( 48 | route = NavigationRout.AlgorithmListScreen.rout + "/{groupId}", 49 | arguments = listOf( 50 | navArgument("groupId") { 51 | nullable = false 52 | type = NavType.IntType 53 | } 54 | )) { 55 | val groupId = remember { 56 | it.arguments?.getInt("groupId") 57 | } 58 | 59 | AlgorithmListScreen( 60 | navController = navController, 61 | groupId!!, 62 | screenViewModel 63 | ) 64 | } 65 | 66 | composable( 67 | route = NavigationRout.AlgorithmVisualizerScreen.rout + "/{algorithmId}", 68 | arguments = listOf( 69 | navArgument("algorithmId") { 70 | nullable = false 71 | type = NavType.IntType 72 | } 73 | ) 74 | ) { 75 | val algorithmId = remember { 76 | it.arguments?.getInt("algorithmId") 77 | } 78 | 79 | AlgorithmVisualizerScreen(algorithmId = algorithmId!!, 80 | screenViewModel = screenViewModel, 81 | navController = navController 82 | ) 83 | 84 | } 85 | 86 | 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/AlgorithmGroupListScreen.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.clickable 5 | import androidx.compose.foundation.layout.* 6 | import androidx.compose.foundation.lazy.LazyColumn 7 | import androidx.compose.foundation.shape.RoundedCornerShape 8 | import androidx.compose.material.MaterialTheme 9 | import androidx.compose.material.Text 10 | import androidx.compose.runtime.* 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Alignment.Companion.Center 13 | import androidx.compose.ui.Alignment.Companion.CenterVertically 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.draw.clip 16 | import androidx.compose.ui.unit.dp 17 | import com.example.algorithmsvisualizer.data.db.relations.AlgorithmGroupWithAlgorithms 18 | import com.example.algorithmsvisualizer.data.model.Algorithm 19 | import com.example.algorithmsvisualizer.data.model.AlgorithmGroup 20 | import com.example.algorithmsvisualizer.viewmodel.ScreensViewModel 21 | 22 | @Composable 23 | fun AlgorithmGroupListScreen( 24 | viewModel: ScreensViewModel, 25 | onClick: (groupId: Int,algorithmList: List) -> Unit 26 | ) { 27 | 28 | val algorithmGroupStateList = 29 | viewModel.algorithmGroupWithAlgorithms.collectAsState(initial = emptyList()) 30 | 31 | 32 | Column( 33 | modifier = Modifier.fillMaxSize() 34 | ) { 35 | SearchBar( 36 | onTextChange = {}, modifier = Modifier 37 | .fillMaxWidth() 38 | .padding(start = 10.dp, end = 10.dp, top = 10.dp) 39 | ) 40 | AlgorithmList( 41 | algorithmList = algorithmGroupStateList.value, 42 | modifier = Modifier.padding(top = 18.dp) 43 | ) { groupId,algorithmList -> 44 | onClick(groupId, algorithmList) 45 | } 46 | } 47 | 48 | } 49 | 50 | @Composable 51 | fun AlgorithmList( 52 | modifier: Modifier = Modifier, 53 | algorithmList: List, 54 | onClick: (groupId: Int,List) -> Unit, 55 | ) { 56 | 57 | LazyColumn( 58 | modifier = modifier, 59 | contentPadding = PaddingValues( bottom = 15.dp, start = 15.dp, end = 15.dp), 60 | horizontalAlignment = Alignment.CenterHorizontally, 61 | verticalArrangement = Arrangement.spacedBy(20.dp) 62 | ) { 63 | 64 | 65 | items(algorithmList.size) { 66 | val algorithmGroupWithAlgorithms = algorithmList[it] 67 | AlgorithmGroupItem(algorithmGroup = algorithmList[it].algorithmGroup, count = algorithmGroupWithAlgorithms.algorithms.size,onClick = { 68 | onClick(algorithmGroupWithAlgorithms.algorithmGroup.groupId,algorithmGroupWithAlgorithms.algorithms) 69 | }) 70 | } 71 | 72 | } 73 | 74 | 75 | } 76 | 77 | @Composable 78 | fun AlgorithmGroupItem( 79 | modifier: Modifier = Modifier, 80 | algorithmGroup: AlgorithmGroup, 81 | count: Int, 82 | onClick: (AlgorithmGroup) -> Unit, 83 | ) { 84 | Box(modifier = modifier 85 | .clickable { onClick(algorithmGroup) } 86 | .background(MaterialTheme.colors.surface) 87 | .height(100.dp) 88 | .clip(RoundedCornerShape(2.dp)), 89 | contentAlignment = Center) { 90 | 91 | // Icon( 92 | // painter = painterResource(id = R.drawable.ic_star), 93 | // modifier = Modifier 94 | // .align(Alignment.TopCenter) 95 | // .padding(start = 40.dp, top = 10.dp) 96 | // .size(15.dp), 97 | // contentDescription = null, 98 | // tint = Color.Yellow 99 | // ) 100 | // 101 | // Icon( 102 | // painter = painterResource(id = R.drawable.ic_star), 103 | // modifier = Modifier 104 | // .align(Alignment.CenterEnd) 105 | // .padding(bottom = 40.dp, end = 16.dp) 106 | // .size(15.dp), 107 | // contentDescription = null, 108 | // tint = Color.Yellow 109 | // ) 110 | // 111 | // Icon( 112 | // painter = painterResource(id = R.drawable.ic_star), 113 | // modifier = Modifier 114 | // .align(Alignment.BottomCenter) 115 | // .padding(start = 55.dp, top = 10.dp, bottom = 8.dp) 116 | // .size(15.dp), 117 | // contentDescription = null, 118 | // tint = Color.Yellow 119 | // ) 120 | 121 | Row( 122 | horizontalArrangement = Arrangement.SpaceBetween, 123 | modifier = Modifier.padding(horizontal = 15.dp) 124 | ) { 125 | 126 | Column( 127 | modifier = Modifier 128 | .weight(0.6f) 129 | .align(CenterVertically) 130 | ) { 131 | 132 | Text( 133 | text = algorithmGroup.name, 134 | style = MaterialTheme.typography.h2, 135 | color = MaterialTheme.colors.primary 136 | ) 137 | 138 | Text( 139 | text = count.toString().plus(" algorithms"), 140 | style = MaterialTheme.typography.h3, color = MaterialTheme.colors.onSurface, 141 | modifier = Modifier 142 | ) 143 | } 144 | 145 | Row( 146 | modifier = Modifier.weight(0.3f), 147 | horizontalArrangement = Arrangement.End 148 | ) { 149 | val radius = 32f 150 | DrawSortImage(radius = radius) 151 | } 152 | 153 | } 154 | 155 | } 156 | } 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/Common.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.compose.foundation.Canvas 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.CircleShape 6 | import androidx.compose.material.* 7 | import androidx.compose.runtime.* 8 | import androidx.compose.ui.Alignment 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.focus.onFocusChanged 11 | import androidx.compose.ui.geometry.Offset 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.graphics.PathEffect 14 | import androidx.compose.ui.graphics.drawscope.Stroke 15 | import androidx.compose.ui.res.painterResource 16 | import androidx.compose.ui.text.TextStyle 17 | import androidx.compose.ui.text.font.FontWeight 18 | import androidx.compose.ui.text.style.TextAlign 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | import com.example.algorithmsvisualizer.ui.theme.WorkSans 22 | 23 | @Composable 24 | fun DrawSortImage( 25 | modifier: Modifier = Modifier, 26 | radius: Float = 35f, 27 | ) { 28 | BoxWithConstraints(modifier = Modifier.fillMaxSize()) { 29 | val maxHeight = constraints.maxHeight.toFloat() 30 | val maxWidth = constraints.maxWidth.toFloat() 31 | 32 | 33 | 34 | Canvas(modifier = modifier, onDraw = { 35 | 36 | //Left Big Circle 37 | drawCircle( 38 | color = Color(0xFFD6D6D6), 39 | radius = radius * 3, 40 | center = Offset(y = maxHeight / 2, x = (radius * 3.2).toFloat()), 41 | style = Stroke( 42 | 2f, 43 | pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 10f) 44 | ) 45 | ) 46 | 47 | //Right Big Circle 48 | drawCircle( 49 | color = Color(0xFFD6D6D6), 50 | radius = radius * 3, 51 | center = Offset(y = maxHeight / 2, x = (radius * 3.2 * 2).toFloat()), 52 | style = Stroke( 53 | 2f, 54 | pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 10f) 55 | ) 56 | ) 57 | 58 | //First circle from left 59 | drawCircle( 60 | color = Color(0xFF4eeaca), 61 | radius = radius, 62 | center = Offset(y = maxHeight / 2, x = 0f) 63 | ) 64 | 65 | //Second circle from left 66 | drawCircle( 67 | color = Color(0xFF4e9796), 68 | radius = radius - 4, 69 | center = Offset(y = maxHeight / 2, x = (radius * 3.2).toFloat()), 70 | ) 71 | 72 | //Third circle from left 73 | drawCircle( 74 | color = Color(0xFF9a84d6), 75 | radius = radius, 76 | center = Offset(y = maxHeight / 2, x = (radius * 3.2 * 2).toFloat()), 77 | ) 78 | 79 | //Fourth circle from left 80 | drawCircle( 81 | color = Color(0xFF816568), 82 | radius = radius - 4, 83 | center = Offset(y = maxHeight / 2, x = (radius * 3.2 * 3).toFloat()), 84 | ) 85 | 86 | 87 | }) 88 | } 89 | 90 | } 91 | 92 | @Composable 93 | fun Star(modifier: Modifier = Modifier, tint: Color = Color.Yellow) { 94 | Icon( 95 | painter = painterResource(id = R.drawable.ic_star), 96 | contentDescription = null, 97 | tint = tint, 98 | modifier = modifier 99 | ) 100 | } 101 | 102 | @Composable 103 | fun SearchBar( 104 | modifier: Modifier = Modifier, 105 | hint: String = "Search...", 106 | hintColor: Color = MaterialTheme.colors.onSurface, 107 | searchBoxColor: Color = MaterialTheme.colors.surface, 108 | onTextChange: (String) -> Unit, 109 | 110 | ) { 111 | 112 | Box( 113 | modifier = modifier, 114 | contentAlignment = Alignment.Center 115 | ) { 116 | 117 | var searchText by remember { 118 | mutableStateOf("") 119 | } 120 | 121 | var isSearchBarFocused by remember { 122 | mutableStateOf(false) 123 | } 124 | 125 | TextField( 126 | value = searchText, 127 | onValueChange = { 128 | onTextChange(it) 129 | searchText = it 130 | }, 131 | colors = TextFieldDefaults.textFieldColors( 132 | backgroundColor = searchBoxColor, 133 | textColor = Color.White, 134 | focusedIndicatorColor = Color.Transparent, 135 | unfocusedIndicatorColor = Color.Transparent 136 | ), 137 | shape = CircleShape, 138 | textStyle = TextStyle( 139 | color = Color.White, 140 | fontSize = 14.sp, 141 | fontFamily = WorkSans, 142 | fontWeight = FontWeight.Normal 143 | ), 144 | modifier = Modifier 145 | .fillMaxWidth() 146 | .onFocusChanged { 147 | isSearchBarFocused = it.isFocused 148 | }, 149 | singleLine = true, 150 | ) 151 | 152 | if (!isSearchBarFocused) 153 | Text( 154 | text = hint, 155 | textAlign = TextAlign.Start, 156 | modifier = Modifier 157 | .fillMaxWidth() 158 | .padding(horizontal = 12.dp), 159 | style = MaterialTheme.typography.h3, 160 | fontSize = 14.sp, 161 | color = hintColor 162 | 163 | ) 164 | 165 | } 166 | 167 | } 168 | 169 | 170 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/AlgorithmListScreen.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.clickable 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.lazy.LazyColumn 8 | import androidx.compose.foundation.shape.RoundedCornerShape 9 | import androidx.compose.material.Icon 10 | import androidx.compose.material.IconButton 11 | import androidx.compose.material.MaterialTheme 12 | import androidx.compose.material.Text 13 | import androidx.compose.material.icons.Icons 14 | import androidx.compose.material.icons.filled.ArrowBack 15 | import androidx.compose.runtime.* 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.clip 19 | import androidx.compose.ui.draw.shadow 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.painter.Painter 22 | import androidx.compose.ui.layout.ContentScale 23 | import androidx.compose.ui.res.painterResource 24 | import androidx.compose.ui.unit.dp 25 | import androidx.compose.ui.unit.sp 26 | import androidx.navigation.NavController 27 | import com.example.algorithmsvisualizer.data.model.Algorithm 28 | import com.example.algorithmsvisualizer.events.AppEvents 29 | import com.example.algorithmsvisualizer.navigation.NavigationRout 30 | import com.example.algorithmsvisualizer.viewmodel.ScreensViewModel 31 | 32 | @Composable 33 | fun AlgorithmListScreen( 34 | navController: NavController, 35 | groupId: Int, 36 | viewModel: ScreensViewModel, 37 | ) { 38 | 39 | val algorithmList = viewModel.algorithmListState 40 | 41 | Column( 42 | modifier = Modifier 43 | .fillMaxSize() 44 | ) { 45 | 46 | 47 | Row( 48 | modifier = Modifier 49 | .fillMaxWidth() 50 | .padding(vertical = 15.dp), 51 | verticalAlignment = Alignment.CenterVertically, 52 | ) { 53 | 54 | IconButton(onClick = { 55 | navController.navigateUp() 56 | }, 57 | ) { 58 | Icon( 59 | imageVector = Icons.Default.ArrowBack, 60 | contentDescription = "Back", 61 | tint = MaterialTheme.colors.onSurface, 62 | modifier = Modifier 63 | ) 64 | } 65 | 66 | } 67 | 68 | 69 | 70 | AlgorithmList( 71 | algorithmsItems = algorithmList.value, 72 | modifier = Modifier.padding(horizontal = 15.dp), 73 | onClick = { 74 | navController.navigate(NavigationRout.AlgorithmVisualizerScreen.rout + "/${it.algorithmId}") 75 | viewModel.onAlgorithmScreenAction(AppEvents.AlgorithmClick(it)) 76 | }) 77 | 78 | } 79 | 80 | } 81 | 82 | 83 | @Composable 84 | fun AlgorithmList( 85 | modifier: Modifier = Modifier, 86 | algorithmsItems: List, 87 | onClick: (Algorithm) -> Unit, 88 | ) { 89 | LazyColumn( 90 | modifier = modifier, 91 | contentPadding = PaddingValues(top = 10.dp, bottom = 20.dp), 92 | verticalArrangement = Arrangement.spacedBy(20.dp), 93 | horizontalAlignment = Alignment.CenterHorizontally 94 | ) { 95 | items(algorithmsItems.size) { 96 | AlgorithmCard( 97 | image = painterResource( 98 | id = when (algorithmsItems[it].name) { 99 | "Insertion Sort" -> R.drawable.insertionsort 100 | "Selection Sort" -> R.drawable.selectionsort 101 | "Merge Sort" -> R.drawable.mergesort 102 | "Quick Sort" -> R.drawable.quicksort 103 | "Heap Sort" -> R.drawable.heasort 104 | "Bubble Sort" -> R.drawable.bubblesort 105 | else -> 0 106 | } 107 | 108 | ), 109 | algorithm = algorithmsItems[it], 110 | onClick = onClick, 111 | ) 112 | } 113 | } 114 | } 115 | 116 | @Composable 117 | fun AlgorithmCard( 118 | modifier: Modifier = Modifier, 119 | image: Painter, 120 | algorithm: Algorithm, 121 | titleColor: Color = MaterialTheme.colors.primary, 122 | descriptionTextColor: Color = MaterialTheme.colors.onSurface, 123 | onClick: (Algorithm) -> Unit, 124 | ) { 125 | 126 | Box( 127 | modifier = modifier 128 | .background(MaterialTheme.colors.surface) 129 | .clip(RoundedCornerShape(3.dp)) 130 | .clickable { onClick(algorithm) } 131 | ) { 132 | 133 | Column( 134 | modifier = Modifier.fillMaxSize(), 135 | verticalArrangement = Arrangement.spacedBy(0.dp) 136 | ) { 137 | Image( 138 | painter = image, 139 | contentDescription = algorithm.name, 140 | modifier = Modifier 141 | .clip(RoundedCornerShape(5.dp)) 142 | .shadow(5.dp) 143 | .fillMaxWidth() 144 | .height(160.dp), 145 | contentScale = ContentScale.Crop 146 | ) 147 | 148 | Spacer(modifier = Modifier.height(7.dp)) 149 | 150 | Text( 151 | text = algorithm.name, 152 | color = titleColor, 153 | style = MaterialTheme.typography.h2, 154 | modifier = Modifier 155 | .padding(horizontal = 5.dp) 156 | ) 157 | 158 | 159 | Text( 160 | text = algorithm.title.trim(), 161 | color = descriptionTextColor, 162 | modifier = Modifier 163 | .padding(horizontal = 8.dp), 164 | style = MaterialTheme.typography.h3, 165 | fontSize = 16.sp, 166 | maxLines = 2 167 | ) 168 | 169 | Spacer(modifier = Modifier.height(14.dp)) 170 | 171 | } 172 | 173 | } 174 | 175 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/viewmodel/AlgorithmViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer.viewmodel 2 | 3 | import android.annotation.SuppressLint 4 | import android.util.Log 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.lifecycle.ViewModel 7 | import androidx.lifecycle.viewModelScope 8 | import com.example.algorithmsvisualizer.algorithms.* 9 | import com.example.algorithmsvisualizer.data.model.Algorithm 10 | import com.example.algorithmsvisualizer.events.AppEvents 11 | import com.example.algorithmsvisualizer.helper.ArrayOperations 12 | import dagger.hilt.android.lifecycle.HiltViewModel 13 | import kotlinx.coroutines.delay 14 | import kotlinx.coroutines.launch 15 | import javax.inject.Inject 16 | 17 | @HiltViewModel 18 | class AlgorithmViewModel @Inject constructor( 19 | private val insertionSort: InsertionSort, 20 | private val selectionSort: SelectionSort, 21 | private val bubbleSort: BubbleSort, 22 | private val mergeSort: MergeSort, 23 | private val quickSort: QuickSort, 24 | private val heapSort: HeapSort, 25 | ) : ViewModel() { 26 | 27 | val onSortingFinish = mutableStateOf(false) 28 | 29 | val arrState = 30 | mutableStateOf(arrayOf(100, 120, 80, 55, 40, 5, 25, 320, 80, 23, 534, 64)) 31 | 32 | var nextStep = 1 33 | var previousStep = 0 34 | 35 | @SuppressLint("MutableCollectionMutableState") 36 | var sortedArrLevels = mutableListOf>() 37 | 38 | private var stepSize = 2 39 | 40 | var delayDuration = 850L 41 | 42 | fun onAction(event: AppEvents) { 43 | when (event) { 44 | 45 | is AppEvents.SortAlgorithm -> { 46 | isPaused = false 47 | onSortingFinish.value = false 48 | arrState.value = event.arr 49 | val delay = event.delay 50 | this.delayDuration = delay 51 | startAlgorithm(arrState.value.size) 52 | 53 | } 54 | 55 | is AppEvents.Initialization -> { 56 | prepareSortedArrLevels(event.algorithm) 57 | } 58 | 59 | is AppEvents.DeleteItem -> deleteItemFromArray(event.index) 60 | 61 | is AppEvents.UpdateItem -> updateItemInTheArray(event.index, event.value) 62 | 63 | is AppEvents.Pause -> pauseInsertionSort() 64 | 65 | is AppEvents.IncreaseDelay -> increaseDelay(event.increaseAmount) 66 | 67 | is AppEvents.DecreaseDelay -> decreaseDelay(event.decreaseAmount) 68 | 69 | is AppEvents.NextStep -> nextStep() 70 | 71 | is AppEvents.PreviousStep -> previousStep() 72 | 73 | else -> {} 74 | } 75 | } 76 | 77 | private fun prepareSortedArrLevels(algorithm: Algorithm) { 78 | when (algorithm.name) { 79 | "Insertion Sort" -> { 80 | insertionSort(arrState.value.clone()) 81 | } 82 | "Selection Sort" -> { 83 | selectionSort(arrState.value.clone()) 84 | } 85 | "Merge Sort" -> { 86 | mergeSort(arrState.value.clone()) 87 | } 88 | "Heap Sort" -> { 89 | heapSort(arrState.value.clone()) 90 | } 91 | "Quick Sort" -> { 92 | quickSort(arrState.value.clone()) 93 | } 94 | "Bubble Sort" -> { 95 | bubbleSort(arrState.value.clone()) 96 | } 97 | } 98 | } 99 | 100 | 101 | private fun decreaseDelay(decreaseAmount: Long) { 102 | if (delayDuration > 160) { 103 | delayDuration -= decreaseAmount 104 | } 105 | } 106 | 107 | private fun increaseDelay(increaseAmount: Long) { 108 | delayDuration += increaseAmount 109 | 110 | } 111 | 112 | private var isNextStepClicked = false 113 | private fun nextStep() { 114 | if (nextStep < sortedArrLevels.size && nextStep >= 0) { 115 | copyArrayIntoArrState(sortedArrLevels[nextStep].toIntArray(), arrState.value.size) 116 | sortingState = nextStep 117 | nextStep++ 118 | previousStep++ 119 | isNextStepClicked = true 120 | } 121 | } 122 | 123 | private fun previousStep() { 124 | //Solve bug 125 | //bug description : When the user clicks on nextStep the previousStep will increment by 1 126 | //the problem is when the user clicks on previous step after that increment. 127 | //the solution is to check if the next step already clicked. if so then we decrement previousStep by 1. 128 | if (isNextStepClicked) { 129 | previousStep-- 130 | nextStep-- 131 | isNextStepClicked = false 132 | } 133 | 134 | if (previousStep >= 0) { 135 | copyArrayIntoArrState(sortedArrLevels[previousStep].toIntArray(), arrState.value.size) 136 | //To prevent the previousStep becoming -1 137 | if (previousStep != 0) { 138 | sortingState = previousStep 139 | nextStep-- 140 | previousStep-- 141 | } 142 | } 143 | } 144 | 145 | private var isPaused = false 146 | private var sortingState = 0 147 | private fun startAlgorithm(size: Int) = viewModelScope.launch { 148 | for (i in sortingState until sortedArrLevels.size) { 149 | if (!isPaused) { 150 | delay(delayDuration) 151 | copyArrayIntoArrState(sortedArrLevels[i].toIntArray(), size) 152 | } else { 153 | sortingState = i 154 | nextStep = i + 1 155 | previousStep = i 156 | return@launch 157 | } 158 | } 159 | onSortingFinish.value = true 160 | } 161 | 162 | private fun pauseInsertionSort() { 163 | isPaused = true 164 | } 165 | 166 | 167 | private fun insertionSort( 168 | arr: Array, 169 | ) = viewModelScope.launch { 170 | insertionSort.sort( 171 | arr, 172 | iChange = { i -> 173 | 174 | }, 175 | jChange = { j -> 176 | 177 | }, 178 | onSwap = { arr -> 179 | addArrayIntoSortedArrLevels(arr) 180 | } 181 | ) 182 | 183 | // Sorting is finished 184 | onSortingFinish.value = true 185 | 186 | } 187 | 188 | private fun selectionSort( 189 | arr: Array, 190 | ) = viewModelScope.launch { 191 | selectionSort.sort( 192 | arr, 193 | iChange = { i -> 194 | 195 | }, 196 | jChange = { j -> 197 | 198 | }, 199 | onSwap = { arr -> 200 | addArrayIntoSortedArrLevels(arr) 201 | } 202 | ) 203 | } 204 | 205 | 206 | private fun mergeSort( 207 | arr: Array 208 | ) = viewModelScope.launch { 209 | mergeSort.sort( 210 | arr, 211 | iChange = { i -> 212 | 213 | }, 214 | jChange = { j -> 215 | 216 | }, 217 | onSwap = { arr -> 218 | addArrayIntoSortedArrLevels(arr) 219 | } 220 | ) 221 | } 222 | 223 | private fun heapSort( 224 | arr: Array 225 | ) = viewModelScope.launch { 226 | heapSort.sort( 227 | arr, 228 | iChange = { i -> 229 | 230 | }, 231 | jChange = { j -> 232 | 233 | }, 234 | onSwap = { arr -> 235 | addArrayIntoSortedArrLevels(arr) 236 | } 237 | ) 238 | } 239 | 240 | private fun quickSort( 241 | arr: Array 242 | ) = viewModelScope.launch { 243 | quickSort.sort( 244 | arr, 245 | iChange = { i -> 246 | 247 | }, 248 | jChange = { j -> 249 | 250 | }, 251 | onSwap = { arr -> 252 | addArrayIntoSortedArrLevels(arr) 253 | } 254 | ) 255 | } 256 | 257 | private fun bubbleSort( 258 | arr: Array 259 | ) = viewModelScope.launch { 260 | bubbleSort.sort( 261 | arr, 262 | iChange = { i -> 263 | 264 | }, 265 | jChange = { j -> 266 | 267 | }, 268 | onSwap = { arr -> 269 | addArrayIntoSortedArrLevels(arr) 270 | } 271 | ) 272 | } 273 | 274 | private fun copyArrayIntoArrState(arr: IntArray, size: Int) { 275 | val copy = Array(size) { 0 } 276 | arr.forEachIndexed { i, index -> 277 | copy[i] = index 278 | } 279 | arrState.value = copy 280 | } 281 | 282 | private fun addArrayIntoSortedArrLevels(arr: Array) { 283 | sortedArrLevels.add(arr.toList()) 284 | } 285 | 286 | 287 | private fun deleteItemFromArray(index: Int) { 288 | //Delete the element and copy the new array to the arrState array 289 | val arrWithTheDeletedElement = ArrayOperations.deleteArrayElement(arrState.value, index) 290 | copyArrayIntoArrState(arrWithTheDeletedElement.toIntArray(), arrWithTheDeletedElement.size) 291 | refactorSortedArrayLevels() 292 | } 293 | 294 | private fun updateItemInTheArray(index: Int, value: Int) { 295 | Log.d("test", "updating") 296 | val tempArr = arrState.value.clone() 297 | tempArr[index] = value 298 | 299 | copyArrayIntoArrState(tempArr.toIntArray(), tempArr.size) 300 | refactorSortedArrayLevels() 301 | } 302 | 303 | private fun refactorSortedArrayLevels() { 304 | //Restore the sortedArrayLevels because we have already changed an element 305 | //and we resort the new arrState array 306 | sortedArrLevels = ArrayList() 307 | insertionSort(arrState.value.clone()) 308 | 309 | //We don't pass the original arrState instead we pass a clone of it 310 | } 311 | 312 | fun s(){} 313 | 314 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/algorithmsvisualizer/AlgorithmVisualizerScreen.kt: -------------------------------------------------------------------------------- 1 | package com.example.algorithmsvisualizer 2 | 3 | import android.util.Log 4 | import androidx.compose.animation.core.animateIntAsState 5 | import androidx.compose.animation.core.tween 6 | import androidx.compose.foundation.background 7 | import androidx.compose.foundation.clickable 8 | import androidx.compose.foundation.layout.* 9 | import androidx.compose.foundation.rememberScrollState 10 | import androidx.compose.foundation.shape.RoundedCornerShape 11 | import androidx.compose.foundation.text.KeyboardOptions 12 | import androidx.compose.foundation.text.selection.SelectionContainer 13 | import androidx.compose.foundation.verticalScroll 14 | import androidx.compose.material.* 15 | import androidx.compose.material.icons.Icons 16 | import androidx.compose.material.icons.filled.Add 17 | import androidx.compose.material.icons.filled.ArrowBack 18 | import androidx.compose.runtime.* 19 | import androidx.compose.ui.Alignment 20 | import androidx.compose.ui.Alignment.Companion.Bottom 21 | import androidx.compose.ui.Alignment.Companion.BottomCenter 22 | import androidx.compose.ui.Alignment.Companion.Center 23 | import androidx.compose.ui.Alignment.Companion.CenterHorizontally 24 | import androidx.compose.ui.Modifier 25 | import androidx.compose.ui.draw.clip 26 | import androidx.compose.ui.draw.shadow 27 | import androidx.compose.ui.graphics.Color 28 | import androidx.compose.ui.res.painterResource 29 | import androidx.compose.ui.text.TextStyle 30 | import androidx.compose.ui.text.font.FontWeight 31 | import androidx.compose.ui.text.input.KeyboardType 32 | import androidx.compose.ui.unit.dp 33 | import androidx.compose.ui.unit.sp 34 | import androidx.hilt.navigation.compose.hiltViewModel 35 | import androidx.navigation.NavController 36 | import com.example.algorithmsvisualizer.data.model.AlgorithmCode 37 | import com.example.algorithmsvisualizer.events.AppEvents 38 | import com.example.algorithmsvisualizer.ui.theme.LightGrayBlue 39 | import com.example.algorithmsvisualizer.ui.theme.WorkSans 40 | import com.example.algorithmsvisualizer.viewmodel.AlgorithmViewModel 41 | import com.example.algorithmsvisualizer.viewmodel.ScreensViewModel 42 | import com.ireward.htmlcompose.HtmlText 43 | 44 | @Composable 45 | fun AlgorithmVisualizerScreen( 46 | algorithmId: Int, 47 | screenViewModel: ScreensViewModel, 48 | algorithmViewModel: AlgorithmViewModel = hiltViewModel(), 49 | navController: NavController, 50 | ) { 51 | 52 | 53 | val levelList = algorithmViewModel.sortedArrLevels 54 | 55 | 56 | val algorithm = screenViewModel.algorithmState.value 57 | 58 | LaunchedEffect(key1 = true){ 59 | algorithmViewModel.onAction(AppEvents.Initialization(algorithm)) 60 | } 61 | 62 | val codes = screenViewModel.algorithmCodes.value 63 | 64 | 65 | val arr = algorithmViewModel.arrState.value 66 | 67 | 68 | 69 | var shouldStartAlgorithm by remember { 70 | mutableStateOf(false) 71 | } 72 | 73 | var onSortingFinish = algorithmViewModel.onSortingFinish.value 74 | 75 | 76 | if (onSortingFinish) { 77 | shouldStartAlgorithm = false 78 | } 79 | 80 | Scaffold( 81 | modifier = Modifier.fillMaxSize(), 82 | topBar = { 83 | TopBar(name = algorithm.name, timeComplexity = algorithm.timeComplexity) { 84 | navController.navigateUp() 85 | } 86 | }, 87 | backgroundColor = MaterialTheme.colors.background, 88 | bottomBar = { 89 | BottomBar( 90 | modifier = Modifier.fillMaxWidth(), 91 | onPlayPauseClick = { 92 | shouldStartAlgorithm = !shouldStartAlgorithm 93 | 94 | if (shouldStartAlgorithm) { 95 | algorithmViewModel.onAction(AppEvents.SortAlgorithm(algorithm, arr, 850)) 96 | } else 97 | algorithmViewModel.onAction(AppEvents.Pause) 98 | }, 99 | 100 | onNextStepClick = { 101 | if (!shouldStartAlgorithm) { 102 | algorithmViewModel.onAction(AppEvents.NextStep) 103 | 104 | } 105 | }, 106 | onBackStepClick = { 107 | if (!shouldStartAlgorithm) { 108 | algorithmViewModel.onAction(AppEvents.PreviousStep) 109 | } 110 | }, 111 | onSpeedUpClick = { algorithmViewModel.onAction(AppEvents.IncreaseDelay(200)) }, 112 | onSlowDownClick = { algorithmViewModel.onAction(AppEvents.DecreaseDelay(100)) }, 113 | isPlaying = shouldStartAlgorithm 114 | 115 | ) 116 | } 117 | ) { 118 | val bottomPadding = it.calculateBottomPadding() 119 | Column( 120 | modifier = Modifier 121 | .fillMaxSize() 122 | .padding(bottom = bottomPadding) 123 | ) { 124 | VisualizerSection( 125 | modifier = Modifier 126 | .weight(0.4f) 127 | .fillMaxWidth(), 128 | arr, 129 | algorithmViewModel 130 | ) 131 | 132 | TabBarSection( 133 | modifier = Modifier 134 | .fillMaxWidth() 135 | .weight(0.6f), 136 | tabs = listOf( 137 | TabItem(icon = painterResource(id = R.drawable.ic_text), "Description"), 138 | TabItem(icon = painterResource(id = R.drawable.ic_code), "Code"), 139 | ), 140 | code = if (codes.isNotEmpty()) codes.first() else AlgorithmCode("", 0, ""), 141 | algorithm.description 142 | ) 143 | } 144 | 145 | 146 | } 147 | 148 | } 149 | 150 | @Composable 151 | fun VisualizerSection( 152 | modifier: Modifier = Modifier, 153 | elements: Array, 154 | algorithmViewModel: AlgorithmViewModel 155 | // onValueChangeClick: (Int) -> Unit, 156 | ) { 157 | 158 | var arr = elements 159 | 160 | BoxWithConstraints(modifier = modifier, contentAlignment = BottomCenter) { 161 | val maxHeight = constraints.maxHeight 162 | val maxWidth = constraints.maxWidth 163 | 164 | /** 165 | * I tested the app on 1440p phone width and found that there was no space between the items. 166 | * I will handle it by checking if the maxWidth is 1440p then i will increase the space 167 | */ 168 | val itemWidth = remember { 169 | if (maxWidth < 1440) 170 | ((maxWidth / arr.size) / 3.5).toInt() 171 | else 172 | ((maxWidth / arr.size) / 4.5).toInt() 173 | } 174 | 175 | var indexToChange by remember { 176 | mutableStateOf(0) 177 | } 178 | 179 | var shouldShowChangeValueAlert by remember { 180 | mutableStateOf(false) 181 | } 182 | 183 | Row( 184 | modifier = Modifier.fillMaxWidth(), 185 | horizontalArrangement = Arrangement.SpaceEvenly 186 | ) { 187 | var animationDelay = remember { 188 | 0 189 | } 190 | arr.forEachIndexed { index, element -> 191 | ArrayItemReprisentation( 192 | modifier = Modifier.align(Bottom), 193 | height = element, 194 | width = itemWidth, 195 | index = index, 196 | element = element, 197 | animationDelay = animationDelay, 198 | ) { indexClicked -> 199 | indexToChange = indexClicked 200 | shouldShowChangeValueAlert = true 201 | } 202 | animationDelay += 50 203 | } 204 | } 205 | 206 | 207 | if (shouldShowChangeValueAlert) 208 | ChangeElementAlertDialog( 209 | onUpdateClick = { 210 | algorithmViewModel.onAction(AppEvents.UpdateItem(indexToChange,it)) 211 | shouldShowChangeValueAlert = false 212 | 213 | }, 214 | onDelete = { 215 | algorithmViewModel.onAction(AppEvents.DeleteItem(indexToChange)) 216 | shouldShowChangeValueAlert = false 217 | }, 218 | onDismiss = { shouldShowChangeValueAlert = false }, 219 | currentElement = arr[indexToChange], 220 | ) 221 | 222 | 223 | } 224 | } 225 | 226 | @Composable 227 | fun ChangeElementAlertDialog( 228 | modifier: Modifier = Modifier, 229 | onUpdateClick: (Int) -> Unit, 230 | onDelete: (Int) -> Unit, 231 | onDismiss: () -> Unit, 232 | currentElement: Int, 233 | ) { 234 | var number by remember { 235 | mutableStateOf(currentElement) 236 | } 237 | 238 | Box(modifier = modifier) { 239 | AlertDialog( 240 | onDismissRequest = { 241 | onDismiss() 242 | }, 243 | confirmButton = { 244 | TextButton(onClick = { 245 | onUpdateClick(number) 246 | }) { 247 | Text(text = "Update") 248 | } 249 | }, 250 | dismissButton = { 251 | TextButton(onClick = { onDelete(currentElement) }) { 252 | Text(text = "Delete") 253 | } 254 | }, 255 | text = { 256 | Column(modifier = Modifier.align(Center)) { 257 | TextField( 258 | value = number.toString(), 259 | onValueChange = { 260 | number = if (it.isEmpty()) 0 else 261 | it.toInt() 262 | }, 263 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), 264 | colors = TextFieldDefaults.textFieldColors(MaterialTheme.colors.onSurface), 265 | textStyle = TextStyle(color = Color.White) 266 | ) 267 | } 268 | }, 269 | backgroundColor = MaterialTheme.colors.surface, 270 | modifier = Modifier.clip(RoundedCornerShape(10.dp)) 271 | ) 272 | } 273 | 274 | } 275 | 276 | @Composable 277 | fun ArrayItemReprisentation( 278 | modifier: Modifier = Modifier, 279 | animationDelay: Int = 0, 280 | animationDuration: Int = 350, 281 | height: Int, 282 | width: Int, 283 | index: Int, 284 | element: Int, 285 | onClick: (Int) -> Unit, 286 | ) { 287 | 288 | var isEnabled by remember { 289 | mutableStateOf(false) 290 | } 291 | 292 | 293 | val boxHeight = animateIntAsState( 294 | targetValue = if (!isEnabled) 0 else height, animationSpec = tween( 295 | durationMillis = animationDuration, 296 | delayMillis = animationDelay 297 | ) 298 | ) 299 | 300 | LaunchedEffect(key1 = true) { 301 | isEnabled = true 302 | } 303 | 304 | 305 | Column(modifier = modifier) { 306 | Text( 307 | text = element.toString(), 308 | modifier = Modifier 309 | .align(CenterHorizontally), 310 | color = Color.White, 311 | fontSize = (width / 3).sp, 312 | ) 313 | Box(modifier = Modifier 314 | .height(boxHeight.value.dp) 315 | .width(width.dp) 316 | .background(LightGrayBlue) 317 | .clickable { onClick(index) } 318 | ) 319 | 320 | } 321 | 322 | } 323 | 324 | @Composable 325 | fun TabBarSection( 326 | modifier: Modifier = Modifier, 327 | tabs: List, 328 | code: AlgorithmCode, 329 | algorithmDescription: String, 330 | ) { 331 | 332 | var selectedTab by remember { 333 | mutableStateOf(1) 334 | } 335 | 336 | Column(modifier = modifier) { 337 | Column( 338 | modifier = Modifier 339 | .fillMaxWidth() 340 | .height(55.dp) 341 | ) { 342 | 343 | TabRow( 344 | selectedTabIndex = selectedTab, 345 | backgroundColor = MaterialTheme.colors.surface, 346 | contentColor = Color.Transparent, 347 | modifier = Modifier.fillMaxSize() 348 | ) { 349 | tabs.forEachIndexed { i, tab -> 350 | TabItem(tab = tab, onClick = { selectedTab = i }, isSelected = i == selectedTab) 351 | } 352 | } 353 | } 354 | Column( 355 | modifier = Modifier.verticalScroll(rememberScrollState()), 356 | verticalArrangement = Arrangement.Top 357 | ) { 358 | SelectionContainer { 359 | HtmlText( 360 | text = if (selectedTab == 0) algorithmDescription.trim() else code.code.trim(), 361 | modifier = Modifier 362 | .fillMaxSize() 363 | .padding(start = 10.dp, end = 10.dp, bottom = 10.dp, top = 10.dp), 364 | ) 365 | } 366 | } 367 | 368 | } 369 | 370 | } 371 | 372 | @Composable 373 | fun TabItem( 374 | tab: TabItem, 375 | modifier: Modifier = Modifier, 376 | onClick: () -> Unit, 377 | isSelected: Boolean, 378 | ) { 379 | Box(modifier = modifier.clickable { onClick() }, contentAlignment = Alignment.Center) { 380 | 381 | Row( 382 | horizontalArrangement = Arrangement.SpaceEvenly, 383 | verticalAlignment = Alignment.CenterVertically, 384 | ) { 385 | Icon( 386 | painter = tab.icon, contentDescription = null, 387 | tint = if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface, 388 | modifier = Modifier.size(25.dp) 389 | ) 390 | 391 | Text( 392 | text = tab.title, 393 | color = if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface, 394 | fontFamily = WorkSans, 395 | fontWeight = FontWeight.Medium, 396 | fontSize = 17.sp 397 | ) 398 | 399 | 400 | } 401 | Box( 402 | modifier = Modifier 403 | .fillMaxWidth() 404 | .height(4.dp) 405 | .align(BottomCenter) 406 | .background(if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface) 407 | ) 408 | } 409 | 410 | } 411 | 412 | 413 | @Composable 414 | fun TopBar( 415 | modifier: Modifier = Modifier, 416 | name: String, 417 | timeComplexity: String, 418 | onBackClick: () -> Unit, 419 | ) { 420 | 421 | TopAppBar( 422 | modifier = Modifier.fillMaxWidth(), 423 | backgroundColor = MaterialTheme.colors.background, 424 | elevation = 0.dp 425 | ) { 426 | Row( 427 | modifier = Modifier.fillMaxWidth(), 428 | horizontalArrangement = Arrangement.SpaceBetween, 429 | verticalAlignment = Alignment.CenterVertically 430 | ) { 431 | 432 | IconButton(onClick = { onBackClick() }) { 433 | Icon( 434 | imageVector = Icons.Default.ArrowBack, 435 | contentDescription = "Back", 436 | tint = MaterialTheme.colors.onSurface, 437 | modifier = Modifier.size(30.dp) 438 | ) 439 | } 440 | 441 | Text( 442 | text = name, 443 | style = MaterialTheme.typography.h2, 444 | color = Color.White, 445 | fontSize = 18.sp 446 | ) 447 | 448 | Text( 449 | text = timeComplexity, 450 | style = MaterialTheme.typography.h2, 451 | color = MaterialTheme.colors.secondaryVariant, 452 | fontSize = 18.sp, 453 | modifier = Modifier.padding(end = 10.dp) 454 | ) 455 | 456 | 457 | } 458 | } 459 | } 460 | 461 | @Composable 462 | fun BottomBar( 463 | modifier: Modifier = Modifier, 464 | onPlayPauseClick: () -> Unit, 465 | onNextStepClick: () -> Unit, 466 | onBackStepClick: () -> Unit, 467 | onSpeedUpClick: () -> Unit, 468 | onSlowDownClick: () -> Unit, 469 | isPlaying: Boolean = false, 470 | backgroundColor: Color = MaterialTheme.colors.surface, 471 | ) { 472 | 473 | BottomAppBar( 474 | backgroundColor = backgroundColor, 475 | modifier = Modifier.height(75.dp) 476 | ) { 477 | Row( 478 | horizontalArrangement = Arrangement.SpaceEvenly, 479 | verticalAlignment = Alignment.CenterVertically, 480 | modifier = modifier 481 | ) { 482 | 483 | IconButton(onClick = { onSlowDownClick() }) { 484 | Icon( 485 | painter = painterResource(id = R.drawable.ic_minus), 486 | contentDescription = null, 487 | tint = MaterialTheme.colors.onSurface, 488 | modifier = Modifier.size(16.dp) 489 | ) 490 | } 491 | 492 | IconButton(onClick = { 493 | onPlayPauseClick() 494 | }) { 495 | Icon( 496 | painter = if (!isPlaying) painterResource(id = R.drawable.ic_play).also { 497 | } else painterResource( 498 | id = R.drawable.ic_pause 499 | ), 500 | contentDescription = null, 501 | tint = Color.White, 502 | ) 503 | } 504 | 505 | IconButton(onClick = { onSpeedUpClick() }) { 506 | Icon( 507 | imageVector = Icons.Default.Add, 508 | contentDescription = null, 509 | tint = MaterialTheme.colors.onSurface 510 | ) 511 | } 512 | 513 | IconButton(onClick = { onBackStepClick() }) { 514 | Icon( 515 | painter = painterResource(id = R.drawable.ic_left_arrow), 516 | contentDescription = null, 517 | tint = MaterialTheme.colors.onSurface, 518 | modifier = Modifier.size(19.dp) 519 | ) 520 | } 521 | 522 | Button( 523 | onClick = { onNextStepClick() }, 524 | shape = RoundedCornerShape(7.dp), 525 | colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.secondary), 526 | modifier = Modifier.shadow(3.dp) 527 | ) { 528 | Row( 529 | horizontalArrangement = Arrangement.spacedBy(5.dp), 530 | modifier = Modifier.fillMaxHeight(0.5f), 531 | verticalAlignment = Alignment.CenterVertically 532 | ) { 533 | Text( 534 | text = "Next Step", 535 | style = MaterialTheme.typography.h3, 536 | color = MaterialTheme.colors.surface, 537 | fontWeight = FontWeight.Medium, 538 | fontSize = 18.sp, 539 | ) 540 | 541 | Icon( 542 | painter = painterResource(id = R.drawable.ic_right_arrow), 543 | contentDescription = null, 544 | tint = MaterialTheme.colors.surface, 545 | modifier = Modifier.size(19.dp) 546 | ) 547 | 548 | } 549 | } 550 | } 551 | } 552 | 553 | } --------------------------------------------------------------------------------