├── .gitignore
├── .idea
├── .gitignore
├── .name
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── release
│ ├── app-release.apk
│ └── output-metadata.json
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── wenull
│ │ └── mathyourbrain
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── wenull
│ │ │ └── mathyourbrain
│ │ │ ├── MYBApp.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── data
│ │ │ ├── local
│ │ │ │ ├── AppDAO.kt
│ │ │ │ ├── AppDB.kt
│ │ │ │ ├── Converters.kt
│ │ │ │ └── entities
│ │ │ │ │ ├── GameX.kt
│ │ │ │ │ └── User.kt
│ │ │ ├── prefrences
│ │ │ │ └── UserPrefrences.kt
│ │ │ └── remote
│ │ │ │ ├── AppService.kt
│ │ │ │ └── AuthService.kt
│ │ │ ├── di
│ │ │ ├── DatabaseModule.kt
│ │ │ ├── PrefrencesModule.kt
│ │ │ ├── RepositoryModule.kt
│ │ │ └── RetrofitModule.kt
│ │ │ ├── models
│ │ │ ├── basic
│ │ │ │ ├── ErrorResponse.kt
│ │ │ │ ├── Game.kt
│ │ │ │ ├── Question.kt
│ │ │ │ └── User.kt
│ │ │ ├── requests
│ │ │ │ ├── CreateGameRequest.kt
│ │ │ │ ├── SigninRequest.kt
│ │ │ │ ├── SignupRequest.kt
│ │ │ │ └── UpdateGameRequest.kt
│ │ │ ├── response
│ │ │ │ ├── CreateGameResponse.kt
│ │ │ │ ├── GetAllAvatarsResponse.kt
│ │ │ │ ├── GetLeaderboardResponse.kt
│ │ │ │ ├── GetLeaderboardResponseItem.kt
│ │ │ │ ├── GetUserDataResponse.kt
│ │ │ │ ├── Question.kt
│ │ │ │ ├── SigninResponse.kt
│ │ │ │ ├── SignupResponse.kt
│ │ │ │ └── UpdateGameResponse.kt
│ │ │ └── utils
│ │ │ │ └── DataState.kt
│ │ │ ├── repo
│ │ │ ├── AppRepository.kt
│ │ │ └── base
│ │ │ │ └── BaseRespository.kt
│ │ │ ├── ui
│ │ │ ├── components
│ │ │ │ ├── Header.kt
│ │ │ │ ├── LoadingDialog.kt
│ │ │ │ ├── Logo.kt
│ │ │ │ ├── MemojiSelector.kt
│ │ │ │ ├── TextInput.kt
│ │ │ │ ├── Timer.kt
│ │ │ │ └── gamescreen
│ │ │ │ │ ├── GameCompleted.kt
│ │ │ │ │ ├── Option.kt
│ │ │ │ │ └── ResignAlertDialog.kt
│ │ │ ├── screens
│ │ │ │ ├── auth
│ │ │ │ │ ├── SigninScreen.kt
│ │ │ │ │ └── SignupScreen.kt
│ │ │ │ ├── main
│ │ │ │ │ ├── GameScreen.kt
│ │ │ │ │ ├── HomeScreen.kt
│ │ │ │ │ └── LeaderBoard.kt
│ │ │ │ └── splash
│ │ │ │ │ └── SplashScreen.kt
│ │ │ └── theme
│ │ │ │ ├── Color.kt
│ │ │ │ ├── Shape.kt
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Type.kt
│ │ │ ├── utils
│ │ │ └── Indicator.kt
│ │ │ └── viewmodels
│ │ │ └── MainViewModel.kt
│ └── res
│ │ ├── drawable
│ │ ├── down.xml
│ │ ├── google_classroom.png
│ │ ├── ic_icon.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_logo.xml
│ │ ├── ic_warning.xml
│ │ ├── memoji.png
│ │ ├── pi.png
│ │ ├── plus__.png
│ │ └── star.xml
│ │ ├── font
│ │ ├── circularstdblack.otf
│ │ ├── circularstdblackitalic.otf
│ │ ├── circularstdbold.otf
│ │ ├── circularstdbolditalic.otf
│ │ ├── circularstdbook.otf
│ │ ├── circularstdbookitalic.otf
│ │ ├── circularstdlight.otf
│ │ ├── circularstdlightitalic.otf
│ │ ├── circularstdmedium.otf
│ │ └── circularstdmediumitalic.otf
│ │ ├── mipmap-anydpi-v26
│ │ └── ic_launcher.xml
│ │ ├── raw
│ │ └── loading.json
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── wenull
│ └── mathyourbrain
│ └── ExampleUnitTest.kt
├── build.gradle
├── file cover.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── mvvm.png
├── settings.gradle
└── shot1.png
/.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 |
17 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Math Your Brain
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | xmlns:android
18 |
19 | ^$
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | xmlns:.*
29 |
30 | ^$
31 |
32 |
33 | BY_NAME
34 |
35 |
36 |
37 |
38 |
39 |
40 | .*:id
41 |
42 | http://schemas.android.com/apk/res/android
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | .*:name
52 |
53 | http://schemas.android.com/apk/res/android
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | name
63 |
64 | ^$
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | style
74 |
75 | ^$
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | .*
85 |
86 | ^$
87 |
88 |
89 | BY_NAME
90 |
91 |
92 |
93 |
94 |
95 |
96 | .*
97 |
98 | http://schemas.android.com/apk/res/android
99 |
100 |
101 | ANDROID_ATTRIBUTE_ORDER
102 |
103 |
104 |
105 |
106 |
107 |
108 | .*
109 |
110 | .*
111 |
112 |
113 | BY_NAME
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | # Math-Your-Brain
6 | Math Your Brain is a math game built using Jetpack Compose and Modern MVVM Architecture. I built this so that programmers learning Jetpack Compose Can use this repository as a learning material for Jetpack Compose.
7 |
8 |
9 |
10 | ***Try latest Math Your Brain app apk from below 👇***
11 |
12 | [](https://github.com/Somnath6646/Math-Your-Brain/releases/download/APKRelease/myb.apk)
13 |
14 |
15 |
16 | ## UI Design 🎨
17 |
18 | ***Click to View Math Your Brain app Design from below 👇***
19 |
20 | [](https://www.figma.com/file/yRgrdPy6lJFXmV7oLGn7pg/Math-Your-Brain?node-id=0%3A1)
21 |
22 |
23 |
24 | ### Backend Code
25 |
26 | ***Click to View Math Your Brain app Backend Code from below 👇***
27 |
28 | [](https://github.com/rounaksingh1694/myb-backend)
29 |
30 |
31 |
32 |
33 | ### TO-DOs
34 |
35 | - [ ] Add Logout
36 | - [ ] Make Profile Screen as in the figma file
37 | - [ ] Lessons Section
38 |
39 |
40 | ## Built with 🛠
41 |
42 | - [Kotlin](https://kotlinlang.org/) - First class and official programming language for Android development.
43 | - [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) - For asynchronous and more..
44 | - [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) - A cold asynchronous data stream that sequentially emits values and completes normally or with an exception.
45 | - [Android Architecture Components](https://developer.android.com/topic/libraries/architecture) - Collection of libraries that help you design robust, testable, and maintainable apps.
46 | - [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) - Data objects that notify views when the underlying database changes.
47 | - [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) - Stores UI-related data that isn't destroyed on UI changes.
48 | - [ViewBinding](https://developer.android.com/topic/libraries/view-binding) - Generates a binding class for each XML layout file present in that module and allows you to more easily write code that interacts with views.
49 | - [Room](https://developer.android.com/topic/libraries/architecture/room) - SQLite object mapping library.
50 | - [Navigation Component](https://developer.android.com/guide/navigation/navigation-getting-started) Navigation refers to the interactions that allow users to navigate across, into, and back out from the different pieces of content within your app.
51 | - [Safe args](https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args) - Gradle plugin that provides type safety when navigating and passing data between destinations.
52 | - [DataStore](https://developer.android.com/topic/libraries/architecture/datastore) - Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers.
53 | - [Dependency Injection](https://developer.android.com/training/dependency-injection) -
54 | - [Hilt-Dagger](https://dagger.dev/hilt/) - Standard library to incorporate Dagger dependency injection into an Android application.
55 | - [Hilt-ViewModel](https://developer.android.com/training/dependency-injection/hilt-jetpack) - DI for injecting `ViewModel`.
56 | - [Retrofit](https://square.github.io/retrofit/) - A type-safe HTTP client for Android and Java.
57 | - [Jetpack Compose UI Toolkit](https://developer.android.com/jetpack/compose) - Modern UI development toolkit.
58 | - [Accompanist](https://google.github.io/accompanist/) - Accompanist is a group of libraries that aim to supplement Jetpack Compose with features that are commonly required by developers but not yet available.
59 | - [Coil-compose](https://coil-kt.github.io/coil/compose/) - An image loading library for Android backed by Kotlin Coroutines.
60 |
61 | ## Architecture
62 |
63 | This app uses [_**MVVM (Model View View-Model)**_](https://developer.android.com/jetpack/docs/guide#recommended-app-arch) architecture.
64 | 
65 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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 32
10 |
11 | defaultConfig {
12 | applicationId "com.wenull.mathyourbrain"
13 | minSdk 24
14 | targetSdk 32
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 true
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 | buildFeatures {
39 | compose true
40 | }
41 | composeOptions {
42 | kotlinCompilerExtensionVersion compose_version
43 | }
44 | packagingOptions {
45 | resources {
46 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
47 | }
48 | }
49 | }
50 |
51 | dependencies {
52 |
53 | implementation 'androidx.core:core-ktx:1.7.0'
54 | implementation "androidx.compose.ui:ui:$compose_version"
55 | implementation "androidx.compose.material:material:$compose_version"
56 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
57 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
58 | implementation 'androidx.activity:activity-compose:1.3.1'
59 | implementation 'androidx.room:room-ktx:2.3.0'
60 | testImplementation 'junit:junit:4.13.2'
61 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
62 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
63 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
64 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
65 | debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
66 | implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
67 |
68 | implementation "androidx.datastore:datastore-preferences:1.0.0"
69 |
70 | implementation "com.google.dagger:hilt-android:2.38.1"
71 | kapt "com.google.dagger:hilt-compiler:2.38.1"
72 |
73 | def nav_version = "2.4.2"
74 | implementation "androidx.navigation:navigation-compose:$nav_version"
75 |
76 | def retrofit_version = "2.9.0"
77 | implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
78 | implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
79 |
80 | def okhttp_interceptor ="4.9.1"
81 |
82 | implementation("com.squareup.okhttp3:logging-interceptor:$okhttp_interceptor")
83 | // define a BOM and its version
84 | implementation(platform("com.squareup.okhttp3:okhttp-bom:$okhttp_interceptor"))
85 |
86 | // define any required OkHttp artifacts without version
87 | implementation("com.squareup.okhttp3:okhttp")
88 |
89 | implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1"
90 |
91 |
92 | def lifecycle_version = "2.5.0-rc01"
93 | def arch_version = "2.1.0"
94 |
95 | // ViewModel
96 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
97 | // ViewModel utilities for Compose
98 | implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
99 | // LiveData
100 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
101 | // Lifecycles only (without ViewModel or LiveData)
102 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
103 |
104 | // Saved state module for ViewModel
105 | implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
106 |
107 | // Annotation processor
108 | kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
109 |
110 |
111 | def accompanist_version ="0.23.1"
112 |
113 | implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist_version"
114 |
115 | implementation "com.google.accompanist:accompanist-insets:$accompanist_version"
116 | // If using insets-ui
117 | implementation "com.google.accompanist:accompanist-insets-ui:$accompanist_version"
118 |
119 | implementation "com.google.accompanist:accompanist-navigation-animation:$accompanist_version"
120 |
121 | implementation "com.google.accompanist:accompanist-swiperefresh:$accompanist_version"
122 |
123 |
124 | def room_version = "2.3.0"
125 | implementation "androidx.room:room-ktx:$room_version"
126 | implementation "androidx.room:room-runtime:$room_version"
127 | kapt "androidx.room:room-compiler:$room_version"
128 |
129 |
130 |
131 | implementation "io.coil-kt:coil-compose:2.1.0"
132 |
133 | def lottieVersion = "5.0.3"
134 | implementation "com.airbnb.android:lottie-compose:$lottieVersion"
135 |
136 | }
137 |
138 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.wenull.mathyourbrain.models.*{ *; }
2 | -dontwarn okio.**
3 | -dontwarn javax.annotation.Nullable
4 | -dontwarn javax.annotation.ParametersAreNonnullByDefault
5 |
6 | -keepattributes Signature
7 | # For using GSON @Expose annotation
8 | -keepattributes *Annotation*
9 |
10 | #-keep class com.google.gson.stream.** { *; }
--------------------------------------------------------------------------------
/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/release/app-release.apk
--------------------------------------------------------------------------------
/app/release/output-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "artifactType": {
4 | "type": "APK",
5 | "kind": "Directory"
6 | },
7 | "applicationId": "com.wenull.mathyourbrain",
8 | "variantName": "release",
9 | "elements": [
10 | {
11 | "type": "SINGLE",
12 | "filters": [],
13 | "attributes": [],
14 | "versionCode": 1,
15 | "versionName": "1.0",
16 | "outputFile": "app-release.apk"
17 | }
18 | ],
19 | "elementType": "File"
20 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/wenull/mathyourbrain/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain
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.wenull.mathyourbrain", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/MYBApp.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | @HiltAndroidApp
7 | class MYBApp: Application() {
8 |
9 | override fun onCreate() {
10 | super.onCreate()
11 | }
12 |
13 | companion object{
14 | val token: String? = null
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain
2 |
3 | import android.os.Build
4 | import android.os.Bundle
5 | import android.widget.Toast
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import androidx.activity.viewModels
9 | import androidx.annotation.RequiresApi
10 | import androidx.compose.animation.ExperimentalAnimationApi
11 | import androidx.compose.animation.core.tween
12 | import androidx.compose.animation.slideInHorizontally
13 | import androidx.compose.animation.slideOutHorizontally
14 | import androidx.compose.foundation.ExperimentalFoundationApi
15 | import androidx.compose.foundation.layout.fillMaxSize
16 | import androidx.compose.material.MaterialTheme
17 | import androidx.compose.material.Surface
18 | import androidx.compose.material.Text
19 | import androidx.compose.runtime.Composable
20 | import androidx.compose.runtime.SideEffect
21 | import androidx.compose.runtime.getValue
22 | import androidx.compose.runtime.livedata.observeAsState
23 | import androidx.compose.runtime.remember
24 | import androidx.compose.ui.Modifier
25 | import androidx.compose.ui.graphics.Color
26 | import androidx.compose.ui.tooling.preview.Preview
27 | import androidx.compose.ui.unit.ExperimentalUnitApi
28 | import androidx.core.view.WindowCompat
29 | import androidx.lifecycle.Observer
30 | import com.google.accompanist.insets.ProvideWindowInsets
31 | import com.google.accompanist.insets.systemBarsPadding
32 | import com.google.accompanist.navigation.animation.AnimatedNavHost
33 | import com.google.accompanist.navigation.animation.composable
34 | import com.google.accompanist.navigation.animation.rememberAnimatedNavController
35 | import com.google.accompanist.systemuicontroller.SystemUiController
36 | import com.google.accompanist.systemuicontroller.rememberSystemUiController
37 | import com.wenull.mathyourbrain.ui.components.LoadingDialog
38 | import com.wenull.mathyourbrain.ui.screens.auth.SignupScreen
39 | import com.wenull.mathyourbrain.ui.screens.auth.SigninScreen
40 | import com.wenull.mathyourbrain.ui.screens.main.GameScreen
41 | import com.wenull.mathyourbrain.ui.screens.main.HomeScreen
42 | import com.wenull.mathyourbrain.ui.screens.main.LeaderBoard
43 | import com.wenull.mathyourbrain.ui.screens.splash.SplashScreen
44 | import com.wenull.mathyourbrain.ui.theme.MathYourBrainTheme
45 | import com.wenull.mathyourbrain.ui.theme.SplashTheme
46 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
47 | import dagger.hilt.android.AndroidEntryPoint
48 |
49 |
50 | const val Splash = "splash"
51 | const val SignUp = "signup"
52 | const val SignIn = "signin"
53 | const val HomeScreen = "homescreen"
54 | const val GameScreen = "gamescreen"
55 | const val LeaderBoard = "leaderboard"
56 |
57 | @ExperimentalAnimationApi
58 | @ExperimentalFoundationApi
59 | @RequiresApi(Build.VERSION_CODES.N)
60 | @ExperimentalUnitApi
61 | @AndroidEntryPoint
62 | class MainActivity : ComponentActivity() {
63 |
64 | val viewModel: MainViewModel by viewModels()
65 |
66 |
67 | @OptIn(ExperimentalAnimationApi::class)
68 | override fun onCreate(savedInstanceState: Bundle?) {
69 | super.onCreate(savedInstanceState)
70 |
71 | viewModel.accessToken.observe(this, Observer {
72 | // Toast.makeText(this, "$it", Toast.LENGTH_SHORT).show()
73 | })
74 | viewModel.users.observe(this, Observer {
75 | // Toast.makeText(this, "$it", Toast.LENGTH_SHORT).show()
76 | })
77 | viewModel.toast.observe(this, Observer {
78 | it.getContentIfNotHandled().let {
79 | Toast.makeText(this, "$it", Toast.LENGTH_SHORT).show()
80 | }
81 | })
82 |
83 | if(BuildConfig.DEBUG){
84 | viewModel.debugToast.observe(this, Observer {
85 | it.getContentIfNotHandled().let {
86 | Toast.makeText(this, "$it", Toast.LENGTH_SHORT).show()
87 | }
88 | })
89 | }
90 |
91 |
92 | WindowCompat.setDecorFitsSystemWindows(window, false)
93 | setContent {
94 | val systemUiController = rememberSystemUiController()
95 | val useDarkIcons = MaterialTheme.colors.isLight
96 | SideEffect {
97 | systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = useDarkIcons)
98 | }
99 | ProvideWindowInsets {
100 | val users by viewModel.users.observeAsState(null)
101 | if(users != null)
102 | {if( users!!.size >0) {
103 | val user = users?.get(0);
104 | if (user != null) {
105 | viewModel.getUser(user)
106 | }
107 | }
108 | }
109 |
110 | Main(systemUiController)
111 | }
112 | }
113 | }
114 |
115 | @ExperimentalAnimationApi
116 | @ExperimentalFoundationApi
117 | @RequiresApi(Build.VERSION_CODES.N)
118 | @ExperimentalUnitApi
119 | @Composable
120 | fun Main(systemUiController: SystemUiController) {
121 | val modifier = Modifier.systemBarsPadding()
122 |
123 | val entryAnim = slideInHorizontally(initialOffsetX = { 1000 }, animationSpec = tween(700))
124 | val exitAnim = slideOutHorizontally(targetOffsetX = { -1000 }, animationSpec = tween(700))
125 |
126 |
127 | Surface(color = MaterialTheme.colors.background, ) {
128 | val navController = rememberAnimatedNavController()
129 |
130 | AnimatedNavHost(navController = navController, startDestination = Splash) {
131 |
132 | composable(Splash, enterTransition = {entryAnim},
133 | exitTransition = {exitAnim},
134 | popEnterTransition = {entryAnim},
135 | popExitTransition = {exitAnim}) {
136 | SplashTheme {
137 | val useDarkIcons = MaterialTheme.colors.isLight
138 | SideEffect {
139 | systemUiController.setSystemBarsColor(Color.Black, darkIcons = useDarkIcons)
140 | }
141 | SplashScreen(systemUiController,
142 | navController = navController, viewModel =
143 | viewModel
144 | )
145 | }
146 | }
147 | composable(
148 | SignIn, enterTransition = {entryAnim},
149 | exitTransition = {exitAnim},
150 | popEnterTransition = {entryAnim},
151 | popExitTransition = {exitAnim}) {
152 | val isVisible = remember{ viewModel.isLoading }
153 | if(isVisible.value){
154 | LoadingDialog()
155 | }
156 | val useDarkIcons = MaterialTheme.colors.isLight
157 | SideEffect {
158 | systemUiController.isSystemBarsVisible = true
159 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
160 | }
161 | MathYourBrainTheme {
162 | SideEffect {
163 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
164 | }
165 | SigninScreen(navController = navController, viewModel = viewModel)
166 | }
167 | }
168 |
169 | composable(
170 | SignUp, enterTransition = {entryAnim},
171 | exitTransition = {exitAnim},
172 | popEnterTransition = {entryAnim},
173 | popExitTransition = {exitAnim}) {
174 | val isVisible = remember{ viewModel.isLoading }
175 | if(isVisible.value){
176 | LoadingDialog()
177 | }
178 | val useDarkIcons = MaterialTheme.colors.isLight
179 | SideEffect {
180 | systemUiController.isSystemBarsVisible = true
181 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
182 | }
183 | MathYourBrainTheme{
184 | SideEffect {
185 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
186 | }
187 | SignupScreen(navController = navController, viewModel = viewModel)
188 | }
189 | }
190 |
191 | composable(
192 | HomeScreen, enterTransition = {entryAnim},
193 | exitTransition = {exitAnim},
194 | popEnterTransition = {entryAnim},
195 | popExitTransition = {exitAnim}) {
196 | val useDarkIcons = MaterialTheme.colors.isLight
197 | SideEffect {
198 | systemUiController.isSystemBarsVisible = true
199 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
200 | }
201 | val isVisible = remember{ viewModel.isLoading }
202 | if(isVisible.value){
203 | LoadingDialog()
204 | }
205 | MathYourBrainTheme{
206 | HomeScreen(navController, viewModel, modifier, systemUiController)
207 | }
208 | }
209 |
210 |
211 | composable(
212 | GameScreen, enterTransition = {entryAnim},
213 | exitTransition = {exitAnim},
214 | popEnterTransition = {entryAnim},
215 | popExitTransition = {exitAnim}) {
216 | val useDarkIcons = MaterialTheme.colors.isLight
217 | SideEffect {
218 | systemUiController.isSystemBarsVisible = true
219 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
220 | }
221 | val isVisible = remember{ viewModel.isLoading }
222 | if(isVisible.value){
223 | LoadingDialog()
224 | }
225 | MathYourBrainTheme{
226 | GameScreen(navController, viewModel, modifier, systemUiController)
227 | }
228 | }
229 | composable(
230 | LeaderBoard, enterTransition = {entryAnim},
231 | exitTransition = {exitAnim},
232 | popEnterTransition = {entryAnim},
233 | popExitTransition = {exitAnim}) {
234 | val useDarkIcons = MaterialTheme.colors.isLight
235 | SideEffect {
236 | systemUiController.isSystemBarsVisible = true
237 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
238 | }
239 | val isVisible = remember{ viewModel.isLoading }
240 | if(isVisible.value){
241 | LoadingDialog()
242 | }
243 | MathYourBrainTheme{
244 | LeaderBoard(navController, viewModel, modifier, systemUiController)
245 | }
246 | }
247 |
248 |
249 | }
250 | }
251 | }
252 |
253 | }
254 |
255 |
256 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/local/AppDAO.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.local
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy
7 | import androidx.room.Query
8 | import androidx.room.RoomMasterTable.TABLE_NAME
9 | import com.wenull.mathyourbrain.data.local.entities.User
10 |
11 | @Dao
12 | interface AppDAO {
13 |
14 | @Insert(onConflict = OnConflictStrategy.REPLACE)
15 | suspend fun insertUser(user: User): Long
16 |
17 | @Query("SELECT * FROM ${User.TABLE_NAME} ")
18 | fun getUserFromDB(): LiveData>
19 |
20 | @Query("DELETE FROM ${User.TABLE_NAME} ")
21 | fun deleteAll()
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/local/AppDB.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.local
2 |
3 |
4 | import androidx.room.Database
5 | import androidx.room.RoomDatabase
6 | import androidx.room.TypeConverters
7 | import com.wenull.mathyourbrain.data.local.entities.User
8 |
9 | @Database(entities = [User::class], version = 1, exportSchema = false)
10 | @TypeConverters(Converters::class)
11 | abstract class AppDB : RoomDatabase() {
12 |
13 | abstract fun appDao(): AppDAO
14 |
15 | companion object {
16 | const val DATABASE_NAME = "resapp_database"
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/local/Converters.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.local
2 |
3 | import android.app.usage.UsageEvents
4 | import androidx.room.TypeConverter
5 | import com.google.gson.Gson
6 | import com.wenull.mathyourbrain.data.local.entities.GameX
7 | import com.wenull.mathyourbrain.models.basic.Game
8 | import com.wenull.mathyourbrain.models.basic.Question
9 |
10 | class Converters {
11 | @TypeConverter
12 | fun gamesListToJson(games: List) = Gson().toJson(games)
13 |
14 | @TypeConverter
15 | fun questionsListToJson(question: List) = Gson().toJson(question)
16 |
17 | @TypeConverter
18 | fun jsonToGames(json: String) = Gson().fromJson(json, Array::class.java).toList()
19 |
20 | @TypeConverter
21 | fun jsonToQuestions(json: String) = Gson().fromJson(json, Array::class.java).toList()
22 |
23 |
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/local/entities/GameX.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.local.entities
2 |
3 | import com.wenull.mathyourbrain.models.basic.Question
4 |
5 | data class GameX(
6 | val userId: String,
7 | val totalTime: Int,
8 | val completedTime: Int,
9 | val totalPoints: Int,
10 | val scoredPoints: Int,
11 | val totalQuestions: Int,
12 | val thresholdScore: Int,
13 | val resigned: Boolean,
14 | val rating: Int,
15 | val correctQuestions: List,
16 | val createdAt: String
17 |
18 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/local/entities/User.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.local.entities
2 |
3 |
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import com.google.gson.annotations.SerializedName
7 | import com.wenull.mathyourbrain.models.basic.Game
8 |
9 | @Entity(tableName = User.TABLE_NAME)
10 | data class User(
11 | @SerializedName("avatar")
12 | val avatar: String,
13 | @SerializedName("games")
14 | val games: List,
15 | @PrimaryKey(autoGenerate = false)
16 | @SerializedName("_id")
17 | val id: String,
18 | @SerializedName("name")
19 | val name: String,
20 | @SerializedName("rating")
21 | val rating: Int,
22 | @SerializedName("username")
23 | val username: String
24 | ){
25 | companion object{
26 | const val TABLE_NAME = "user"
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/prefrences/UserPrefrences.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.prefrences
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.Preferences
6 | import androidx.datastore.preferences.core.booleanPreferencesKey
7 | import androidx.datastore.preferences.core.edit
8 | import androidx.datastore.preferences.core.stringPreferencesKey
9 | import androidx.datastore.preferences.preferencesDataStore
10 | import kotlinx.coroutines.flow.Flow
11 | import kotlinx.coroutines.flow.map
12 |
13 | class UserPreferences(context: Context) {
14 |
15 | private val applicationContext = context.applicationContext
16 |
17 | private val Context.dataStore: DataStore by preferencesDataStore(name = "settings")
18 |
19 | val accessToken: Flow = applicationContext.dataStore.data
20 | .map { preferences ->
21 | preferences[ACCESS_TOKEN]
22 | }
23 |
24 | suspend fun saveAccessToken(accessToken: String) {
25 | applicationContext.dataStore.edit { settings ->
26 | settings[ACCESS_TOKEN] = accessToken
27 | }
28 | }
29 |
30 | suspend fun clearData() {
31 | applicationContext.dataStore.edit {
32 | it.clear()
33 | }
34 | }
35 |
36 | val appInstalledJustNow: Flow = applicationContext.dataStore.data
37 | .map { preferences ->
38 | preferences[APP_INSTALLED_JUST_NOW]
39 | }
40 |
41 | suspend fun appInstalledJustNow(appInstalledJustNow: Boolean) {
42 |
43 | applicationContext.dataStore.edit { settings ->
44 | settings[APP_INSTALLED_JUST_NOW] = appInstalledJustNow
45 | }
46 | }
47 |
48 | companion object {
49 | val ACCESS_TOKEN = stringPreferencesKey("access_token")
50 | val APP_INSTALLED_JUST_NOW = booleanPreferencesKey("app_installed_now")
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/remote/AppService.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.remote
2 |
3 |
4 | import com.wenull.mathyourbrain.models.requests.CreateGameRequest
5 | import com.wenull.mathyourbrain.models.requests.UpdateGameRequest
6 | import com.wenull.mathyourbrain.models.response.*
7 | import retrofit2.Response
8 | import retrofit2.http.*
9 |
10 | interface AppService {
11 |
12 |
13 |
14 | @Headers("Accept: application/json")
15 | @GET("/api/misc/avatars/get")
16 | suspend fun getAllAvatars(): Response
17 |
18 | @Headers("Accept: application/json")
19 | @GET("/api/user/get/{userId}")
20 | suspend fun getUser(
21 | @Header("Authorization") accessToken: String,
22 | @Path("userId") userId: String): Response
23 |
24 |
25 | @Headers("Accept: application/json")
26 | @POST("/api/game/create/{userId}")
27 | suspend fun createGame(
28 | @Header("Authorization") accessToken: String,
29 | @Path("userId") userId: String,
30 | @Body createGameRequest: CreateGameRequest): Response
31 |
32 |
33 | @Headers("Accept: application/json")
34 | @POST("/api/game/update/{userId}/{gameId}")
35 | suspend fun updateGame(
36 | @Header("Authorization") accessToken: String,
37 | @Path("userId") userId: String,
38 | @Path("gameId") gameId: String,
39 | @Body updateGameRequest: UpdateGameRequest): Response
40 |
41 | @Headers("Accept: application/json")
42 | @GET("/api/user/leaderboard/{userId}")
43 | suspend fun getLeaderboard(
44 | @Header("Authorization") accessToken: String,
45 | @Path("userId") userId: String): Response
46 |
47 |
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/data/remote/AuthService.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.data.remote
2 |
3 | import com.wenull.mathyourbrain.models.requests.SigninRequest
4 | import com.wenull.mathyourbrain.models.requests.SignupRequest
5 | import com.wenull.mathyourbrain.models.response.SigninResponse
6 | import com.wenull.mathyourbrain.models.response.SignupResponse
7 | import retrofit2.Response
8 | import retrofit2.http.Body
9 | import retrofit2.http.GET
10 | import retrofit2.http.Headers
11 | import retrofit2.http.POST
12 |
13 | interface AuthService {
14 |
15 | @Headers("Accept: application/json")
16 | @POST("/api/auth/signup")
17 | suspend fun signUp(@Body signUpRequest: SignupRequest): Response
18 |
19 | @Headers("Accept: application/json")
20 | @POST("/api/auth/signin")
21 | suspend fun signIn(@Body signInRequest: SigninRequest): Response
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/di/DatabaseModule.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.di
2 |
3 | import android.app.Application
4 | import androidx.room.Room
5 | import com.wenull.mathyourbrain.data.local.AppDB
6 | import com.wenull.mathyourbrain.data.local.AppDAO
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.components.SingletonComponent
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | object DatabaseModule {
16 |
17 | @Provides
18 | @Singleton
19 | fun provideResAppDatabase(application: Application): AppDB {
20 | return Room.databaseBuilder(
21 | application.applicationContext,
22 | AppDB::class.java,
23 | AppDB.DATABASE_NAME
24 | ).build()
25 | }
26 |
27 | @Provides
28 | @Singleton
29 | fun provideResourcesDAO(appDatabase: AppDB): AppDAO {
30 | return appDatabase.appDao()
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/di/PrefrencesModule.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.di
2 |
3 | import android.content.Context
4 | import com.wenull.mathyourbrain.data.prefrences.UserPreferences
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.qualifiers.ApplicationContext
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | @Module
13 | @InstallIn(SingletonComponent::class)
14 | object PrefrencesModule {
15 |
16 | @Provides
17 | @Singleton
18 | fun provideUserPreferences(@ApplicationContext context: Context): UserPreferences {
19 | return UserPreferences(context)
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/di/RepositoryModule.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.di
2 |
3 |
4 | import com.wenull.mathyourbrain.data.local.AppDAO
5 | import com.wenull.mathyourbrain.data.remote.AppService
6 | import com.wenull.mathyourbrain.data.remote.AuthService
7 | import com.wenull.mathyourbrain.repo.AppRepository
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.components.SingletonComponent
12 | import javax.inject.Singleton
13 |
14 | @Module
15 | @InstallIn(SingletonComponent::class)
16 | object RepositoryModule {
17 |
18 | @Provides
19 | @Singleton
20 | fun provideAppRepository(authService: AuthService, Service: AppService, dao: AppDAO, ) = AppRepository(authService, Service, dao)
21 |
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/di/RetrofitModule.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.di
2 |
3 | import com.google.gson.Gson
4 | import com.google.gson.GsonBuilder
5 | import com.wenull.mathyourbrain.data.remote.AppService
6 | import com.wenull.mathyourbrain.data.remote.AuthService
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.components.SingletonComponent
11 | import okhttp3.OkHttpClient
12 | import okhttp3.logging.HttpLoggingInterceptor
13 | import retrofit2.Retrofit
14 | import retrofit2.converter.gson.GsonConverterFactory
15 | import java.util.concurrent.TimeUnit
16 | import javax.inject.Singleton
17 |
18 | @Module
19 | @InstallIn(SingletonComponent::class)
20 | object RetrofitModule {
21 |
22 | @Provides
23 | @Singleton
24 | fun provideGsonBuilder(): Gson = GsonBuilder().create()
25 |
26 | @Provides
27 | @Singleton
28 | fun provideRetrofit(gson: Gson): Retrofit.Builder {
29 | val logging = HttpLoggingInterceptor()
30 | logging.setLevel(HttpLoggingInterceptor.Level.BODY)
31 | val client = OkHttpClient.Builder().apply {
32 | this.addInterceptor(logging)
33 | .connectTimeout(30, TimeUnit.SECONDS)
34 | .readTimeout(20, TimeUnit.SECONDS)
35 | .writeTimeout(25, TimeUnit.SECONDS)
36 | }.build()
37 |
38 | return Retrofit.Builder()
39 | .baseUrl("Base url here")
40 | .client( client
41 | )
42 |
43 | .addConverterFactory(GsonConverterFactory.create(gson))
44 | }
45 |
46 | @Provides
47 | @Singleton
48 | fun provideAuthService(retrofit: Retrofit.Builder): AuthService {
49 | return retrofit.build().create(AuthService::class.java)
50 | }
51 |
52 | @Provides
53 | @Singleton
54 | fun provideResService(retrofit: Retrofit.Builder): AppService {
55 | return retrofit.build().create(AppService::class.java)
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/basic/ErrorResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.basic
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class ErrorResponse(
6 | @SerializedName("error")
7 | val error: String
8 | ) {
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/basic/Game.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.basic
2 |
3 | data class Game(
4 | val userId: String,
5 | val totalTime: Int,
6 | val completedTime: Int,
7 | val totalPoints: Int,
8 | val scoredPoints: Int,
9 | val questions: List,
10 | val totalQuestions: Int,
11 | val thresholdScore: Int,
12 | val resigned: Boolean,
13 | val rating: Int,
14 | val correctQuestions: List,
15 | val createdAt: String
16 |
17 | )
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/basic/Question.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.basic
2 |
3 | data class Question(
4 | val question: String,
5 | val options: List,
6 | val correctOption: Int,
7 | val rating: Int,
8 | )
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/basic/User.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.basic
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 | import com.wenull.mathyourbrain.data.local.entities.GameX
6 | import com.wenull.mathyourbrain.models.basic.Game
7 |
8 | data class User(
9 | @SerializedName("avatar")
10 | val avatar: String,
11 | @SerializedName("games")
12 | val games: List,
13 | @SerializedName("_id")
14 | val id: String,
15 | @SerializedName("name")
16 | val name: String,
17 | @SerializedName("rating")
18 | val rating: Int,
19 | @SerializedName("username")
20 | val username: String
21 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/requests/CreateGameRequest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.requests
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class CreateGameRequest(
7 | @SerializedName("rating")
8 | val rating: Int,
9 | @SerializedName("thresholdScore")
10 | val thresholdScore: Int,
11 | @SerializedName("totalQuestions")
12 | val totalQuestions: Int,
13 | @SerializedName("totalTime")
14 | val totalTime: Int
15 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/requests/SigninRequest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.requests
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class SigninRequest(
7 | @SerializedName("password")
8 | val password: String,
9 | @SerializedName("username")
10 | val username: String
11 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/requests/SignupRequest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.requests
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class SignupRequest(
7 | @SerializedName("avatar")
8 | val avatar: String,
9 | @SerializedName("name")
10 | val name: String,
11 | @SerializedName("password")
12 | val password: String,
13 | @SerializedName("username")
14 | val username: String
15 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/requests/UpdateGameRequest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.requests
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class UpdateGameRequest(
7 | @SerializedName("completedTime")
8 | val completedTime: Int,
9 | @SerializedName("correctQuestions")
10 | val correctQuestions: List,
11 | @SerializedName("rating")
12 | val rating: Int,
13 | @SerializedName("resigned")
14 | val resigned: Boolean,
15 | @SerializedName("scoredPoints")
16 | val scoredPoints: Int
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/CreateGameResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class CreateGameResponse(
7 | @SerializedName("completedTime")
8 | val completedTime: Int,
9 | @SerializedName("correctQuestions")
10 | val correctQuestions: List,
11 | @SerializedName("createdAt")
12 | val createdAt: String,
13 | @SerializedName("_id")
14 | val id: String,
15 | @SerializedName("questions")
16 | val questions: List,
17 | @SerializedName("rating")
18 | val rating: Int,
19 | @SerializedName("resigned")
20 | val resigned: Boolean,
21 | @SerializedName("scoredPoints")
22 | val scoredPoints: Int,
23 | @SerializedName("thresholdScore")
24 | val thresholdScore: Int,
25 | @SerializedName("totalPoints")
26 | val totalPoints: Int,
27 | @SerializedName("totalQuestions")
28 | val totalQuestions: Int,
29 | @SerializedName("totalTime")
30 | val totalTime: Int,
31 | @SerializedName("updatedAt")
32 | val updatedAt: String,
33 | @SerializedName("user")
34 | val user: String,
35 | @SerializedName("__v")
36 | val v: Int
37 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/GetAllAvatarsResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class GetAllAvatarsResponse(
6 | @SerializedName("avatarLinks")
7 | val avatars: List,)
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/GetLeaderboardResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | class GetLeaderboardResponse : ArrayList()
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/GetLeaderboardResponseItem.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class GetLeaderboardResponseItem(
7 | @SerializedName("avatar")
8 | val avatar: String,
9 | @SerializedName("games")
10 | val games: List,
11 | @SerializedName("_id")
12 | val id: String,
13 | @SerializedName("name")
14 | val name: String,
15 | @SerializedName("rating")
16 | val rating: Int,
17 | @SerializedName("username")
18 | val username: String
19 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/GetUserDataResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 | import com.wenull.mathyourbrain.data.local.entities.User
4 |
5 | data class GetUserDataResponse(val user: User) {
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/Question.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class Question(
7 | @SerializedName("correctOption")
8 | val correctOption: Int,
9 | @SerializedName("createdAt")
10 | val createdAt: String,
11 | @SerializedName("_id")
12 | val id: String,
13 | @SerializedName("options")
14 | val options: List,
15 | @SerializedName("question")
16 | val question: String,
17 | @SerializedName("rating")
18 | val rating: Int,
19 | @SerializedName("updatedAt")
20 | val updatedAt: String,
21 | @SerializedName("__v")
22 | val v: Int
23 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/SigninResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 | import com.wenull.mathyourbrain.models.basic.User
6 |
7 | data class SigninResponse(
8 | @SerializedName("accessToken")
9 | val accessToken: String,
10 | @SerializedName("user")
11 | val user: User
12 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/SignupResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 | import com.wenull.mathyourbrain.models.basic.User
6 |
7 | data class SignupResponse(
8 | @SerializedName("accessToken")
9 | val accessToken: String,
10 | @SerializedName("user")
11 | val user: User
12 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/response/UpdateGameResponse.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.models.response
2 |
3 |
4 | import com.google.gson.annotations.SerializedName
5 |
6 | data class UpdateGameResponse(
7 | @SerializedName("completedTime")
8 | val completedTime: Int,
9 | @SerializedName("correctQuestions")
10 | val correctQuestions: List,
11 | @SerializedName("createdAt")
12 | val createdAt: String,
13 | @SerializedName("_id")
14 | val id: String,
15 | @SerializedName("questions")
16 | val questions: List,
17 | @SerializedName("rating")
18 | val rating: Int,
19 | @SerializedName("resigned")
20 | val resigned: Boolean,
21 | @SerializedName("scoredPoints")
22 | val scoredPoints: Int,
23 | @SerializedName("thresholdScore")
24 | val thresholdScore: Int,
25 | @SerializedName("totalPoints")
26 | val totalPoints: Int,
27 | @SerializedName("totalQuestions")
28 | val totalQuestions: Int,
29 | @SerializedName("totalTime")
30 | val totalTime: Int,
31 | @SerializedName("updatedAt")
32 | val updatedAt: String,
33 | @SerializedName("user")
34 | val user: String,
35 | @SerializedName("__v")
36 | val v: Int
37 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/models/utils/DataState.kt:
--------------------------------------------------------------------------------
1 | package com.qrate.android.models.utils
2 |
3 | sealed class DataState {
4 | data class Success(val data: T): DataState()
5 | data class Error(val error: String): DataState()
6 | object Loading: DataState()
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/repo/AppRepository.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.repo
2 |
3 | import com.wenull.mathyourbrain.data.local.AppDAO
4 | import com.wenull.mathyourbrain.data.local.entities.User
5 | import com.wenull.mathyourbrain.data.remote.AppService
6 | import com.wenull.mathyourbrain.data.remote.AuthService
7 | import com.wenull.mathyourbrain.models.requests.CreateGameRequest
8 | import com.wenull.mathyourbrain.models.requests.SigninRequest
9 | import com.wenull.mathyourbrain.models.requests.SignupRequest
10 | import com.wenull.mathyourbrain.models.requests.UpdateGameRequest
11 | import com.wenull.mathyourbrain.repo.base.BaseRepository
12 | import retrofit2.Response
13 | import retrofit2.http.Body
14 | import retrofit2.http.Header
15 | import retrofit2.http.Path
16 |
17 | class AppRepository(private val authService: AuthService, private val appService: AppService, private val dao: AppDAO) : BaseRepository() {
18 |
19 | val users = dao.getUserFromDB()
20 |
21 | suspend fun signUp(@Body signUpRequest: SignupRequest) = safeApiCall {
22 | authService.signUp(signUpRequest)
23 | }
24 | suspend fun signIn(@Body signInRequest: SigninRequest) = safeApiCall {
25 | authService.signIn(signInRequest)
26 | }
27 |
28 |
29 | suspend fun saveUser(user: User){
30 | dao.insertUser(user)
31 | }
32 |
33 | suspend fun getUser(@Header("Authorization") accessToken: String,
34 | @Path("userId") userId: String) = safeApiCall {
35 | appService.getUser(accessToken, userId)
36 | }
37 |
38 | suspend fun getLeaderboard(@Header("Authorization") accessToken: String,
39 | @Path("userId") userId: String) = safeApiCall {
40 | appService.getLeaderboard(accessToken, userId)
41 | }
42 |
43 | suspend fun createGame(@Header("Authorization") accessToken: String,
44 | @Path("userId") userId: String,
45 | createGameRequest: CreateGameRequest) = safeApiCall {
46 | appService.createGame(accessToken, userId, createGameRequest)
47 | }
48 | suspend fun updateGame( @Header("Authorization") accessToken: String,
49 | @Path("userId") userId: String,
50 | @Path("gameId") gameId: String,
51 | @Body updateGameRequest: UpdateGameRequest
52 | ) = safeApiCall {
53 | appService.updateGame(accessToken, userId, gameId, updateGameRequest)
54 | }
55 |
56 |
57 | suspend fun getAllAvatars() = safeApiCall {
58 | appService.getAllAvatars()
59 | }
60 |
61 | suspend fun deleteAllUser(){
62 | dao.deleteAll()
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/repo/base/BaseRespository.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.repo.base
2 |
3 | import android.util.Log
4 | import com.google.gson.Gson
5 | import com.google.gson.reflect.TypeToken
6 | import com.qrate.android.models.utils.DataState
7 | import com.wenull.mathyourbrain.models.basic.ErrorResponse
8 | import kotlinx.coroutines.flow.Flow
9 | import kotlinx.coroutines.flow.flow
10 | import retrofit2.Response
11 | import java.net.ConnectException
12 |
13 | open class BaseRepository {
14 | suspend fun safeApiCall(
15 | apiCall: suspend () -> Response
16 | ): Flow> = flow {
17 | emit(DataState.Loading)
18 | println("SAFE API CALLING")
19 | try {
20 | val response = apiCall()
21 | Log.i("Response", response.body().toString())
22 | if (response.isSuccessful) {
23 | emit(DataState.Success(response.body()))
24 | } else {
25 | val gson = Gson()
26 | val type = object : TypeToken() {}.type
27 |
28 | val errorResponse: ErrorResponse? =
29 | gson.fromJson(response.errorBody()!!.charStream(), type)
30 | println("NOT SUCCESSFUL $errorResponse")
31 | if (errorResponse != null) {
32 | emit(DataState.Error(errorResponse.error))
33 | }
34 | }
35 |
36 | } catch (e: Exception) {
37 | if (e is ConnectException) {
38 | emit(DataState.Error("No network connection"))
39 | } else {
40 | println("ERRORRRR")
41 | e.printStackTrace()
42 | // emit(DataState.Error("ERROR"))
43 | }
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/Header.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material.Icon
8 | import androidx.compose.material.Surface
9 | import androidx.compose.material.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.clip
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.res.painterResource
16 | import androidx.compose.ui.unit.dp
17 | import coil.compose.AsyncImage
18 | import com.wenull.mathyourbrain.R
19 | import com.wenull.mathyourbrain.data.local.entities.User
20 | import com.wenull.mathyourbrain.ui.screens.main.ratingTextStyle
21 | import com.wenull.mathyourbrain.ui.screens.main.usernameTextStyle
22 |
23 | @Composable
24 | fun Header(user: User, modifier: Modifier = Modifier, onclick: () -> Unit) {
25 |
26 | Row(modifier) {
27 | Box(
28 | Modifier
29 | .padding(top = 30.dp, bottom = 20.dp)
30 |
31 | .clip(RoundedCornerShape(100))
32 | ) {
33 | Box(Modifier.background(Color(246,246,246))) {
34 | Row(Modifier.padding(horizontal = 15.dp, vertical = 10.dp)) {
35 | AsyncImage(
36 | model = user.avatar,
37 | modifier = Modifier.size(45.dp),
38 | contentDescription = null
39 | )
40 | Column(
41 | Modifier
42 | .padding(end = 9.dp)
43 | .align(Alignment.CenterVertically)) {
44 | Text(
45 | text = user.name,
46 | style = usernameTextStyle,
47 | modifier = Modifier.padding(bottom = 4.dp)
48 | )
49 | Row {
50 | Image(
51 | painter = painterResource(id = R.drawable.star),
52 | contentDescription = null,
53 | modifier = Modifier.size(12.dp)
54 | )
55 | Text(text = "${user.rating}", style = ratingTextStyle, modifier = Modifier.padding(start= 2.dp))
56 | }
57 | }
58 | Column(
59 | Modifier
60 | .padding(horizontal = 9.dp)
61 | .align(Alignment.CenterVertically)) {
62 |
63 | Icon(
64 | painter = painterResource(id = R.drawable.down),
65 | contentDescription = null,
66 | tint = Color(145, 145, 145)
67 | )
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/LoadingDialog.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components
2 |
3 | import androidx.compose.foundation.background
4 | import com.wenull.mathyourbrain.R
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.foundation.lazy.GridCells
8 | import androidx.compose.foundation.lazy.LazyVerticalGrid
9 | import androidx.compose.foundation.shape.RoundedCornerShape
10 | import androidx.compose.material.CircularProgressIndicator
11 | import androidx.compose.material.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.runtime.getValue
14 | import androidx.compose.runtime.remember
15 | import androidx.compose.ui.Alignment
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.draw.clip
18 | import androidx.compose.ui.graphics.Color
19 | import androidx.compose.ui.layout.ContentScale
20 | import androidx.compose.ui.text.TextStyle
21 | import androidx.compose.ui.text.font.FontWeight
22 | import androidx.compose.ui.text.style.TextAlign
23 | import androidx.compose.ui.unit.dp
24 | import androidx.compose.ui.unit.sp
25 | import androidx.compose.ui.window.Dialog
26 | import coil.compose.AsyncImage
27 | import coil.compose.AsyncImagePainter
28 | import coil.compose.SubcomposeAsyncImage
29 | import coil.compose.SubcomposeAsyncImageContent
30 | import com.airbnb.lottie.compose.LottieAnimation
31 | import com.airbnb.lottie.compose.LottieCompositionSpec
32 | import com.airbnb.lottie.compose.rememberLottieComposition
33 | import com.wenull.mathyourbrain.ui.theme.AppFont
34 | import com.wenull.mathyourbrain.ui.theme.MemojiDialogTitle
35 |
36 | @Composable
37 | fun LoadingDialog(){
38 | Dialog(onDismissRequest = { }) {
39 | Box(
40 | Modifier
41 | .height(80.dp).width(80.dp)
42 | .clip(RoundedCornerShape(20.dp))
43 | .background(Color.Black), contentAlignment = Alignment.Center) {
44 | Loader()
45 | }
46 |
47 | }
48 |
49 | }
50 |
51 |
52 |
53 | @Composable
54 | fun Loader() {
55 | val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.loading))
56 | LottieAnimation(composition,
57 | Modifier
58 | .fillMaxSize()
59 | .padding(0.dp), contentScale = ContentScale.Crop)
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/Logo.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.res.painterResource
7 | import com.wenull.mathyourbrain.R
8 |
9 |
10 | @Composable
11 | fun Logo(
12 | modifier: Modifier
13 | ){
14 | Image(painter = painterResource(id = R.drawable.ic_launcher_background), contentDescription = "logo", modifier = modifier)
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/MemojiSelector.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.draw.clip
11 | import androidx.compose.ui.graphics.Color
12 | import androidx.compose.ui.text.style.TextAlign
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Dialog
15 | import coil.compose.AsyncImagePainter
16 | import coil.compose.SubcomposeAsyncImage
17 | import coil.compose.SubcomposeAsyncImageContent
18 | import com.wenull.mathyourbrain.ui.theme.MemojiDialogTitle
19 |
20 |
21 | @Composable
22 | fun MemojiSelector(links: List, dismiss: () -> Unit, onClick:(String) -> Unit){
23 |
24 | Dialog(onDismissRequest = {dismiss()}) {
25 | Box(
26 | modifier = Modifier.clip(RoundedCornerShape(20.dp)).background(Color.White)){
27 | var count = 0
28 |
29 | if(links.isEmpty()) {
30 |
31 | }else {
32 | Column(){
33 |
34 |
35 | Text("Choose your avatar", style = MemojiDialogTitle, modifier = Modifier
36 | .fillMaxWidth(1f)
37 | .padding(25.dp), textAlign = TextAlign.Center)
38 |
39 | Row(horizontalArrangement = Arrangement.SpaceEvenly){
40 | for (i in 0..3) {
41 | Column(){
42 | for (j in 0..3) {
43 | if(count Unit,
49 | textFieldValue: TextFieldValue,
50 | keyboardShown: Boolean,
51 | keyboardOptions: KeyboardOptions = KeyboardOptions(
52 | keyboardType = keyboardType,
53 | imeAction = ImeAction.Send
54 | ),
55 | keyboardActions: KeyboardActions = KeyboardActions {
56 |
57 | },
58 | borderWidth: Dp,
59 | backgroundColor: Color,
60 | border: Color,
61 | borderRadius: Dp,
62 | hint: String,
63 | onTextFieldFocused: (Boolean) -> Unit,
64 | focusState: Boolean,
65 | padding: PaddingValues = PaddingValues(17.dp),
66 | modifier: Modifier = Modifier,
67 | textStyle: TextStyle = LocalTextStyle.current.copy(color = LocalContentColor.current),
68 | hintStyle: TextStyle = hintTextStyle
69 | ) {
70 | val descr = "descr"
71 | var (lastFocusState) = remember { mutableStateOf(true) }
72 | Row(
73 | modifier = modifier.semantics {
74 | contentDescription = descr
75 | }.onFocusChanged { state ->
76 | if (lastFocusState != state.isFocused) {
77 | onTextFieldFocused(state.isFocused)
78 | }
79 | lastFocusState = state.isFocused
80 | }
81 |
82 |
83 | ) {
84 | Box(Modifier.clip(RoundedCornerShape(borderRadius))
85 | .border(borderWidth, border, RoundedCornerShape(borderRadius))
86 | .background(backgroundColor)) {
87 |
88 | Box(
89 | modifier = Modifier
90 | .padding(paddingValues = padding)
91 | .fillMaxWidth(1f)
92 | ,
93 | contentAlignment = Alignment.Center
94 | ) {
95 |
96 |
97 | BasicTextField(
98 | value = textFieldValue,
99 | onValueChange = { onTextChanged(it) },
100 | modifier = Modifier
101 | .fillMaxWidth()
102 | .padding(start = 10.dp)
103 | .align(Alignment.Center)
104 | ,
105 | keyboardOptions = keyboardOptions,
106 | maxLines = 1,
107 | keyboardActions = keyboardActions,
108 | textStyle = textStyle,
109 | )
110 |
111 | val disableContentColor =
112 | MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
113 | if (textFieldValue.text.isEmpty() && !focusState) {
114 | Text(
115 | modifier = Modifier
116 | .align(Alignment.CenterStart)
117 | .padding(start = 10.dp),
118 | text = AnnotatedString(hint),
119 | style = hintStyle
120 | )
121 |
122 |
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/Timer.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components
2 |
3 | import android.os.CountDownTimer
4 | import android.util.Log
5 | import androidx.compose.foundation.background
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.Row
8 | import androidx.compose.foundation.layout.fillMaxWidth
9 | import androidx.compose.foundation.layout.height
10 | import androidx.compose.material.Text
11 | import androidx.compose.runtime.*
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.unit.dp
16 | import com.wenull.mathyourbrain.ui.theme.TimerTextStyle
17 | import kotlinx.coroutines.delay
18 |
19 | val hexList = listOf(
20 | 0xFF0BBC00,
21 | 0xFF32C100,
22 | 0xFF81BE00,
23 | 0xFF99CE00,
24 | 0xFFCACE00,
25 | 0xFFDBD200,
26 | 0xFFDB9E00,
27 | 0xFFDB8300,
28 | 0xFFDB7600,
29 | 0xFFDB6900,
30 | 0xFFDB3500
31 | )
32 | var timer_color = Color(hexList[0])
33 |
34 | @Composable
35 | fun Timer(
36 | value: Float,
37 | currentTime:Long,
38 | totalTime: Long,
39 | modifier: Modifier = Modifier,
40 | onFinish:()-> Unit
41 | ) {
42 |
43 | var isTimerRunning by remember {
44 | mutableStateOf(true)
45 | }
46 |
47 |
48 |
49 | Box(
50 | contentAlignment = Alignment.CenterStart,
51 | modifier = modifier
52 | ) {
53 |
54 |
55 | var n : Float= hexList.size.toFloat();
56 |
57 |
58 | if((n/hexList.size)== value) {
59 | timer_color = Color(hexList.get((n - 1).toInt()))
60 | }
61 |
62 |
63 |
64 | Row(
65 | Modifier
66 | .background(Color(0xFFECECEC))
67 | .height(27.dp)
68 | .fillMaxWidth(1f)) {
69 |
70 | }
71 |
72 | val color = if (value <= 1.0f / hexList.size) {
73 | Color(hexList.get(hexList.size - 1))
74 | } else if (value <= 2.0f / hexList.size) {
75 | Color(hexList.get(hexList.size - 2))
76 | }else if (value <= 3.0f / hexList.size) {
77 | Color(hexList.get(hexList.size - 3))
78 | }else if (value <= 4.0f / hexList.size) {
79 | Color(hexList.get(hexList.size - 4))
80 | }else if (value <= 5.0f / hexList.size) {
81 | Color(hexList.get(hexList.size - 5))
82 | }else if (value <= 6.0f / hexList.size) {
83 | Color(hexList.get(hexList.size - 6))
84 | }else if (value <= 7.0f / hexList.size) {
85 | Color(hexList.get(hexList.size - 7))
86 | }else if (value <= 8.0f / hexList.size) {
87 | Color(hexList.get(hexList.size - 8))
88 | }else if (value <= 9.0f/ hexList.size) {
89 | Color(hexList.get(hexList.size - 9))
90 | }else if (value <= 10.0f / hexList.size) {
91 | Color(hexList.get(hexList.size - 10))
92 | } else {
93 | Color(hexList.get(0))
94 | }
95 |
96 | val first_part =if((currentTime / 1000)/60 > 10)
97 | "${(currentTime / 1000L)/60}" else "0"+((currentTime / 1000L)/60).toString()
98 | val second_part = if((currentTime / 1000)%60 < 10) "0"+ "${(currentTime / 1000)%60}" else "${(currentTime / 1000)%60}"
99 |
100 | Row(
101 | Modifier
102 | .background(color)
103 | .height(27.dp)
104 | .fillMaxWidth(value)) {
105 |
106 | }
107 | Text(
108 | text = "$first_part:$second_part",
109 | style = TimerTextStyle,
110 | color = if(value <= 1/2f) Color.Black else Color.White,
111 | modifier= Modifier.align(Alignment.Center)
112 | )
113 |
114 | if(currentTime <= 0L) {
115 | onFinish()
116 |
117 | //TimeFinished
118 | }
119 | }
120 |
121 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/gamescreen/GameCompleted.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components.gamescreen
2 |
3 | import android.util.Log
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.interaction.MutableInteractionSource
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.material.FloatingActionButtonDefaults
10 | import androidx.compose.material.Surface
11 | import androidx.compose.material.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.runtime.remember
14 | import androidx.compose.ui.Alignment
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.draw.clip
17 | import androidx.compose.ui.graphics.Color
18 | import androidx.compose.ui.text.style.TextAlign
19 | import androidx.compose.ui.unit.dp
20 | import androidx.compose.ui.window.Dialog
21 | import androidx.compose.ui.window.DialogProperties
22 | import com.wenull.mathyourbrain.ui.theme.CTAButtonTextStyle
23 | import com.wenull.mathyourbrain.ui.theme.*
24 |
25 | @Composable
26 | fun GameCompleted(newGame: ()-> Unit, leave: () -> Unit, newRating: Int, correctQuestions: Int, totalScore: Int, completedTime: Long, scoredPoints: Int){
27 |
28 | Dialog(
29 | onDismissRequest = { },
30 | properties = DialogProperties()
31 | ) {
32 | Column(
33 | Modifier
34 | .clip(RoundedCornerShape(15.dp))
35 | .background(Color.White)
36 | .padding(25.dp)) {
37 |
38 | Column(Modifier.fillMaxWidth(1f), horizontalAlignment = Alignment.CenterHorizontally) {
39 | Text(
40 | "NEW RATING",
41 | style = NewRatingOverlineTextStyle,
42 | modifier = Modifier
43 | .fillMaxWidth(1f)
44 | .padding(bottom = 5.dp),
45 | textAlign = TextAlign.Center
46 | )
47 |
48 | Text(
49 | "$newRating", style = NewRatingTextStyle, modifier = Modifier
50 | .fillMaxWidth(1f)
51 | .padding(bottom = 20.dp), textAlign = TextAlign.Center
52 | )
53 | }
54 | Row(
55 | Modifier
56 | .fillMaxWidth(1f)
57 | .padding(bottom = 25.dp), horizontalArrangement = Arrangement.SpaceBetween){
58 | Column(Modifier, horizontalAlignment = Alignment.CenterHorizontally) {
59 | Text(
60 | "Correct",
61 | style = ScoreOverlineTextStyle,
62 | modifier = Modifier,
63 | textAlign = TextAlign.Center
64 | )
65 |
66 | Text(
67 | "$correctQuestions/20", style = ScoreTextStyle, modifier = Modifier
68 | , textAlign = TextAlign.Center
69 | )
70 | }
71 | Column(Modifier.fillMaxWidth(1/3f), horizontalAlignment = Alignment.CenterHorizontally) {
72 | Text(
73 | "Time",
74 | style = ScoreOverlineTextStyle,
75 | modifier = Modifier,
76 | textAlign = TextAlign.Center
77 | )
78 |
79 | Log.i("Hey 12456", completedTime.toString())
80 |
81 | val first_part =if((completedTime)/60 > 10)
82 | "${(completedTime)/60}" else "0"+((completedTime)/60).toString()
83 | val second_part = if((completedTime )%60 < 10) "0"+ "${(completedTime)%60}" else "${(completedTime)%60}"
84 |
85 | val strTime ="$first_part:$second_part"
86 | Text(
87 | strTime, style = ScoreTextStyle, modifier = Modifier, textAlign = TextAlign.Center
88 | )
89 | }
90 | Column(Modifier, horizontalAlignment = Alignment.CenterHorizontally) {
91 | Text(
92 | "Score",
93 | style = ScoreOverlineTextStyle,
94 | modifier = Modifier,
95 | textAlign = TextAlign.Center
96 | )
97 |
98 | Text(
99 | "$scoredPoints/$totalScore", style = ScoreTextStyle, modifier = Modifier
100 | , textAlign = TextAlign.Center
101 | )
102 | }
103 | }
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | Column() {
112 | val interactionSource = remember { MutableInteractionSource() }
113 |
114 |
115 | Surface(
116 | modifier = Modifier
117 |
118 | .padding(bottom = 12.dp)
119 | .fillMaxWidth(1f)
120 | .clip(RoundedCornerShape(10.dp)),
121 | elevation = FloatingActionButtonDefaults.elevation()
122 | .elevation(interactionSource).value,
123 | ) {
124 | Box(modifier = Modifier
125 |
126 | .clickable { leave() }
127 | .background(Color(0xFFF8F8F8))
128 | .padding(10.dp), contentAlignment = Alignment.Center) {
129 | Text(text = "Leave", color = Color.Black, style = CTAButtonTextStyle)
130 | }
131 | }
132 |
133 | Surface(
134 | modifier = Modifier
135 | .fillMaxWidth(1f)
136 | .clip(RoundedCornerShape(10.dp)),
137 | elevation = FloatingActionButtonDefaults.elevation()
138 | .elevation(interactionSource).value,
139 |
140 | ) {
141 | Box(modifier = Modifier
142 |
143 | .clickable {
144 | newGame()
145 | }
146 | .background(Color.Black)
147 | .padding(10.dp), contentAlignment = Alignment.Center) {
148 | Text(text = "New Game", color = Color.White, style = CTAButtonTextStyle)
149 | }
150 | }
151 |
152 |
153 |
154 | }
155 | }
156 | }
157 |
158 |
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/gamescreen/Option.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components.gamescreen
2 |
3 | import androidx.compose.foundation.border
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Row
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.shape.RoundedCornerShape
10 | import androidx.compose.material.Text
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.clip
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.unit.dp
16 | import com.wenull.mathyourbrain.ui.theme.OptionTextStyle
17 |
18 | @Composable
19 | fun Option(index: Int, text: String, onClick: (Int) -> Unit){
20 | Box(
21 | Modifier
22 |
23 | .padding(start = 12.dp, end = 12.dp, top = 5.dp, bottom = 15.dp)
24 | .clip(RoundedCornerShape(20.dp))
25 | .border(2.dp, Color(244, 244, 244), RoundedCornerShape(20.dp))
26 | .clickable {
27 | onClick(index)
28 | }
29 | .fillMaxWidth()) {
30 | Row(Modifier.padding(top = 15.dp, bottom = 15.dp, start =15.dp, end = 15.dp)) {
31 | Text(text = "${(65+index).toChar()}", style = OptionTextStyle, modifier = Modifier.padding(start = 15.dp, end = 24.dp, top = 15.dp, bottom = 15.dp))
32 | Text(text = "${text}", style = OptionTextStyle, modifier = Modifier.padding(start = 15.dp, end = 24.dp, top = 15.dp, bottom = 15.dp))
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/components/gamescreen/ResignAlertDialog.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.components.gamescreen
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.interaction.MutableInteractionSource
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.Column
8 | import androidx.compose.foundation.layout.fillMaxWidth
9 | import androidx.compose.foundation.layout.padding
10 | import androidx.compose.foundation.shape.RoundedCornerShape
11 | import androidx.compose.material.FloatingActionButtonDefaults
12 | import androidx.compose.material.Surface
13 | import androidx.compose.material.Text
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.runtime.remember
16 | import androidx.compose.ui.Alignment
17 | import androidx.compose.ui.Modifier
18 | import androidx.compose.ui.draw.clip
19 | import androidx.compose.ui.graphics.Color
20 | import androidx.compose.ui.text.style.TextAlign
21 | import androidx.compose.ui.unit.dp
22 | import androidx.compose.ui.window.Dialog
23 | import androidx.compose.ui.window.DialogProperties
24 | import com.wenull.mathyourbrain.ui.screens.main.TableContentTextStyle
25 | import com.wenull.mathyourbrain.ui.theme.CTAButtonTextStyle
26 | import com.wenull.mathyourbrain.ui.theme.MemojiDialogTitle
27 |
28 | @Composable
29 | fun ResignAlertDialog(yes: ()-> Unit, no: () -> Unit){
30 | Dialog(
31 | onDismissRequest = { },
32 | properties = DialogProperties()
33 | ) {
34 | Column(
35 | Modifier
36 | .clip(RoundedCornerShape(15.dp))
37 | .background(Color.White)
38 | .padding(25.dp)) {
39 |
40 | Text(
41 | "Do you want to resign?", style = MemojiDialogTitle, modifier = Modifier
42 | .fillMaxWidth(1f)
43 | .padding(bottom = 10.dp), textAlign = TextAlign.Center
44 | )
45 |
46 | Text(
47 | "Resigning this will make you lose ratings", style = TableContentTextStyle, modifier = Modifier
48 | .fillMaxWidth(1f)
49 | .padding(bottom = 20.dp), textAlign = TextAlign.Center
50 | )
51 |
52 |
53 |
54 | Column() {
55 | val interactionSource = remember { MutableInteractionSource() }
56 |
57 |
58 | Surface(
59 | modifier = Modifier
60 |
61 | .padding(bottom = 12.dp)
62 | .fillMaxWidth(1f)
63 | .clip(RoundedCornerShape(10.dp)),
64 | elevation = FloatingActionButtonDefaults.elevation()
65 | .elevation(interactionSource).value,
66 | ) {
67 | Box(modifier = Modifier
68 |
69 | .clickable { yes() }
70 | .background(Color(0xFFF8F8F8))
71 | .padding(10.dp), contentAlignment = Alignment.Center) {
72 | Text(text = "Yes", color = Color.Black, style = CTAButtonTextStyle)
73 | }
74 | }
75 |
76 | Surface(
77 | modifier = Modifier
78 | .fillMaxWidth(1f)
79 | .clip(RoundedCornerShape(10.dp)),
80 | elevation = FloatingActionButtonDefaults.elevation()
81 | .elevation(interactionSource).value,
82 |
83 | ) {
84 | Box(modifier = Modifier
85 |
86 | .clickable {
87 | no()
88 | }
89 | .background(Color.Black)
90 | .padding(10.dp), contentAlignment = Alignment.Center) {
91 | Text(text = "No", color = Color.White, style = CTAButtonTextStyle)
92 | }
93 | }
94 |
95 |
96 |
97 | }
98 | }
99 | }
100 |
101 |
102 |
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/auth/SigninScreen.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.auth
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.border
6 | import androidx.compose.foundation.clickable
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.foundation.text.KeyboardActions
10 | import androidx.compose.material.*
11 | import androidx.compose.runtime.*
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.layout.*
17 | import androidx.compose.ui.res.painterResource
18 | import androidx.compose.ui.text.TextStyle
19 | import androidx.compose.ui.text.font.FontWeight
20 | import androidx.compose.ui.text.input.TextFieldValue
21 | import androidx.compose.ui.unit.dp
22 | import androidx.compose.ui.unit.sp
23 | import androidx.navigation.NavController
24 | import com.google.accompanist.insets.systemBarsPadding
25 | import com.wenull.mathyourbrain.HomeScreen
26 | import com.wenull.mathyourbrain.R
27 | import com.wenull.mathyourbrain.SignUp
28 | import com.wenull.mathyourbrain.data.local.entities.User
29 | import com.wenull.mathyourbrain.models.requests.SigninRequest
30 | import com.wenull.mathyourbrain.models.response.SigninResponse
31 | import com.wenull.mathyourbrain.ui.components.TextInput
32 | import com.wenull.mathyourbrain.ui.screens.splash.CTAButton
33 | import com.wenull.mathyourbrain.ui.theme.AppFont
34 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
35 | import com.wenull.mathyourbrain.viewmodels.Task
36 |
37 |
38 | val SignInTextStyle = TextStyle(
39 | fontFamily = AppFont,
40 | fontWeight = FontWeight.Bold,
41 | fontSize = 33.02.sp,
42 | color = Color(0xFF000000),
43 | letterSpacing = 0.25.sp
44 | )
45 |
46 | val TextCTATextStyle = TextStyle(
47 | fontFamily = AppFont,
48 | fontWeight = FontWeight.Medium,
49 | fontSize = 14.sp,
50 | letterSpacing = 0.sp
51 | )
52 |
53 | val WarningTextStyle = TextStyle(
54 | fontFamily = AppFont,
55 | fontWeight = FontWeight.Normal,
56 | fontSize = 12.84.sp,
57 | letterSpacing = 0.25.sp,
58 | color = Color.Black
59 | )
60 |
61 | @Composable
62 | fun Warning(warningText: String){
63 |
64 |
65 | Box(
66 | Modifier
67 | .clip(RoundedCornerShape(5.dp))
68 | .border(1.dp, Color(0xFFFF3A3A), RoundedCornerShape(5.dp))
69 | .background(Color(0xFFFFE5E5))
70 | ) {
71 | Row(Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically) {
72 | Image(painter = painterResource(id = R.drawable.ic_warning)
73 | , contentDescription = "ic_warning" )
74 | Text(warningText, style = WarningTextStyle, modifier = Modifier.padding(start = 10.dp))
75 | }
76 | }
77 |
78 |
79 |
80 | }
81 |
82 |
83 |
84 | @Composable
85 | fun SigninScreen(navController: NavController, viewModel: MainViewModel = androidx.lifecycle.viewmodel.compose.viewModel()) {
86 |
87 | val (isVisible, setVisible) = remember { mutableStateOf(false) }
88 | val (warningString, setWarningString) = remember { mutableStateOf("") }
89 |
90 | var usernameState by remember { mutableStateOf(TextFieldValue()) }
91 | var passwordState by remember { mutableStateOf(TextFieldValue()) }
92 |
93 | var textFieldFocusState by remember { mutableStateOf(true) }
94 | Column(
95 | Modifier
96 | .fillMaxSize()
97 | .background(Color.White)
98 | .systemBarsPadding(), verticalArrangement = Arrangement.SpaceBetween
99 | , horizontalAlignment = Alignment.CenterHorizontally
100 | ) {
101 | Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxHeight(0.75f)) {
102 | Column(horizontalAlignment = Alignment.CenterHorizontally) {
103 | Text(text = "Sign in", style = SignInTextStyle, modifier = Modifier.padding(bottom = 32.dp))
104 | Column(Modifier.padding(horizontal = 24.dp, vertical = 12.dp), ) {
105 | TextInput(
106 |
107 | modifier = Modifier.padding(bottom = 12.dp)
108 | ,
109 | textFieldValue = usernameState,
110 | onTextChanged = { usernameState = it },
111 | // Only show the keyboard if there's no input selector and text field has focus
112 | keyboardShown = textFieldFocusState,
113 | keyboardActions = KeyboardActions(
114 | onSend = {
115 | }
116 | )
117 | ,
118 |
119 | // Close extended selector if text field receives focus
120 | onTextFieldFocused = { focused ->
121 |
122 | textFieldFocusState = focused
123 | },
124 | focusState = textFieldFocusState,
125 | borderRadius = 9.17.dp,
126 | backgroundColor = Color(0xFFFBFBFB),
127 | border = Color(0xFFF2F2F2),
128 | borderWidth = 0.92.dp,
129 | hint = "Username"
130 | )
131 |
132 | TextInput(
133 |
134 | modifier = Modifier.padding(bottom = 12.dp)
135 | ,
136 | textFieldValue = passwordState,
137 | onTextChanged = { passwordState = it },
138 | // Only show the keyboard if there's no input selector and text field has focus
139 | keyboardShown = textFieldFocusState,
140 | keyboardActions = KeyboardActions(
141 | onSend = {
142 | }
143 | )
144 | ,
145 |
146 | // Close extended selector if text field receives focus
147 | onTextFieldFocused = { focused ->
148 |
149 | textFieldFocusState = focused
150 | },
151 | focusState = textFieldFocusState,
152 | borderRadius = 9.17.dp,
153 | backgroundColor = Color(0xFFFBFBFB),
154 | border = Color(0xFFF2F2F2),
155 | borderWidth = 0.92.dp,
156 | hint = "Password"
157 | )
158 |
159 |
160 | }
161 |
162 | }
163 |
164 | }
165 | if(!warningString.isNullOrEmpty()){
166 | Warning(warningText = warningString)
167 | }
168 | Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
169 | Row(Modifier.padding(bottom = 20.dp)) {
170 | Text("Don’t have an account?", style = TextCTATextStyle, color = Color(0xFFC2C2C2) )
171 | Text(" Sign up", style = TextCTATextStyle, color = Color(0xFF000000) , modifier = Modifier.clickable {
172 | navController.navigate(SignUp)
173 | })
174 | }
175 | CTAButton(onClick = {
176 | if( usernameState.text.isEmpty() && passwordState.text.isEmpty()){
177 | setWarningString("Fill All Details")
178 | }else if (usernameState.text.isEmpty() || passwordState.text.isEmpty()){
179 | if(usernameState.text.isEmpty()) setWarningString("Username is required")
180 | if(passwordState.text.isEmpty()) setWarningString("Password is required")
181 | }else {
182 |
183 | viewModel.signin(
184 | SigninRequest(username = usernameState.text, password = passwordState.text),
185 |
186 | object : Task {
187 | override fun whileLoading() {
188 | setVisible(true)
189 | }
190 |
191 | override fun onSucess(data: SigninResponse?) {
192 | setVisible(false)
193 | if (data != null) {
194 | val user = data.user
195 | viewModel.saveUserDetails(data.accessToken, User(avatar = user.avatar, games = user.games, id = user.id, name = user.name, rating = user.rating, username = user.username))
196 | navController.navigate(HomeScreen){
197 | popUpTo(0){
198 | inclusive = true }
199 | }
200 | }
201 |
202 | }
203 |
204 | override fun onError(error: String) {
205 | setVisible(false)
206 | setWarningString(error)
207 |
208 | }
209 |
210 | }
211 |
212 |
213 |
214 | ) } }, isPrimary = true, text = "Sign in", modifier = Modifier.padding(bottom = 12.dp))
215 |
216 |
217 | }
218 | }
219 |
220 | }
221 |
222 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/auth/SignupScreen.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.auth
2 |
3 | import android.util.Log
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.border
6 | import androidx.compose.foundation.clickable
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.foundation.text.KeyboardActions
10 | import androidx.compose.material.*
11 | import androidx.compose.material.SnackbarDefaults.backgroundColor
12 | import androidx.compose.runtime.*
13 | import androidx.compose.ui.Alignment
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.draw.clip
16 | import androidx.compose.ui.graphics.Color
17 | import androidx.compose.ui.layout.ContentScale
18 | import androidx.compose.ui.text.input.TextFieldValue
19 | import androidx.compose.ui.unit.dp
20 | import androidx.lifecycle.viewmodel.compose.viewModel
21 | import androidx.navigation.NavController
22 | import coil.compose.AsyncImage
23 | import coil.compose.rememberImagePainter
24 | import com.google.accompanist.insets.systemBarsPadding
25 | import com.wenull.mathyourbrain.ui.components.LoadingDialog
26 | import com.wenull.mathyourbrain.ui.components.MemojiSelector
27 | import com.wenull.mathyourbrain.HomeScreen
28 | import com.wenull.mathyourbrain.SignIn
29 | import com.wenull.mathyourbrain.data.local.entities.User
30 | import com.wenull.mathyourbrain.models.requests.SignupRequest
31 | import com.wenull.mathyourbrain.models.response.GetAllAvatarsResponse
32 | import com.wenull.mathyourbrain.models.response.SigninResponse
33 | import com.wenull.mathyourbrain.models.response.SignupResponse
34 | import com.wenull.mathyourbrain.ui.components.TextInput
35 | import com.wenull.mathyourbrain.ui.components.hintTextStyle
36 | import com.wenull.mathyourbrain.ui.screens.auth.SignInTextStyle
37 | import com.wenull.mathyourbrain.ui.screens.auth.TextCTATextStyle
38 | import com.wenull.mathyourbrain.ui.screens.auth.Warning
39 | import com.wenull.mathyourbrain.ui.screens.splash.CTAButton
40 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
41 | import com.wenull.mathyourbrain.viewmodels.Task
42 |
43 | @Composable
44 | fun SignupScreen(
45 | viewModel: MainViewModel = viewModel(),
46 | navController: NavController) {
47 | val (isVisible, setVisible) = remember { mutableStateOf(false) }
48 | val (warningString, setWarningString) = remember { mutableStateOf("") }
49 |
50 | var nameState by remember { mutableStateOf(TextFieldValue()) }
51 | var usernameState by remember { mutableStateOf(TextFieldValue()) }
52 | var passwordState by remember { mutableStateOf(TextFieldValue()) }
53 | var avatarState by remember { mutableStateOf(null) }
54 |
55 | var textFieldFocusState by remember { mutableStateOf(true) }
56 | var isChoosingMemoji by remember{mutableStateOf(false)}
57 | var anAvatarSelected by remember{mutableStateOf(false)}
58 |
59 | var avatars by remember { mutableStateOf>(listOf())}
60 |
61 | if(isChoosingMemoji && avatars.size>0)
62 | MemojiSelector(avatars) { string ->
63 | avatarState = (string)
64 | isChoosingMemoji = false
65 | anAvatarSelected = true
66 | }
67 |
68 |
69 | Column(
70 | Modifier
71 | .fillMaxSize()
72 | .background(Color.White)
73 | .systemBarsPadding(), verticalArrangement = Arrangement.SpaceBetween
74 | , horizontalAlignment = Alignment.CenterHorizontally
75 | ) {
76 | Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxHeight(0.75f)) {
77 | Column(horizontalAlignment = Alignment.CenterHorizontally) {
78 | Text(text = "Sign up", style = SignInTextStyle, modifier = Modifier.padding(bottom = 32.dp))
79 |
80 | Column(Modifier.padding(horizontal = 24.dp, vertical = 12.dp), ) {
81 |
82 |
83 | TextInput(
84 |
85 | modifier = Modifier.padding(bottom = 12.dp)
86 | ,
87 | textFieldValue = nameState,
88 | onTextChanged = { nameState = it },
89 | // Only show the keyboard if there's no input selector and text field has focus
90 | keyboardShown = textFieldFocusState,
91 | keyboardActions = KeyboardActions(
92 | onSend = {
93 | }
94 | )
95 | ,
96 |
97 | // Close extended selector if text field receives focus
98 | onTextFieldFocused = { focused ->
99 |
100 | textFieldFocusState = focused
101 | },
102 | focusState = textFieldFocusState,
103 | borderRadius = 9.17.dp,
104 | backgroundColor = Color(0xFFFBFBFB),
105 | border = Color(0xFFF2F2F2),
106 | borderWidth = 0.92.dp,
107 | hint = "Name"
108 | )
109 |
110 |
111 | TextInput(
112 | modifier = Modifier.padding(bottom = 12.dp)
113 | ,
114 | textFieldValue = usernameState,
115 | onTextChanged = { usernameState = it },
116 | // Only show the keyboard if there's no input selector and text field has focus
117 | keyboardShown = textFieldFocusState,
118 | keyboardActions = KeyboardActions(
119 | onSend = {
120 | })
121 | ,
122 |
123 | // Close extended selector if text field receives focus
124 | onTextFieldFocused = { focused ->
125 |
126 | textFieldFocusState = focused
127 | },
128 | focusState = textFieldFocusState,
129 | borderRadius = 9.17.dp,
130 | backgroundColor = Color(0xFFFBFBFB),
131 | border = Color(0xFFF2F2F2),
132 | borderWidth = 0.92.dp,
133 | hint = "Username"
134 | )
135 |
136 | TextInput(
137 |
138 | modifier = Modifier.padding(bottom = 12.dp)
139 | ,
140 | textFieldValue = passwordState,
141 | onTextChanged = { passwordState = it },
142 | // Only show the keyboard if there's no input selector and text field has focus
143 | keyboardShown = textFieldFocusState,
144 | keyboardActions = KeyboardActions(
145 | onSend = {
146 | }
147 | )
148 | ,
149 |
150 | // Close extended selector if text field receives focus
151 | onTextFieldFocused = { focused ->
152 |
153 | textFieldFocusState = focused
154 | },
155 | focusState = textFieldFocusState,
156 | borderRadius = 9.17.dp,
157 | backgroundColor = Color(0xFFFBFBFB),
158 | border = Color(0xFFF2F2F2),
159 | borderWidth = 0.92.dp,
160 | hint = "Password"
161 | )
162 |
163 |
164 | Row(
165 | modifier = Modifier
166 | .padding(bottom = 12.dp)
167 | .clickable {
168 | isChoosingMemoji = !isChoosingMemoji
169 | viewModel.getAllAvatars(object : Task {
170 | override fun whileLoading() {
171 | }
172 |
173 | override fun onSucess(data: GetAllAvatarsResponse) {
174 | avatars = data.avatars
175 | Log.i("12245", "Avatars $avatars")
176 | }
177 |
178 | override fun onError(error: String) {
179 | }
180 |
181 | })
182 | }
183 | ) {
184 | Box(
185 | Modifier
186 | .clip(RoundedCornerShape(9.17.dp))
187 | .border(
188 | 0.92.dp, Color(0xFFF2F2F2),
189 | RoundedCornerShape(9.17.dp)
190 | )
191 | .background(Color(0xFFFBFBFB))
192 | ) {
193 |
194 | Box(
195 | modifier = Modifier
196 | .padding(paddingValues = PaddingValues(17.dp))
197 | .fillMaxWidth(1f),
198 | contentAlignment = Alignment.Center
199 | ) {
200 |
201 |
202 | Text(
203 | text = if(anAvatarSelected) "Chose An Avatar" else "Choose An Avatar",
204 | modifier = Modifier
205 | .fillMaxWidth()
206 | .padding(start = 10.dp)
207 | .align(Alignment.Center),
208 | style = if(!anAvatarSelected) hintTextStyle else LocalTextStyle.current.copy(color = LocalContentColor.current)
209 | )
210 | }
211 | }
212 | }
213 |
214 |
215 |
216 | }
217 |
218 | }
219 |
220 | }
221 | if(!warningString.isNullOrEmpty()){
222 | Warning(warningText = warningString)
223 | }
224 |
225 |
226 |
227 | Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
228 | Row(Modifier.padding(bottom = 20.dp)) {
229 | Text("Already have an account?", style = TextCTATextStyle, color = Color(0xFFC2C2C2) )
230 | Text(" Sign in", style = TextCTATextStyle, color = Color(0xFF000000) , modifier = Modifier.clickable {
231 | navController.navigate(SignIn)
232 | })
233 | }
234 | CTAButton(onClick = {
235 | if(avatarState.isNullOrEmpty()&&nameState.text.isEmpty()&& usernameState.text.isEmpty() && passwordState.text.isEmpty()){
236 | setWarningString("Fill All Details")
237 | }else if (avatarState.isNullOrEmpty() || nameState.text.isEmpty() || usernameState.text.isEmpty() || passwordState.text.isEmpty()){
238 | if(nameState.text.isEmpty()) setWarningString("Name is required")
239 | if(usernameState.text.isEmpty()) setWarningString("Username is required")
240 | if(passwordState.text.isEmpty()) setWarningString("Password is required")
241 | if(avatarState.isNullOrEmpty()) setWarningString("Password is required")
242 | }else {
243 | viewModel.signup(
244 |
245 |
246 |
247 | SignupRequest(
248 | name = nameState.text,
249 | username = usernameState.text,
250 | password = passwordState.text,
251 | avatar = avatarState!!
252 | ),
253 |
254 | object : Task {
255 | override fun whileLoading() {
256 | setVisible(true)
257 | }
258 |
259 | override fun onSucess(data: SignupResponse?) {
260 | setVisible(false)
261 | if (data != null) {
262 | val user = data.user
263 | Log.i("12245", "viewmodel save calling $user")
264 | viewModel.saveUserDetails(
265 | data.accessToken,
266 | User(
267 | avatar = user.avatar,
268 | games = user.games,
269 | id = user.id,
270 | name = user.name,
271 | rating = user.rating,
272 | username = user.username
273 | )
274 | )
275 | navController.navigate(HomeScreen) {
276 | popUpTo(0) {
277 | inclusive = true
278 | }
279 | }
280 | }
281 |
282 | }
283 |
284 | override fun onError(error: String) {
285 | setVisible(false)
286 | setWarningString(error)
287 |
288 | }
289 |
290 |
291 | }
292 |
293 |
294 | )
295 | }}, isPrimary = true, text = "Sign up", modifier = Modifier.padding(bottom = 12.dp))
296 |
297 |
298 | }
299 |
300 | }
301 | }
302 |
303 |
304 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/main/GameScreen.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.main
2 |
3 | import android.util.Log
4 | import androidx.activity.compose.BackHandler
5 | import androidx.compose.foundation.*
6 | import androidx.compose.foundation.interaction.MutableInteractionSource
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.material.*
10 | import androidx.compose.runtime.*
11 | import androidx.compose.runtime.livedata.observeAsState
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.graphics.Color
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.*
20 | import androidx.compose.ui.window.Dialog
21 | import androidx.compose.ui.window.DialogProperties
22 | import androidx.navigation.NavController
23 | import com.google.accompanist.insets.systemBarsPadding
24 | import com.google.accompanist.systemuicontroller.SystemUiController
25 | import com.wenull.mathyourbrain.data.local.entities.User
26 | import com.wenull.mathyourbrain.models.response.SigninResponse
27 | import com.wenull.mathyourbrain.models.response.UpdateGameResponse
28 | import com.wenull.mathyourbrain.ui.components.Timer
29 | import com.wenull.mathyourbrain.ui.components.gamescreen.GameCompleted
30 | import com.wenull.mathyourbrain.ui.components.gamescreen.Option
31 | import com.wenull.mathyourbrain.ui.components.gamescreen.ResignAlertDialog
32 | import com.wenull.mathyourbrain.ui.screens.splash.CTAButton
33 | import com.wenull.mathyourbrain.ui.theme.AppFont
34 | import com.wenull.mathyourbrain.ui.theme.CTAButtonTextStyle
35 | import com.wenull.mathyourbrain.ui.theme.QuestionNumberTextStyle
36 | import com.wenull.mathyourbrain.ui.theme.QuestionTextStyle
37 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
38 | import com.wenull.mathyourbrain.viewmodels.Task
39 | import kotlinx.coroutines.delay
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | var points: Int = 0
49 | val answers = mutableListOf()
50 | val correctQuestions = mutableListOf()
51 |
52 | val tag = "654987"
53 |
54 | @OptIn(ExperimentalUnitApi::class)
55 | @Composable
56 | fun GameScreen(navController: NavController, viewModel: MainViewModel, modifier: Modifier, systemUiController: SystemUiController) {
57 |
58 |
59 |
60 | val useDarkIcons = MaterialTheme.colors.isLight
61 | val users by viewModel.users.observeAsState(null)
62 | val value by viewModel.value
63 | var isSubmitButtonAvailable by remember{ mutableStateOf(false) }
64 |
65 | SideEffect {
66 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
67 | }
68 |
69 |
70 |
71 |
72 | val createGameResponse by viewModel.createGameResponse
73 | val user = users?.get(0)
74 |
75 | if(user!=null) {
76 | if (createGameResponse != null){
77 | if (createGameResponse!!.questions.size> 0) {
78 | var currentQuestionNumber by remember { mutableStateOf(1) }
79 |
80 | var resignDialogVisible by remember { mutableStateOf(false) }
81 | var gameCompletedDialogVisible by remember { mutableStateOf(false) }
82 | var newRating by remember{ mutableStateOf(user.rating)}
83 | var correctQuestionsForDialog by remember{ mutableStateOf(0)}
84 | var completedTimeForDialog by remember{ mutableStateOf(0L)}
85 | var scoreForDialog by remember{ mutableStateOf(0)}
86 | val currentTime by viewModel.currentTime.observeAsState()
87 |
88 | Column(
89 | Modifier
90 | .fillMaxSize()
91 | .systemBarsPadding()
92 | .verticalScroll(rememberScrollState(), true), horizontalAlignment = Alignment.CenterHorizontally
93 | ) {
94 | BackHandler() {
95 | resignDialogVisible = true
96 | }
97 |
98 |
99 | if (gameCompletedDialogVisible) {
100 |
101 | GameCompleted(newGame = {
102 | correctQuestionsForDialog = 0
103 | gameCompletedDialogVisible = false
104 | viewModel.createGame(user)
105 | navController.popBackStack()
106 | navController.navigate(com.wenull.mathyourbrain.GameScreen)
107 | }, leave = {
108 | correctQuestionsForDialog = 0
109 | gameCompletedDialogVisible = false
110 | navController.popBackStack()
111 |
112 | }, newRating = newRating, correctQuestions = correctQuestionsForDialog, completedTime = completedTimeForDialog, totalScore = 40, scoredPoints = scoreForDialog)
113 | }
114 |
115 |
116 | if (resignDialogVisible) {
117 | ResignAlertDialog(yes = {
118 |
119 | viewModel.updateGame(
120 | userId = user.id,
121 | gameId = createGameResponse!!.id,
122 | correctQuestions,
123 | completedTime = (((20*10000 - viewModel.currentTime.value?.peekContent()!!)/ 1000.0)),
124 | points,
125 | resigned = true,
126 | rating = getRatingByPoints(points, user.rating),
127 | object : Task {
128 | override fun whileLoading() {
129 | gameCompletedDialogVisible = false
130 | }
131 |
132 | override fun onSucess(data: UpdateGameResponse) {
133 |
134 | gameCompletedDialogVisible = true
135 | scoreForDialog = points
136 |
137 | completedTimeForDialog = data.completedTime.toLong()
138 | println("798040 completed tim onsucess: ${completedTimeForDialog}")
139 | correctQuestionsForDialog = correctQuestions.size
140 | newRating = data.rating
141 | points = 0
142 | answers.clear()
143 | correctQuestions.clear()
144 | }
145 |
146 | override fun onError(error: String) {
147 |
148 | gameCompletedDialogVisible = false
149 | }
150 | })
151 | viewModel.stopTimer()
152 |
153 | resignDialogVisible = false
154 | }) {
155 | resignDialogVisible = false
156 | }
157 | }
158 |
159 | currentTime?.getContentIfNotHandled()?.let {
160 | Timer(
161 | totalTime = 1000L * 200,
162 | modifier = Modifier.padding(top = 10.dp),
163 | value = value,
164 | currentTime = it,
165 | ) {
166 | Log.i(tag, "time finished!")
167 | viewModel.updateGame(
168 | userId = user.id,
169 | gameId = createGameResponse!!.id,
170 | correctQuestions,
171 | completedTime = (((20 * 10000 - viewModel.currentTime.value?.peekContent()!!) / 1000.0)),
172 | points,
173 | resigned = true,
174 | rating = getRatingByPoints(points, user.rating),
175 | object : Task {
176 | override fun whileLoading() {
177 |
178 | }
179 |
180 | override fun onSucess(data: UpdateGameResponse) {
181 | gameCompletedDialogVisible = true
182 | completedTimeForDialog = data.completedTime.toLong()
183 | scoreForDialog = data.scoredPoints
184 | correctQuestionsForDialog = data.correctQuestions.size
185 | newRating = data.rating
186 | points = 0
187 | answers.clear()
188 | correctQuestions.clear()
189 |
190 | }
191 |
192 | override fun onError(error: String) {
193 |
194 |
195 | }
196 | })
197 | viewModel.stopTimer()
198 | }
199 | }
200 |
201 |
202 |
203 | Column(
204 | horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
205 | .fillMaxWidth(1f)
206 | .padding(horizontal = 15.dp)
207 | ) {
208 |
209 | Text(
210 | "$currentQuestionNumber/20 ${createGameResponse!!.questions[currentQuestionNumber - 1].correctOption}",
211 | style = QuestionNumberTextStyle,
212 | modifier = Modifier.padding(top = 65.dp, bottom = 15.dp),
213 | textAlign = TextAlign.Center
214 | )
215 | Text(
216 | createGameResponse!!.questions[currentQuestionNumber - 1].question,
217 | style = QuestionTextStyle,
218 | modifier = Modifier.padding(
219 | top = 10.dp,
220 | bottom = 35.dp,
221 | start = 15.dp,
222 | end = 15.dp
223 | ),
224 | textAlign = TextAlign.Center
225 | )
226 |
227 | createGameResponse!!.questions[currentQuestionNumber - 1].options.forEachIndexed { index, option ->
228 | Option(index = index, text = option) { index ->
229 | answers.add(index)
230 | if (createGameResponse!!.questions[currentQuestionNumber - 1].correctOption == index) {
231 | points += 2
232 | correctQuestions.add(createGameResponse!!.questions[currentQuestionNumber - 1].id)
233 | }
234 | if (currentQuestionNumber < 20) {
235 | currentQuestionNumber = (currentQuestionNumber + 1)
236 | } else {
237 | isSubmitButtonAvailable = true
238 | }
239 |
240 | }
241 | }
242 | }
243 |
244 | if (isSubmitButtonAvailable)
245 | CTAButton(onClick = {
246 |
247 | viewModel.updateGame(
248 | userId = user.id,
249 | gameId = createGameResponse!!.id,
250 | correctQuestions,
251 | completedTime = (((20*10000 -viewModel.currentTime.value?.peekContent()!! )/ 1000.0)),
252 | points,
253 | resigned = false,
254 | rating = getRatingByPoints(points, user.rating),
255 | object : Task {
256 | override fun whileLoading() {
257 |
258 | }
259 |
260 | override fun onSucess(data: UpdateGameResponse) {
261 |
262 | gameCompletedDialogVisible = true
263 | completedTimeForDialog = data.completedTime.toLong()
264 | scoreForDialog = points
265 | correctQuestionsForDialog = correctQuestions.size
266 | newRating = data.rating
267 | points = 0
268 | answers.clear()
269 | correctQuestions.clear()
270 |
271 | }
272 |
273 | override fun onError(error: String) {
274 |
275 | Log.i("124478", error)
276 |
277 | }
278 | })
279 | viewModel.stopTimer()
280 | }, isPrimary = true, text = "Submit")
281 | }
282 |
283 | }
284 | }}
285 | }
286 |
287 |
288 | fun getRatingByPoints(point: Int, initalRating: Int): Int{
289 | val a: Double = (((point - 20.0)/40.0)*10.0)
290 | val gif = Math.ceil(a)
291 | val delta_r = gif*2
292 | return initalRating+delta_r.toInt()
293 | }
294 |
295 |
296 |
297 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/main/HomeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.main
2 |
3 | import android.annotation.SuppressLint
4 | import android.icu.text.SimpleDateFormat
5 | import android.icu.util.TimeZone
6 | import android.os.Build
7 | import androidx.annotation.RequiresApi
8 | import androidx.compose.foundation.*
9 | import androidx.compose.foundation.layout.*
10 | import androidx.compose.foundation.lazy.LazyColumn
11 | import androidx.compose.foundation.lazy.items
12 | import androidx.compose.foundation.shape.RoundedCornerShape
13 | import androidx.compose.material.*
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.runtime.SideEffect
16 | import androidx.compose.runtime.getValue
17 | import androidx.compose.runtime.livedata.observeAsState
18 | import androidx.compose.ui.Alignment
19 | import androidx.compose.ui.Alignment.Companion.BottomCenter
20 | import androidx.compose.ui.Alignment.Companion.CenterVertically
21 | import androidx.compose.ui.Modifier
22 | import androidx.compose.ui.draw.clip
23 | import androidx.compose.ui.graphics.Color
24 | import androidx.compose.ui.layout.ContentScale
25 | import androidx.compose.ui.res.painterResource
26 | import androidx.compose.ui.text.TextStyle
27 | import androidx.compose.ui.text.font.FontWeight
28 | import androidx.compose.ui.text.style.TextAlign
29 | import androidx.compose.ui.unit.dp
30 | import androidx.compose.ui.unit.sp
31 | import androidx.navigation.NavController
32 | import coil.compose.AsyncImage
33 | import coil.compose.rememberImagePainter
34 | import com.google.accompanist.insets.systemBarsPadding
35 | import com.google.accompanist.systemuicontroller.SystemUiController
36 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
37 | import com.wenull.mathyourbrain.R
38 | import com.wenull.mathyourbrain.data.local.entities.GameX
39 | import com.wenull.mathyourbrain.models.basic.Game
40 | import com.wenull.mathyourbrain.ui.components.Header
41 | import com.wenull.mathyourbrain.ui.screens.splash.CTAButton
42 | import com.wenull.mathyourbrain.ui.theme.AppFont
43 |
44 |
45 | val usernameTextStyle = TextStyle(
46 | fontFamily = AppFont,
47 | fontWeight = FontWeight.Bold,
48 | fontSize = 16.sp,
49 | color = Color(0xFF000000),
50 | letterSpacing = 0.sp
51 | )
52 |
53 | val ratingTextStyle = TextStyle(
54 | fontFamily = AppFont,
55 | fontWeight = FontWeight.Normal,
56 | fontSize = 12.sp,
57 | color = Color(0xFF000000),
58 | letterSpacing = 0.sp
59 | )
60 |
61 | val tabTextStyle = TextStyle(
62 | fontFamily = AppFont,
63 | fontWeight = FontWeight.Medium,
64 | fontSize = 13.75.sp,
65 | color = Color(0xFF000000),
66 | letterSpacing = 0.sp
67 | )
68 |
69 |
70 | @RequiresApi(Build.VERSION_CODES.N)
71 | @ExperimentalFoundationApi
72 | @Composable
73 | fun HomeScreen(navController: NavController, viewModel: MainViewModel, modifier: Modifier, systemUiController: SystemUiController) {
74 |
75 |
76 |
77 | val useDarkIcons = MaterialTheme.colors.isLight
78 | val users by viewModel.users.observeAsState(null)
79 | SideEffect {
80 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
81 | }
82 | if(users != null)
83 | {if( users!!.size >0) {
84 | val user = users?.get(0);
85 | if(user!=null ) {
86 |
87 |
88 |
89 | Box(
90 | Modifier
91 | .systemBarsPadding(true)
92 | .fillMaxSize(1f),
93 | ) {
94 |
95 | Column(Modifier.verticalScroll(rememberScrollState(), true)) {
96 | Header(user = user, modifier = Modifier.align(Alignment.CenterHorizontally)) {
97 |
98 | }
99 |
100 | Row(
101 | Modifier
102 | .align(Alignment.CenterHorizontally)
103 | .fillMaxWidth(1f)
104 | .padding(horizontal = 10.dp, vertical = 5.dp),
105 | horizontalArrangement = Arrangement.SpaceEvenly
106 | ) {
107 |
108 | NewGameCard {
109 | viewModel.createGame(user)
110 | navController.navigate(com.wenull.mathyourbrain.GameScreen)
111 | }
112 |
113 | LeadershipCard {
114 | viewModel.getLeaderboard(user)
115 | navController.navigate(com.wenull.mathyourbrain.LeaderBoard)
116 | }
117 |
118 | LessonsCard {
119 |
120 | }
121 |
122 |
123 | }
124 |
125 | Box(Modifier.padding(start = 15.dp, top = 15.dp, bottom = 100.dp, end = 15.dp)) {
126 | GamesPlayedTable(games = user.games)
127 | }
128 | }
129 |
130 | CTAButton(onClick = {
131 | viewModel.createGame(user)
132 | navController.navigate(com.wenull.mathyourbrain.GameScreen)
133 | }, isPrimary = true, text = "New Game", modifier = Modifier
134 | .align(
135 | BottomCenter
136 | )
137 | .padding(bottom = 15.dp))
138 |
139 |
140 | }
141 |
142 |
143 |
144 |
145 |
146 |
147 | }
148 | }
149 | }
150 | }
151 |
152 |
153 | @Composable
154 | fun NewGameCard(onClick: () -> Unit){
155 | Box(
156 | Modifier
157 | .padding(horizontal = 5.dp, vertical = 12.dp)
158 | .clip(
159 | RoundedCornerShape(13.dp)
160 | )
161 | .clickable {
162 | onClick()
163 | }
164 | .background(Color(248, 248, 248))
165 | ) {
166 | Column(
167 | Modifier
168 | .padding(horizontal = 10.dp, vertical = 10.dp),
169 | horizontalAlignment = Alignment.CenterHorizontally
170 | ) {
171 |
172 | Image(
173 | painter = painterResource(id = R.drawable.plus__),
174 | contentDescription = null,
175 | modifier = Modifier
176 | .height(90.dp)
177 | .aspectRatio(1f / 1f)
178 | .padding(13.dp)
179 | )
180 |
181 | Text(
182 | text = "New Game",
183 | style = tabTextStyle,
184 | modifier = Modifier
185 | .padding(bottom = 15.dp, start = 13.dp, end = 13.dp),
186 | textAlign = TextAlign.Center
187 | )
188 |
189 |
190 | }
191 | }
192 | }
193 |
194 | @Composable
195 | fun LeadershipCard(onClick: () -> Unit){
196 | Box(
197 | Modifier
198 | .padding(horizontal = 5.dp, vertical = 12.dp)
199 | .clip(
200 | RoundedCornerShape(13.dp)
201 | )
202 | .clickable { onClick() }
203 | .background(Color(248, 248, 248))) {
204 | Column( Modifier
205 | .padding(horizontal = 5.dp, vertical = 10.dp),
206 | horizontalAlignment = Alignment.CenterHorizontally
207 | ) {
208 |
209 | Image(
210 | painter = painterResource(id = R.drawable.pi),
211 | contentDescription = null,
212 | modifier = Modifier
213 | .height(90.dp)
214 | .aspectRatio(1f / 1f)
215 | .padding(13.dp)
216 | )
217 |
218 | Text(
219 | text = "Leaderboard",
220 | style = tabTextStyle,
221 | modifier = Modifier
222 | .padding(bottom = 15.dp, start = 13.dp, end = 13.dp),
223 | textAlign = TextAlign.Center
224 | )
225 |
226 |
227 | }
228 | }
229 | }
230 |
231 | @Composable
232 | fun LessonsCard(onClick: () -> Unit){
233 | Box(
234 | Modifier
235 | .padding(horizontal = 5.dp, vertical = 12.dp)
236 |
237 | .clip(
238 | RoundedCornerShape(13.dp)
239 | )
240 | .clickable {
241 | onClick()
242 | }
243 | .background(Color(248, 248, 248))) {
244 | Column( Modifier
245 | .padding(horizontal = 10.dp, vertical = 10.dp),
246 | horizontalAlignment = Alignment.CenterHorizontally
247 | ) {
248 |
249 | Image(
250 | painter = painterResource(id = R.drawable.google_classroom),
251 | contentDescription = null,
252 | modifier = Modifier
253 | .height(90.dp)
254 | .aspectRatio(1f / 1f)
255 | .padding(13.dp)
256 | )
257 |
258 | Text(
259 | text = "Lessons",
260 | style = tabTextStyle,
261 | modifier = Modifier
262 | .padding(bottom = 15.dp, start = 13.dp, end = 13.dp),
263 | textAlign = TextAlign.Center
264 | )
265 |
266 |
267 | }
268 | }
269 | }
270 |
271 |
272 |
273 | val OverlineTextStyle = TextStyle(
274 | fontFamily = AppFont,
275 | fontWeight = FontWeight.Normal,
276 | fontSize = 13.sp,
277 | color = Color(109,109,109),
278 | letterSpacing = 2.sp
279 | )
280 |
281 | val TableHeaderTextStyle = TextStyle(
282 | fontFamily = AppFont,
283 | fontWeight = FontWeight.Medium,
284 | fontSize = 12.sp,
285 | color = Color(164,164,164),
286 | letterSpacing = 0.25.sp
287 | )
288 | val TableContentTextStyle = TextStyle(
289 | fontFamily = AppFont,
290 | fontWeight = FontWeight.Normal,
291 | fontSize = 15.25.sp,
292 | color = Color(95, 95, 95, 255),
293 | letterSpacing = 0.95.sp
294 | )
295 |
296 |
297 |
298 | @RequiresApi(Build.VERSION_CODES.N)
299 | @OptIn(ExperimentalFoundationApi::class)
300 | @Composable
301 | fun GamesPlayedTable(games: List){
302 |
303 | var games = games.reversed()
304 |
305 | Column() {
306 | Text(text = "RECENT GAMES", style = OverlineTextStyle, modifier = Modifier.padding(horizontal = 10.5.dp, vertical = 20.dp))
307 |
308 | Box(
309 | Modifier
310 | .clip(RoundedCornerShape(16.dp))
311 |
312 | .border(2.86.dp, Color(248, 248, 248, 255), RoundedCornerShape(16.dp))
313 | .fillMaxWidth(1f)
314 |
315 | ){
316 | Row(
317 | Modifier
318 | .padding(start = 20.dp, end = 20.dp, top = 10.dp, bottom = 20.dp)
319 | .fillMaxWidth(1f), horizontalArrangement = Arrangement.SpaceBetween) {
320 | Column(){
321 | Text("Date", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp))
322 |
323 | games.forEach(){ game->
324 | Text(text = "${convertToCustomFormat(game.createdAt)}", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp))
325 | }
326 | }
327 |
328 | Column(){
329 | Text("Time", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp))
330 |
331 | games.forEach(){ game->
332 | Text(text = "${game.completedTime/60}m ${game.completedTime%60}s", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp))
333 | }
334 | }
335 |
336 | Column(){
337 | Text("Score", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp))
338 |
339 | games.forEach(){ game->
340 | Text(text = "${game.scoredPoints}", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp))
341 | }
342 | }
343 | Column(){
344 | Text("Rating", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp))
345 |
346 | games.forEach(){ game->
347 | Text(text = "${game.rating}", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp))
348 | }
349 | }
350 | }
351 |
352 | }
353 | }
354 |
355 |
356 |
357 | }
358 |
359 | @SuppressLint("SimpleDateFormat")
360 | private fun convertToCustomFormat(dateStr: String?): String {
361 | val utc = TimeZone.getTimeZone("UTC")
362 | val sourceFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
363 | val destFormat = SimpleDateFormat("dd/MM/YYYY")
364 | sourceFormat.timeZone = utc
365 | val convertedDate = sourceFormat.parse(dateStr)
366 | return destFormat.format(convertedDate)
367 | }
368 |
369 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/main/LeaderBoard.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.main
2 |
3 | import androidx.compose.foundation.border
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.foundation.rememberScrollState
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.foundation.verticalScroll
8 | import androidx.compose.material.MaterialTheme
9 | import androidx.compose.material.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.runtime.SideEffect
12 | import androidx.compose.runtime.getValue
13 | import androidx.compose.runtime.livedata.observeAsState
14 | import androidx.compose.runtime.remember
15 | import androidx.compose.ui.Alignment
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.draw.clip
18 | import androidx.compose.ui.graphics.Color
19 | import androidx.compose.ui.text.TextStyle
20 | import androidx.compose.ui.text.font.FontWeight
21 | import androidx.compose.ui.text.style.TextAlign
22 | import androidx.compose.ui.unit.dp
23 | import androidx.compose.ui.unit.sp
24 | import androidx.navigation.NavController
25 | import coil.compose.AsyncImage
26 | import com.google.accompanist.insets.systemBarsPadding
27 | import com.google.accompanist.systemuicontroller.SystemUiController
28 | import com.wenull.mathyourbrain.ui.theme.AppFont
29 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
30 |
31 |
32 | val LeaderboardTitle = TextStyle(
33 | fontFamily = AppFont,
34 | fontWeight = FontWeight.Bold,
35 | fontSize = 33.02.sp,
36 | color = Color(0xFF000000),
37 | letterSpacing = 0.25.sp
38 | )
39 |
40 |
41 | @Composable
42 | fun LeaderBoard(navController: NavController, viewModel: MainViewModel, modifier: Modifier, systemUiController: SystemUiController) {
43 |
44 |
45 |
46 | val useDarkIcons = MaterialTheme.colors.isLight
47 | val users by viewModel.users.observeAsState(null)
48 | SideEffect {
49 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
50 | }
51 |
52 | val getLeaderboardResponse by remember { viewModel.leaderboardResponse }
53 |
54 | if(getLeaderboardResponse!= null){
55 | val list = getLeaderboardResponse
56 |
57 | Column(
58 | Modifier
59 | .systemBarsPadding()
60 | .fillMaxSize()
61 | .verticalScroll(rememberScrollState(), true)){
62 | Text("Leaderboard", style = LeaderboardTitle, modifier = Modifier.padding(horizontal = 20.dp, vertical = 30.dp))
63 |
64 | Box(
65 | Modifier
66 | .clip(RoundedCornerShape(16.dp))
67 |
68 | .fillMaxWidth(1f)
69 |
70 | ){
71 | Column(Modifier
72 | .padding(start = 20.dp, end = 20.dp, top = 10.dp, bottom = 20.dp)
73 | .fillMaxSize(1f),) {
74 | Row(Modifier
75 | .fillMaxWidth(1f),){
76 | Text("Rank", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp).fillMaxWidth(1/6f), textAlign = TextAlign.Start)
77 | Text("Player", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp ).fillMaxWidth(1/1.4f), textAlign = TextAlign.Start)
78 | Text("Rating", style = TableHeaderTextStyle, modifier = Modifier.padding(8.5.dp), textAlign = TextAlign.Start)
79 | }
80 | list?.forEachIndexed() {index, player ->
81 | Row(
82 | Modifier.fillMaxWidth(1f), verticalAlignment = Alignment.CenterVertically
83 | ) {
84 | Text(text = "#$index", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp), textAlign = TextAlign.Start)
85 | Row( modifier = Modifier.padding(8.5.dp).fillMaxWidth(1/1.3f), verticalAlignment = Alignment.CenterVertically) {
86 | AsyncImage(
87 | model = player.avatar,
88 | modifier = Modifier
89 | .size(40.dp)
90 | .padding(end = 5.dp),
91 | contentDescription = null
92 | )
93 | Text(text = "${player.username}", style = TableContentTextStyle, color = Color.Black,modifier = Modifier.fillMaxSize())
94 | }
95 | Text(text = "${player.rating}", style = TableContentTextStyle, modifier = Modifier.padding(8.5.dp), textAlign = TextAlign.Start)
96 |
97 | }
98 | }
99 |
100 | }
101 | }
102 |
103 | }
104 | }
105 |
106 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/screens/splash/SplashScreen.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.screens.splash
2 |
3 | import android.view.animation.OvershootInterpolator
4 | import androidx.compose.animation.core.tween
5 | import androidx.compose.foundation.Image
6 | import androidx.compose.foundation.background
7 | import androidx.compose.foundation.clickable
8 | import androidx.compose.foundation.interaction.MutableInteractionSource
9 | import androidx.compose.foundation.layout.*
10 | import androidx.compose.foundation.shape.RoundedCornerShape
11 | import androidx.compose.material.*
12 | import androidx.compose.material.ripple.rememberRipple
13 | import androidx.compose.runtime.*
14 | import androidx.compose.runtime.livedata.observeAsState
15 | import androidx.compose.ui.Alignment
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.draw.clip
18 | import androidx.compose.ui.draw.scale
19 | import androidx.compose.ui.graphics.Color
20 | import androidx.compose.ui.res.painterResource
21 | import androidx.compose.ui.text.TextStyle
22 | import androidx.compose.ui.text.font.FontWeight
23 | import androidx.compose.ui.text.style.TextAlign
24 | import androidx.compose.ui.unit.dp
25 | import androidx.compose.ui.unit.sp
26 | import androidx.lifecycle.viewmodel.compose.viewModel
27 | import androidx.navigation.NavController
28 | import com.google.accompanist.systemuicontroller.SystemUiController
29 | import com.qrate.android.*
30 | import com.wenull.mathyourbrain.HomeScreen
31 | import com.wenull.mathyourbrain.R
32 | import com.wenull.mathyourbrain.SignUp
33 | import com.wenull.mathyourbrain.Splash
34 | import com.wenull.mathyourbrain.ui.theme.AppFont
35 | import com.wenull.mathyourbrain.ui.theme.CTAButtonTextStyle
36 | import com.wenull.mathyourbrain.viewmodels.MainViewModel
37 | import kotlinx.coroutines.delay
38 |
39 | @Composable
40 | fun SplashScreen(systemUiController: SystemUiController, navController: NavController, viewModel: MainViewModel = viewModel()) {
41 | val scale = remember {
42 | androidx.compose.animation.core.Animatable(0f)
43 | }
44 | val useDarkIcons = MaterialTheme.colors.isLight
45 | val users by viewModel.users.observeAsState(null)
46 | SideEffect {
47 | systemUiController.setSystemBarsColor(Color.White, darkIcons = useDarkIcons)
48 | }
49 |
50 | LaunchedEffect(key1 = true) {
51 | scale.animateTo(
52 | targetValue = 0.7f,
53 | animationSpec = tween(
54 | durationMillis = 800,
55 | easing = {
56 | OvershootInterpolator(4f).getInterpolation(it)
57 | }))
58 | delay(500L)
59 |
60 |
61 | if(viewModel.accessToken.value == null) {
62 | navController.navigate(SignUp) {
63 | popUpTo(Splash) { inclusive = true }
64 | }
65 | }else{
66 | navController.navigate(HomeScreen) {
67 | popUpTo(Splash) { inclusive = true }
68 | }
69 | }
70 | }
71 |
72 | // Image
73 | Box(contentAlignment = Alignment.Center,
74 | modifier = Modifier
75 | .fillMaxSize()
76 | .background(Color.White)) {
77 | Image(painterResource(id = R.drawable.ic_logo), contentDescription = "", modifier = Modifier.requiredWidth(150.dp).aspectRatio(1f/1f))
78 | }
79 | }
80 |
81 | val SplashAppNameTextStyle = TextStyle(
82 | fontFamily = AppFont,
83 | fontWeight = FontWeight.Bold,
84 | fontSize = 55.37.sp,
85 | color = Color.White,
86 | lineHeight = 24.sp
87 | )
88 |
89 |
90 | @Composable
91 | fun CTAButton(onClick: () -> Unit, isPrimary: Boolean, text: String, modifier : Modifier = Modifier, elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
92 | ){
93 | var bgColor = Color(0xFFFAF8F8)
94 | var textColor = Color.Black
95 | if(isPrimary){
96 | textColor = Color(0xFFFFFFFF)
97 | bgColor = Color.Black
98 | }
99 | val interactionSource = remember { MutableInteractionSource() }
100 | Surface(modifier = modifier
101 | .fillMaxWidth(0.9f)
102 | .clip(RoundedCornerShape(15.dp)),
103 | elevation = elevation.elevation(interactionSource).value,
104 |
105 | ) {
106 | Box(modifier = Modifier
107 |
108 | .clickable { onClick() }
109 | .background(bgColor)
110 | .padding(20.dp)
111 | , contentAlignment = Alignment.Center){
112 | Text(text = text, color = textColor, style = CTAButtonTextStyle)
113 | }
114 | }
115 |
116 |
117 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.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)
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.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/java/com/wenull/mathyourbrain/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.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 | import androidx.compose.ui.graphics.Color
9 |
10 | private val DarkColorPalette = darkColors(
11 | primary = Purple200,
12 | primaryVariant = Purple700,
13 | secondary = Teal200
14 | )
15 |
16 | private val LightColorPalette = lightColors(
17 | primary = Color.Black,
18 | primaryVariant = Color(0xFF627BFF),
19 | secondary = Color(0xFF4B68FF),
20 |
21 | /* Other default colors to override
22 | background = Color.White,
23 | surface = Color.White,
24 | onPrimary = Color.White,
25 | onSecondary = Color.Black,
26 | onBackground = Color.Black,
27 | onSurface = Color.Black,
28 | */
29 | )
30 |
31 |
32 | @Composable
33 | fun MathYourBrainTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
34 | val colors = LightColorPalette
35 |
36 | MaterialTheme(
37 | colors = colors,
38 | typography = Typography,
39 | shapes = Shapes,
40 | content = content
41 | )
42 | }
43 |
44 | @Composable
45 | fun SplashTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
46 | val colors = SplashColorPalette
47 |
48 | MaterialTheme(
49 | colors = colors,
50 | typography = Typography,
51 | shapes = Shapes,
52 | content = content
53 | )
54 | }
55 |
56 | private val SplashColorPalette = lightColors(
57 | primary = Color.Black,
58 | primaryVariant = Color(0xFF627BFF),
59 | secondary = Color(0xFF4B68FF),
60 |
61 |
62 | background = Color.Black
63 |
64 | )
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.ui.theme
2 | import androidx.compose.material.Typography
3 | import androidx.compose.ui.graphics.Color
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.Font
6 | import androidx.compose.ui.text.font.FontFamily
7 | import androidx.compose.ui.text.font.FontStyle
8 | import androidx.compose.ui.text.font.FontWeight
9 | import androidx.compose.ui.unit.sp
10 | import com.wenull.mathyourbrain.R
11 |
12 | val AppFont =FontFamily(
13 | Font(R.font.circularstdbook, FontWeight.Normal),
14 | Font(R.font.circularstdmedium, FontWeight.Medium),
15 | Font(R.font.circularstdlight, FontWeight.Light),
16 | Font(R.font.circularstdbold, FontWeight.Bold)
17 | )
18 |
19 |
20 | val NewRatingOverlineTextStyle = TextStyle(
21 | fontFamily = AppFont,
22 | fontWeight = FontWeight.Medium,
23 | fontSize = 14.sp,
24 | color = Color(0xFF929292),
25 | letterSpacing = 0.25.sp
26 | )
27 | val NewRatingTextStyle = TextStyle(
28 | fontFamily = AppFont,
29 | fontWeight = FontWeight.Bold,
30 | fontSize = 35.sp,
31 | color = Color(0xFF000000),
32 | letterSpacing = 0.25.sp
33 | )
34 | val ScoreOverlineTextStyle = TextStyle(
35 | fontFamily = AppFont,
36 | fontWeight = FontWeight.Medium,
37 | fontSize = 12.sp,
38 | color = Color(0xFF929292),
39 | letterSpacing = 0.25.sp
40 | )
41 | val ScoreTextStyle = TextStyle(
42 | fontFamily = AppFont,
43 | fontWeight = FontWeight.Bold,
44 | fontSize = 20.sp,
45 | color = Color(0xFF000000),
46 | letterSpacing = 0.25.sp
47 | )
48 |
49 | val CTAButtonTextStyle = TextStyle(
50 | fontFamily = AppFont,
51 | fontWeight = FontWeight.Medium,
52 | fontSize = 18.sp,
53 | )
54 |
55 |
56 | val QuestionTextStyle = TextStyle(
57 | fontFamily = AppFont,
58 | fontWeight = FontWeight.Medium,
59 | fontSize = 18.sp,
60 | color = Color(0xFF000000),
61 | letterSpacing = 0.25.sp,
62 | lineHeight = 29.sp
63 | )
64 |
65 | val QuestionNumberTextStyle = TextStyle(
66 | fontFamily = AppFont,
67 | fontWeight = FontWeight.Normal,
68 | fontSize = 17.sp,
69 | color = Color(0xFFACACAC),
70 | letterSpacing =3.sp,
71 | lineHeight = 34.sp
72 | )
73 |
74 | val TimerTextStyle = TextStyle(
75 | fontFamily = AppFont,
76 | fontWeight = FontWeight.Medium,
77 | fontSize = 17.sp,
78 | color = Color(0xFFFFFFFF),
79 | letterSpacing = 1.sp,
80 | lineHeight = 34.sp
81 | )
82 |
83 | val OptionTextStyle = TextStyle(
84 | fontFamily = AppFont,
85 | fontWeight = FontWeight.Medium,
86 | fontSize = 18.sp,
87 | color = Color(0xFF7B7B7B),
88 | letterSpacing = 0.25.sp,
89 | lineHeight = 28.sp
90 | )
91 |
92 | val MemojiDialogTitle = TextStyle(
93 | fontFamily = AppFont,
94 | fontWeight = FontWeight.Bold,
95 | fontSize = 19.02.sp,
96 | color = Color(0xFF000000),
97 | letterSpacing = 0.25.sp
98 | )
99 |
100 |
101 | val Typography = Typography(
102 | body1 = TextStyle(
103 | fontFamily = AppFont,
104 | fontWeight = FontWeight.Normal,
105 | fontSize = 16.sp
106 | )
107 | /* Other default text styles to override
108 | button = TextStyle(
109 | fontFamily = FontFamily.Default,
110 | fontWeight = FontWeight.W500,
111 | fontSize = 14.sp
112 | ),
113 | caption = TextStyle(
114 | fontFamily = FontFamily.Default,
115 | fontWeight = FontWeight.Normal,
116 | fontSize = 12.sp
117 | )
118 | */
119 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/utils/Indicator.kt:
--------------------------------------------------------------------------------
1 | package com.qrate.android.utils
2 |
3 | /**
4 | * Used as a wrapper for data that is exposed via a LiveData that represents an event.
5 | */
6 | open class Indicator(private val content: T) {
7 |
8 | var hasBeenHandled = false
9 | private set // Allow external read but not write
10 |
11 | /**
12 | * Returns the content and prevents its use again.
13 | */
14 | fun getContentIfNotHandled(): T? {
15 | return if (hasBeenHandled) {
16 | null
17 | } else {
18 | hasBeenHandled = true
19 | content
20 | }
21 | }
22 |
23 | /**
24 | * Returns the content, even if it's already been handled.
25 | */
26 | fun peekContent(): T = content
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wenull/mathyourbrain/viewmodels/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain.viewmodels;
2 |
3 | import android.os.CountDownTimer
4 | import android.util.Log
5 | import androidx.compose.runtime.MutableState
6 | import androidx.compose.runtime.mutableStateOf
7 | import androidx.lifecycle.*
8 | import com.qrate.android.models.utils.DataState
9 | import com.qrate.android.utils.Indicator
10 | import com.wenull.mathyourbrain.data.local.entities.User
11 |
12 | import com.wenull.mathyourbrain.data.prefrences.UserPreferences;
13 | import com.wenull.mathyourbrain.models.requests.CreateGameRequest
14 | import com.wenull.mathyourbrain.models.requests.SigninRequest
15 | import com.wenull.mathyourbrain.models.requests.SignupRequest
16 | import com.wenull.mathyourbrain.models.requests.UpdateGameRequest
17 | import com.wenull.mathyourbrain.models.response.*
18 | import com.wenull.mathyourbrain.repo.AppRepository;
19 |
20 | import javax.inject.Inject;
21 |
22 | import dagger.hilt.android.lifecycle.HiltViewModel;
23 | import kotlinx.coroutines.flow.launchIn
24 | import kotlinx.coroutines.flow.onEach
25 | import kotlinx.coroutines.launch
26 |
27 | @HiltViewModel
28 | class MainViewModel @Inject constructor(
29 | private val savedStateHandle: SavedStateHandle,
30 | private val preferences: UserPreferences,
31 | private val repository: AppRepository
32 | ) : ViewModel() {
33 |
34 | val users: LiveData> = repository.users
35 | val accessToken:LiveData = preferences.accessToken.asLiveData()
36 | val debugToast= MutableLiveData>()
37 | val toast = MutableLiveData>()
38 |
39 | val isLoading: MutableState =mutableStateOf(false)
40 |
41 | fun saveUserDetails(token: String, user: User){
42 | viewModelScope.launch {
43 | preferences.saveAccessToken(accessToken = token)
44 | repository.saveUser(user)
45 | }
46 | }
47 |
48 |
49 | fun signup(signupRequest: SignupRequest, task: Task){
50 | viewModelScope.launch {
51 | repository.signUp(signupRequest).onEach {
52 | invokeTask(it, task)
53 | }.launchIn(viewModelScope)
54 | }
55 | }
56 |
57 | private fun invokeTask(dataState: DataState, task: Task){
58 | when(dataState){
59 | is DataState.Loading -> {
60 | isLoading.value = true
61 | task.whileLoading()
62 | }
63 | is DataState.Success -> {
64 | isLoading.value = false
65 | dataState.data?.let { it1 -> task.onSucess(it1) }
66 | }
67 | is DataState.Error -> {
68 | isLoading.value = false
69 | task.onError(dataState.error)
70 | }
71 | }
72 | }
73 |
74 |
75 | fun signin(signinRequest: SigninRequest, task: Task){
76 | viewModelScope.launch {
77 | repository.signIn(signinRequest).onEach {
78 | when(it){
79 | is DataState.Loading -> {
80 | isLoading.value = true
81 | task.whileLoading()
82 | }
83 | is DataState.Success -> {
84 | isLoading.value = false
85 | it.data?.let { it1 -> task.onSucess(it1) }
86 | }
87 | is DataState.Error -> {
88 | isLoading.value = false
89 | task.onError(it.error)
90 | }
91 | }
92 | }.launchIn(viewModelScope)
93 | }
94 | }
95 |
96 |
97 | fun getUser(user: User){
98 | viewModelScope.launch {
99 | repository.getUser("Bearer ${ accessToken.value!! }", user.id).onEach {
100 | when(it){
101 | is DataState.Loading -> {
102 | isLoading.value = true
103 | }
104 | is DataState.Success -> {
105 | isLoading.value = false
106 |
107 | it.data?.let { it1 -> repository.saveUser(it1.user) }
108 |
109 | }
110 | is DataState.Error -> {
111 | isLoading.value = false
112 | }
113 | }
114 | }.launchIn(viewModelScope)
115 | }
116 | }
117 |
118 | val leaderboardResponse = mutableStateOf(null)
119 |
120 | fun getLeaderboard(user: User){
121 | viewModelScope.launch {
122 | repository.getLeaderboard("Bearer ${ accessToken.value!! }", user.id).onEach {
123 | when(it){
124 | is DataState.Loading -> {
125 | isLoading.value = true
126 | }
127 | is DataState.Success -> {
128 | isLoading.value = false
129 | leaderboardResponse.value = it.data
130 | }
131 | is DataState.Error -> {
132 | isLoading.value = false
133 | }
134 | }
135 | }.launchIn(viewModelScope)
136 | }
137 | }
138 |
139 |
140 |
141 | val createGameResponse : MutableState = mutableStateOf(null)
142 |
143 | fun createGame(user: User){
144 | viewModelScope.launch {
145 | repository.createGame("Bearer ${ accessToken.value!! }", user.id, CreateGameRequest(user.rating, 20, 20, 200)).onEach {
146 | when(it){
147 | is DataState.Loading -> {
148 | isLoading.value = true
149 | }
150 | is DataState.Success -> {
151 | isLoading.value = false
152 | createGameResponse.value = it.data
153 | startTimer(1000L*200)
154 | }
155 | is DataState.Error -> {
156 | isLoading.value = false
157 | }
158 | }
159 | }.launchIn(viewModelScope)
160 | }
161 | }
162 |
163 | fun updateGame( userId: String, gameId: String, correctQuestions: List,completedTime: Double, scoredPoints: Int, resigned: Boolean, rating: Int,task: Task,){
164 | val updateGameRequest = UpdateGameRequest(Math.round(completedTime).toInt(), correctQuestions, rating, resigned, scoredPoints)
165 | viewModelScope.launch {
166 | repository.updateGame("Bearer ${ accessToken.value!! }", userId, gameId, updateGameRequest).onEach {
167 | when(it){
168 | is DataState.Loading -> {
169 | isLoading.value = true
170 | task.whileLoading()
171 | }
172 | is DataState.Success -> {
173 | isLoading.value = false
174 | it.data?.let { it1 -> task.onSucess(it1) }
175 | if(users.value!=null) {
176 | getUser(users.value!!.get(0))
177 | }
178 | }
179 | is DataState.Error -> {
180 | isLoading.value = false
181 |
182 | }
183 | }
184 | }.launchIn(viewModelScope)
185 | }
186 | }
187 |
188 |
189 | fun getAllAvatars(task: Task){
190 | viewModelScope.launch {
191 | repository.getAllAvatars().onEach {
192 | when(it){
193 | is DataState.Loading -> {
194 | isLoading.value = true
195 | task.whileLoading()
196 | }
197 | is DataState.Success -> {
198 | isLoading.value = false
199 | it.data?.let { it1 -> task.onSucess(it1) }
200 | }
201 | is DataState.Error -> {
202 |
203 | isLoading.value = false
204 | }
205 | }
206 | }.launchIn(viewModelScope)
207 | }
208 | }
209 |
210 | val currentTime= MutableLiveData>()
211 | val value = mutableStateOf(1F)
212 | val totalTime = mutableStateOf(1L)
213 | lateinit var countDownTimer: CountDownTimer
214 |
215 | fun startTimer(_totalTime:Long){
216 |
217 | totalTime.value = _totalTime
218 | currentTime.value = Indicator(_totalTime)
219 |
220 |
221 | countDownTimer = object : CountDownTimer(totalTime.value, 1L) {
222 | override fun onTick(millisUntilFinished: Long) {
223 | currentTime.value = Indicator(millisUntilFinished)
224 | value.value = currentTime.value!!.peekContent() / totalTime.value.toFloat()
225 | }
226 |
227 | override fun onFinish() {
228 | currentTime.value = Indicator(0L)
229 | }
230 |
231 | }
232 | countDownTimer.start()
233 |
234 | }
235 |
236 | fun stopTimer(){
237 |
238 |
239 | countDownTimer.cancel()
240 |
241 | }
242 |
243 |
244 | }
245 |
246 | interface Task{
247 | fun whileLoading()
248 | fun onSucess(data: T)
249 | fun onError(error: String)
250 | }
251 |
252 |
253 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/down.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/google_classroom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/drawable/google_classroom.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_warning.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/memoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/drawable/memoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/drawable/pi.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/plus__.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/drawable/plus__.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/star.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdblack.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdblack.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdblackitalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdblackitalic.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdbold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdbold.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdbolditalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdbolditalic.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdbook.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdbook.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdbookitalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdbookitalic.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdlight.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdlight.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdlightitalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdlightitalic.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdmedium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdmedium.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/circularstdmediumitalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/app/src/main/res/font/circularstdmediumitalic.otf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/loading.json:
--------------------------------------------------------------------------------
1 | {"v":"5.7.3","fr":60,"ip":13,"op":110,"w":1080,"h":1080,"nm":"BOXS","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":2,"ty":4,"nm":"7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":41.236,"s":[239.25,840.25,0],"to":[0,-50.042,0],"ti":[0,50.042,0]},{"t":75.599609375,"s":[239.25,540,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":34.363,"s":[239.25,540,0],"to":[0,-50.083,0],"ti":[0,50.083,0]},{"t":68.7265625,"s":[239.25,239.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":27.49,"s":[239.25,239.5,0],"to":[50.125,0,0],"ti":[-50.125,0,0]},{"t":61.853515625,"s":[540,239.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":20.617,"s":[540,239.5,0],"to":[49.917,0,0],"ti":[-49.917,0,0]},{"t":54.98046875,"s":[839.5,239.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":13.746,"s":[839.5,239.5,0],"to":[0,50.083,0],"ti":[0,-50.083,0]},{"i":{"x":0.218,"y":0.218},"o":{"x":0.167,"y":0.167},"t":48.109,"s":[839.5,540,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.218,"y":1},"o":{"x":0.546,"y":0},"t":64.908,"s":[839.5,540,0],"to":[-49.917,0,0],"ti":[0,0,0]},{"t":98,"s":[540,540,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":6.873,"s":[839.5,540,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.218,"y":0.218},"o":{"x":0.167,"y":0.167},"t":41.236,"s":[540,540,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.189,"y":1},"o":{"x":0.756,"y":0},"t":56,"s":[540,540,0],"to":[0,0,0],"ti":[0.083,-50.042,0]},{"t":89.091796875,"s":[539.5,840.25,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.218,"y":1},"o":{"x":0.714,"y":0},"t":0,"s":[540,540,0],"to":[-0.083,50.042,0],"ti":[0.083,-50.042,0]},{"i":{"x":0,"y":0},"o":{"x":1,"y":1},"t":34.363,"s":[539.5,840.25,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.186,"y":1},"o":{"x":0.742,"y":0},"t":48.109,"s":[539.5,840.25,0],"to":[-50.042,0,0],"ti":[50.042,0,0]},{"t":80.181640625,"s":[239.25,840.25,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1080,1080],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":150,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":74,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.994397750555,0.994397750555,0.994397750555,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[18.493,18.493],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Adjustment Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[540,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":20,"nm":"Tint","np":6,"mn":"ADBE Tint","ix":1,"en":1,"ef":[{"ty":2,"nm":"Map Black To","mn":"ADBE Tint-0001","ix":1,"v":{"a":0,"k":[0,0,0,0],"ix":1}},{"ty":2,"nm":"Map White To","mn":"ADBE Tint-0002","ix":2,"v":{"a":0,"k":[1,1,1,0],"ix":2}},{"ty":0,"nm":"Amount to Tint","mn":"ADBE Tint-0003","ix":3,"v":{"a":0,"k":100,"ix":3}},{"ty":6,"nm":"","mn":"ADBE Tint-0004","ix":4,"v":0}]}],"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Boxs Animation","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":225.1,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[540,540,0],"ix":1},"s":{"a":0,"k":[42,42,100],"ix":6}},"ao":0,"sy":[{"c":{"a":0,"k":[1,0,0,1],"ix":2},"s":{"a":0,"k":3,"ix":3},"ty":0,"nm":"Stroke"}],"tm":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[0.217]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":109,"s":[1.15]},{"t":301,"s":[5.017]}],"ix":2},"w":1080,"h":1080,"ip":0,"op":301,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":1,"nm":"bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[540,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sw":1080,"sh":1080,"sc":"#000000","ip":0,"op":301,"st":0,"bm":0}],"markers":[]}
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Math Your Brain
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/wenull/mathyourbrain/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.wenull.mathyourbrain
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 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | compose_version = '1.1.1'
4 | }
5 |
6 | dependencies {
7 |
8 | classpath 'com.google.dagger:hilt-android-gradle-plugin:2.38.1'
9 | }
10 | }// Top-level build file where you can add configuration options common to all sub-projects/modules.
11 | plugins {
12 | id 'com.android.application' version '7.2.0' apply false
13 | id 'com.android.library' version '7.2.0' apply false
14 | id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
15 | }
16 |
17 | task clean(type: Delete) {
18 | delete rootProject.buildDir
19 | }
--------------------------------------------------------------------------------
/file cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/file cover.png
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun May 22 23:13:19 IST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/mvvm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/mvvm.png
--------------------------------------------------------------------------------
/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 | }
14 | }
15 | rootProject.name = "Math Your Brain"
16 | include ':app'
17 |
--------------------------------------------------------------------------------
/shot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vishprometa/Math-Your-Brain/4089835c65a7c89c818283c357b26d9a5cf9cc36/shot1.png
--------------------------------------------------------------------------------