├── 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 | 
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 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 1657291245262
30 |
31 |
32 | 1657291245262
33 |
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 | }
--------------------------------------------------------------------------------