├── .idea
├── .name
├── sonarlint
│ └── issuestore
│ │ └── index.pb
├── .gitignore
├── codeStyles
│ └── codeStyleConfig.xml
├── easycode.ignore
├── compiler.xml
├── kotlinc.xml
├── dictionaries
│ └── Piotr.xml
├── vcs.xml
├── AndroidProjectSystem.xml
├── migrations.xml
├── misc.xml
├── deploymentTargetSelector.xml
├── gradle.xml
└── jarRepositories.xml
├── androidApp
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── square.webp
│ │ │ │ ├── circle_fill.webp
│ │ │ │ ├── circle_empty.webp
│ │ │ │ ├── logo_transparent.png
│ │ │ │ ├── bg_in_tile_exercise_disabled.xml
│ │ │ │ ├── bg_in_transparent.xml
│ │ │ │ ├── bg_in_button_help.xml
│ │ │ │ ├── bg_in_tile_exercise.xml
│ │ │ │ ├── ic_send_48dp.xml
│ │ │ │ ├── ic_add_black_24dp.xml
│ │ │ │ ├── ic_check.xml
│ │ │ │ ├── ic_star.xml
│ │ │ │ ├── ic_star_yellow_24dp.xml
│ │ │ │ ├── bg_in_tile_menu.xml
│ │ │ │ ├── bg_in_tile_mode_light.xml
│ │ │ │ ├── bg_in_tile_mode_dark.xml
│ │ │ │ ├── bg_gradient.xml
│ │ │ │ ├── ic_backspace_48dp.xml
│ │ │ │ ├── bg_in_button_yes.xml
│ │ │ │ ├── ic_gamepad_solid.xml
│ │ │ │ ├── bg_in_button_no.xml
│ │ │ │ ├── ic_dumbbell_solid.xml
│ │ │ │ ├── ic_trophy_solid.xml
│ │ │ │ ├── ic_settings_24dp.xml
│ │ │ │ ├── progress_drawable.xml
│ │ │ │ ├── ic_units.xml
│ │ │ │ ├── ic_help.xml
│ │ │ │ └── logo.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── values
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── preloaded_fonts.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── font_certs.xml
│ │ │ │ └── strings.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ └── ic_launcher.xml
│ │ │ ├── font
│ │ │ │ ├── fira_sans_thin.xml
│ │ │ │ └── fira_sans_medium.xml
│ │ │ ├── layout
│ │ │ │ ├── player_row.xml
│ │ │ │ ├── main_activity.xml
│ │ │ │ ├── score_row.xml
│ │ │ │ ├── fragment_exercise_list.xml
│ │ │ │ ├── fragment_battle_game.xml
│ │ │ │ ├── units_help_dialog.xml
│ │ │ │ ├── fragment_scoreboard.xml
│ │ │ │ ├── normal_exercise_item.xml
│ │ │ │ ├── divisibility_exercise_item.xml
│ │ │ │ ├── units_exercise_item.xml
│ │ │ │ ├── normal_rate_dialog.xml
│ │ │ │ ├── fragment_table_game.xml
│ │ │ │ ├── fragment_choose_player.xml
│ │ │ │ └── fragment_units_game.xml
│ │ │ ├── values-cs
│ │ │ │ └── strings.xml
│ │ │ ├── values-sk
│ │ │ │ └── strings.xml
│ │ │ ├── values-pl
│ │ │ │ └── strings.xml
│ │ │ ├── values-hu
│ │ │ │ └── strings.xml
│ │ │ ├── values-nl
│ │ │ │ └── strings.xml
│ │ │ ├── values-pt
│ │ │ │ └── strings.xml
│ │ │ ├── values-de
│ │ │ │ └── strings.xml
│ │ │ └── values-fr
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── octbit
│ │ │ │ └── rutmath
│ │ │ │ ├── util
│ │ │ │ ├── ViewExtension.kt
│ │ │ │ └── base
│ │ │ │ │ ├── DisposableViewModel.kt
│ │ │ │ │ ├── BaseFragment.kt
│ │ │ │ │ └── BaseApplication.kt
│ │ │ │ ├── data
│ │ │ │ ├── model
│ │ │ │ │ ├── PlayerWithExercises.kt
│ │ │ │ │ ├── Player.kt
│ │ │ │ │ ├── Score.kt
│ │ │ │ │ ├── Equation.kt
│ │ │ │ │ ├── Settings.kt
│ │ │ │ │ ├── EquationUnits.kt
│ │ │ │ │ ├── Operation.kt
│ │ │ │ │ └── ExerciseType.kt
│ │ │ │ ├── dao
│ │ │ │ │ ├── SettingsDao.kt
│ │ │ │ │ ├── ScoreDao.kt
│ │ │ │ │ ├── UserDao.kt
│ │ │ │ │ └── ExerciseTypeDao.kt
│ │ │ │ └── AppDatabase.kt
│ │ │ │ ├── ui
│ │ │ │ ├── fragment
│ │ │ │ │ ├── scoreboard
│ │ │ │ │ │ ├── ScoreboardViewHolder.kt
│ │ │ │ │ │ ├── ScoreboardAdapter.kt
│ │ │ │ │ │ └── ScoreboardFragment.kt
│ │ │ │ │ ├── choosePlayer
│ │ │ │ │ │ ├── PlayerViewHolder.kt
│ │ │ │ │ │ ├── ChoosePlayerAdapter.kt
│ │ │ │ │ │ └── ChoosePlayerViewModel.kt
│ │ │ │ │ ├── addSubList
│ │ │ │ │ │ ├── AddSubListAdapter.kt
│ │ │ │ │ │ └── AddSubViewHolder.kt
│ │ │ │ │ ├── mulDivList
│ │ │ │ │ │ ├── MulDivListAdapter.kt
│ │ │ │ │ │ └── MulDivViewHolder.kt
│ │ │ │ │ ├── unitsList
│ │ │ │ │ │ ├── UnitsListAdapter.kt
│ │ │ │ │ │ └── UnitsViewHolder.kt
│ │ │ │ │ ├── divisibilityList
│ │ │ │ │ │ ├── DivisibilityListAdapter.kt
│ │ │ │ │ │ └── DivisibilityViewHolder.kt
│ │ │ │ │ ├── MenuFragment.kt
│ │ │ │ │ └── chooseMode
│ │ │ │ │ │ └── ChooseModeFragment.kt
│ │ │ │ ├── view
│ │ │ │ │ ├── UnitsHelpDialog.kt
│ │ │ │ │ ├── NormalRateDialog.kt
│ │ │ │ │ ├── TableRateDialog.kt
│ │ │ │ │ └── GridSpacingItemDecoration.kt
│ │ │ │ └── activity
│ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── di
│ │ │ │ └── AppModule.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── octbit
│ │ │ └── rutmath
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── octbit
│ │ └── rutmath
│ │ └── ExampleInstrumentedTest.kt
└── build.gradle
├── fastlane
└── metadata
│ └── android
│ ├── en-US
│ ├── title.txt
│ ├── short_description.txt
│ ├── images
│ │ ├── icon.png
│ │ └── phoneScreenshots
│ │ │ ├── 1.jpg
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ └── 4.png
│ └── full_description.txt
│ ├── pl-PL
│ ├── title.txt
│ ├── short_description.txt
│ └── full_description.txt
│ └── pt-BR
│ ├── title.txt
│ ├── short_description.txt
│ └── full_description.txt
├── .gitattributes
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── iosApp
├── iosApp
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── iOSApp.swift
│ ├── Info.plist
│ └── ContentView.swift
├── Configuration
│ └── Config.xcconfig
└── iosApp.xcodeproj
│ └── project.xcworkspace
│ └── contents.xcworkspacedata
├── shared
├── src
│ ├── commonMain
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── octbit
│ │ │ └── rutmath
│ │ │ └── shared
│ │ │ ├── model
│ │ │ ├── Player.kt
│ │ │ ├── Score.kt
│ │ │ ├── Equation.kt
│ │ │ ├── Operation.kt
│ │ │ ├── Settings.kt
│ │ │ ├── EquationUnits.kt
│ │ │ └── ExerciseType.kt
│ │ │ ├── di
│ │ │ └── SharedModule.kt
│ │ │ ├── localization
│ │ │ └── StringProvider.kt
│ │ │ ├── data
│ │ │ └── DatabaseRepository.kt
│ │ │ └── game
│ │ │ └── EquationGenerator.kt
│ ├── iosMain
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── octbit
│ │ │ └── rutmath
│ │ │ └── shared
│ │ │ ├── di
│ │ │ └── IosSharedModule.kt
│ │ │ └── localization
│ │ │ └── IosStringProvider.kt
│ └── androidMain
│ │ └── kotlin
│ │ └── com
│ │ └── octbit
│ │ └── rutmath
│ │ └── shared
│ │ └── di
│ │ └── AndroidSharedModule.kt
└── build.gradle
├── .gitignore
├── metadata
└── com.octbit.rutmath.yml
├── gradle.properties
├── .github
└── workflows
│ ├── test.yml
│ ├── build.yml
│ └── release.yml
├── README.md
└── gradlew.bat
/.idea/.name:
--------------------------------------------------------------------------------
1 | RutMath
--------------------------------------------------------------------------------
/androidApp/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.idea/sonarlint/issuestore/index.pb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | RUTMath
--------------------------------------------------------------------------------
/fastlane/metadata/android/pl-PL/title.txt:
--------------------------------------------------------------------------------
1 | RUTMath
--------------------------------------------------------------------------------
/fastlane/metadata/android/pt-BR/title.txt:
--------------------------------------------------------------------------------
1 | RUTMath
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | A math learning app for children.
--------------------------------------------------------------------------------
/fastlane/metadata/android/pl-PL/short_description.txt:
--------------------------------------------------------------------------------
1 | Aplikacja do nauki matematyki dla dzieci.
--------------------------------------------------------------------------------
/fastlane/metadata/android/pt-BR/short_description.txt:
--------------------------------------------------------------------------------
1 | Um aplicativo matemático para crianças.
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':androidApp'
2 | include ':shared'
3 | rootProject.name='RutMath'
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/androidApp/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/square.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/drawable/square.webp
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/circle_fill.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/drawable/circle_fill.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/circle_empty.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/drawable/circle_empty.webp
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/logo_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/drawable/logo_transparent.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/przemarbor/RUTMath/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFF2FF
4 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/easycode.ignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | node_modules/
4 | dist/
5 | vendor/
6 | cache/
7 | .*/
8 | *.min.*
9 | *.test.*
10 | *.spec.*
11 | *.bundle.*
12 | *.bundle-min.*
13 | *.log
14 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/iosApp/iosApp/iOSApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct iOSApp: App {
5 | var body: some Scene {
6 | WindowGroup {
7 | ContentView()
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/iosApp/Configuration/Config.xcconfig:
--------------------------------------------------------------------------------
1 | TEAM_ID=
2 |
3 | PRODUCT_NAME=KotlinProject
4 | PRODUCT_BUNDLE_IDENTIFIER=org.example.project.KotlinProject$(TEAM_ID)
5 |
6 | CURRENT_PROJECT_VERSION=1
7 | MARKETING_VERSION=1.0
--------------------------------------------------------------------------------
/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/dictionaries/Piotr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | additionandsubtraction
5 | octbit
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/AndroidProjectSystem.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_tile_exercise_disabled.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/preloaded_fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @font/fira_sans_medium
5 | - @font/fira_sans_thin
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CADisableMinimumFrameDurationOnPhone
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_transparent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/util/ViewExtension.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.util
2 |
3 | import android.view.View
4 |
5 | fun View.gone() {
6 | visibility = View.GONE
7 | }
8 |
9 | fun View.visible() {
10 | visibility = View.VISIBLE
11 | }
12 |
13 | fun View.invisible() {
14 | visibility = View.INVISIBLE
15 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_button_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_tile_exercise.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_send_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/PlayerWithExercises.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.Embedded
4 | import androidx.room.Relation
5 |
6 | data class PlayerWithExercises(
7 | @Embedded val player: Player,
8 | @Relation(
9 | parentColumn = "nick",
10 | entityColumn = "userNick"
11 | )
12 | val scores: List
13 | )
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_add_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/Player.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import java.io.Serializable
7 |
8 | @Entity(tableName = "Player")
9 | data class Player(
10 | @PrimaryKey(autoGenerate = false)
11 | @ColumnInfo(name = "nick")
12 | val nick: String
13 | ) : Serializable
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/Player.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Player model representing a game player.
7 | *
8 | * @param nickname player's nickname
9 | * @param id unique identifier for the player
10 | */
11 | @Serializable
12 | data class Player(
13 | val nickname: String,
14 | val id: Int = 0
15 | )
--------------------------------------------------------------------------------
/androidApp/src/main/res/font/fira_sans_thin.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/font/fira_sans_medium.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_star.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_star_yellow_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/test/java/com/octbit/rutmath/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_tile_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_tile_mode_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/Score.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import java.io.Serializable
7 |
8 | @Entity(tableName = "Score")
9 | data class Score(
10 | @ColumnInfo(name = "nick")
11 | val nick: String,
12 | @ColumnInfo(name = "score")
13 | val score: Int,
14 | @PrimaryKey(autoGenerate = true)
15 | var id: Int = 0
16 | ) : Serializable
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_tile_mode_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/Score.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Score model representing a player's score in a game.
7 | *
8 | * @param playerName name of the player who achieved this score
9 | * @param score the score value achieved
10 | * @param id unique identifier for the score record
11 | */
12 | @Serializable
13 | data class Score(
14 | val playerName: String,
15 | val score: Int,
16 | val id: Int = 0
17 | )
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_backspace_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/Equation.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | /**
4 | * Equation model.
5 | *
6 | * @param componentA value A
7 | * @param componentB value B
8 | * @param operation mathematical representation of operation.
9 | * @param correctAnswer answer of whole equation.
10 | *
11 | * For example: (5+2) <=> (componentA = 5, componentB = 2, operation = PLUS, correctAnswer = 7)
12 | *
13 | */
14 |
15 | data class Equation(
16 | val componentA: Int,
17 | val componentB: Int,
18 | val operation: Operation,
19 | val correctAnswer: Int
20 | )
21 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/Settings.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity(tableName = "Settings")
8 | data class Settings(
9 | @PrimaryKey(autoGenerate = true)
10 | var id: Int = 0,
11 | @ColumnInfo(name = "maxNumberInBattleMode")
12 | var maxNumberInBattleMode: Int,
13 | @ColumnInfo(name = "language")
14 | var language: String,
15 | @ColumnInfo(name = "lastNickname1")
16 | var lastNickname1: String,
17 | @ColumnInfo(name = "lastNickname2")
18 | var lastNickname2: String
19 | )
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/Equation.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Equation model.
7 | *
8 | * @param componentA value A
9 | * @param componentB value B
10 | * @param operation mathematical representation of operation.
11 | * @param correctAnswer answer of whole equation.
12 | *
13 | * For example: (5+2) <=> (componentA = 5, componentB = 2, operation = PLUS, correctAnswer = 7)
14 | */
15 | @Serializable
16 | data class Equation(
17 | val componentA: Int,
18 | val componentB: Int,
19 | val operation: Operation,
20 | val correctAnswer: Int
21 | )
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/scoreboard/ScoreboardViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.scoreboard
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import com.octbit.rutmath.R
5 | import com.octbit.rutmath.data.model.Score
6 | import com.octbit.rutmath.databinding.ScoreRowBinding
7 |
8 | class ScoreboardViewHolder(
9 | private val binding: ScoreRowBinding
10 | ) : RecyclerView.ViewHolder(binding.root) {
11 |
12 | fun bind(position: Int, score: Score) = with(binding) {
13 | nick.text = root.context.getString(R.string.scoreboard_format, position, score.nick)
14 | binding.score.text = score.score.toString()
15 | }
16 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_button_yes.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_gamepad_solid.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/bg_in_button_no.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/Operation.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Types of operations that can exists in exercises.
7 | */
8 | @Serializable
9 | enum class Operation {
10 | PLUS,
11 | MINUS,
12 | PLUS_MINUS,
13 | MULTIPLY,
14 | DIVIDE,
15 | MULTIPLY_DIVIDE,
16 | DIVISIBILITY,
17 | UNITS_TIME,
18 | UNITS_LENGTH,
19 | UNITS_WEIGHT,
20 | UNITS_SURFACE,
21 | UNITS_ALL,
22 | // Adding negative plus and negative minus
23 | NEGATIVE_PLUS,
24 | NEGATIVE_MINUS,
25 | NEGATIVE_PLUS_MINUS,
26 | NEGATIVE_MUL,
27 | NEGATIVE_DIV,
28 | NEGATIVE_MUL_DIV
29 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/dao/SettingsDao.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.dao
2 |
3 | import androidx.room.*
4 | import com.octbit.rutmath.data.model.Settings
5 | import io.reactivex.Completable
6 | import io.reactivex.Single
7 |
8 | @Dao
9 | interface SettingsDao {
10 | @Query("SELECT * FROM Settings LIMIT 1")
11 | fun getAll(): Single>
12 |
13 | @Query("SELECT * FROM Settings WHERE id LIKE :id")
14 | fun findById(id: String): Single
15 |
16 | @Insert
17 | fun insertAll(exerciseTypes: List): Completable
18 |
19 | @Delete
20 | fun delete(exerciseType: Settings): Completable
21 |
22 | @Update
23 | fun update(exerciseType: Settings): Completable
24 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/Settings.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Settings model for application configuration.
7 | *
8 | * @param maxNumberInBattleMode maximum number that can appear in battle mode equations
9 | * @param lastNickname1 last used nickname for player 1
10 | * @param lastNickname2 last used nickname for player 2
11 | * @param language application language code (e.g., "en", "pl", "fr", "pt")
12 | */
13 | @Serializable
14 | data class Settings(
15 | val maxNumberInBattleMode: Int = 100,
16 | val lastNickname1: String = "Player 1",
17 | val lastNickname2: String = "Player 2",
18 | val language: String = "en"
19 | )
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/dao/ScoreDao.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.dao
2 |
3 | import androidx.room.*
4 | import com.octbit.rutmath.data.model.Score
5 | import io.reactivex.Completable
6 | import io.reactivex.Single
7 |
8 | @Dao
9 | interface ScoreDao {
10 | @Query("SELECT * FROM Score")
11 | fun getAll(): Single>
12 |
13 | @Query("SELECT * FROM Score WHERE id LIKE :id")
14 | fun findById(id: String): Single
15 |
16 | @Insert
17 | fun insertAll(scores: List): Completable
18 |
19 | @Insert
20 | fun insert(score: Score): Completable
21 |
22 | @Delete
23 | fun delete(score: Score): Completable
24 |
25 | @Update
26 | fun update(score: Score): Completable
27 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | RUTMath is an interactive educational app that helps school-aged children learn math. The application offers many different levels of difficulty to adjust to the user's skill level, and provides exercises and games that help with learning basic math operations such as addition, subtraction, multiplication, and division. Additionally, the application allows to learn how to convert units, such as converting meters to centimeters, kilograms to grams, etc. There is also the possibility of learning multiplication tables and divisibility of numbers, which are very important for further mathematical education. Thus, the application is an excellent tool for teachers and parents who want to help children learn math in a fun and effective way.
--------------------------------------------------------------------------------
/fastlane/metadata/android/pl-PL/full_description.txt:
--------------------------------------------------------------------------------
1 | RUTMath to interaktywna aplikacja edukacyjna, która pomaga dzieciom w wieku szkolnym w nauce matematyki. Oferuje ona wiele poziomów trudności, aby dostosować się do poziomu umiejętności użytkownika, a także zapewnia ćwiczenia i gry, które pomagają w nauce podstawowych działań matematycznych, takich jak dodawanie, odejmowanie, mnożenie i dzielenie. Ponadto, w aplikacji można nauczyć się zamieniać jednostki, czyli przeliczać metry na centymetry, kilogramy na gramy itp. Istnieje również możliwość nauki tabliczki mnożenia oraz podzielności liczb, które są bardzo ważne dla dalszej edukacji matematycznej. Dzięki temu aplikacja jest doskonałym narzędziem dla nauczycieli i rodziców, którzy chcą pomóc dzieciom w nauce matematyki w sposób przyjemny i efektywny.
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/choosePlayer/PlayerViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.choosePlayer
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import com.octbit.rutmath.R
5 | import com.octbit.rutmath.data.model.Player
6 | import com.octbit.rutmath.databinding.PlayerRowBinding
7 |
8 | class PlayerViewHolder(
9 | private val binding: PlayerRowBinding,
10 | private val onItemClickedListener: (Player) -> Unit
11 | ) : RecyclerView.ViewHolder(binding.root) {
12 |
13 | fun bind(position: Int, player: Player) = with(binding){
14 | root.setOnClickListener {
15 | onItemClickedListener.invoke(player)
16 | }
17 | nick.text = root.context.getString(R.string.scoreboard_format, position, player.nick)
18 | }
19 | }
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/com/octbit/rutmath/shared/di/IosSharedModule.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.di
2 |
3 | import com.octbit.rutmath.shared.data.DatabaseRepository
4 | import com.octbit.rutmath.shared.data.IosDatabaseRepository
5 | import com.octbit.rutmath.shared.localization.IosStringProvider
6 | import com.octbit.rutmath.shared.localization.StringProvider
7 | import org.koin.dsl.module
8 |
9 | /**
10 | * iOS-specific shared module containing iOS implementations.
11 | */
12 | val iosSharedModule = module {
13 |
14 | // Database Repository - iOS implementation using UserDefaults
15 | single { IosDatabaseRepository() }
16 |
17 | // String Provider - iOS implementation using NSLocalizedString
18 | single { IosStringProvider() }
19 |
20 | }
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "idiom" : "universal",
16 | "platform" : "ios",
17 | "size" : "1024x1024"
18 | },
19 | {
20 | "appearances" : [
21 | {
22 | "appearance" : "luminosity",
23 | "value" : "tinted"
24 | }
25 | ],
26 | "idiom" : "universal",
27 | "platform" : "ios",
28 | "size" : "1024x1024"
29 | }
30 | ],
31 | "info" : {
32 | "author" : "xcode",
33 | "version" : 1
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/androidApp/src/androidTest/java/com/octbit/rutmath/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath
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.octbit.rutmath", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/di/SharedModule.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.di
2 |
3 | import com.octbit.rutmath.shared.game.EquationGenerator
4 | import com.octbit.rutmath.shared.game.MathEquationGenerator
5 | import com.octbit.rutmath.shared.usecase.GameUseCase
6 | import com.octbit.rutmath.shared.usecase.UnitsGameUseCase
7 | import com.octbit.rutmath.shared.usecase.DataUseCase
8 | import org.koin.dsl.module
9 |
10 | /**
11 | * Shared Koin module containing platform-independent dependencies.
12 | */
13 | val sharedModule = module {
14 |
15 | // Equation Generation
16 | single { MathEquationGenerator() }
17 |
18 | // Use Cases
19 | single { GameUseCase(get()) }
20 | single { UnitsGameUseCase(get()) }
21 | single { DataUseCase(get()) }
22 |
23 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/player_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/pt-BR/full_description.txt:
--------------------------------------------------------------------------------
1 | RUTMath é um aplicativo educacional interativo que auxilia crianças em idade escolar a aprender matemática. O aplicativo oferece vários níveis diferentes de dificuldade para se adequar ao nível de habilidade do usuário e disponibiliza exercícios e jogos que ajudam no aprendizado de operações matemáticas básicas, como adição, subtração, multiplicação e divisão. Além disso, o aplicativo permite aprender como converter unidades, como transformar metros em centímetros, quilogramas em gramas, etc. Há também a possibilidade de aprender as tabuadas de multiplicação e a divisibilidade dos números, que são muito importantes para a educação matemática posterior. Assim, o aplicativo é uma excelente ferramenta para professores e pais que desejam ajudar as crianças a aprender matemática de forma divertida e eficaz.
2 |
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/com/octbit/rutmath/shared/di/AndroidSharedModule.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.di
2 |
3 | import com.octbit.rutmath.shared.data.AndroidDatabaseRepository
4 | import com.octbit.rutmath.shared.data.DatabaseRepository
5 | import com.octbit.rutmath.shared.localization.AndroidStringProvider
6 | import com.octbit.rutmath.shared.localization.StringProvider
7 | import org.koin.dsl.module
8 |
9 | /**
10 | * Android-specific shared module containing Android implementations.
11 | */
12 | val androidSharedModule = module {
13 |
14 | // Database Repository - Android implementation using Room
15 | single { AndroidDatabaseRepository(get()) }
16 |
17 | // String Provider - Android implementation using resources
18 | single { AndroidStringProvider(get()) }
19 |
20 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #CBCBCB
4 | #4F585A
5 |
6 | #F8A95D
7 | #e79b54
8 | #d59559
9 | #cc8d52
10 | #F69A3D
11 | #FC943C
12 | #e4d2c1
13 | #98A8CEE8
14 |
15 | #66000000
16 | #ffffff
17 | #E83030
18 | #22A322
19 | #4D788183
20 |
21 |
--------------------------------------------------------------------------------
/.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 | .idea/deploymentTargetDropDown.xml
16 | .idea/misc.xml
17 | .idea/runConfigurations.xml
18 |
19 | # Kotlin Multiplatform
20 | **/build/
21 | kotlin-js-store/
22 | node_modules/
23 |
24 | # Android
25 | *.apk
26 | *.ap_
27 | *.dex
28 | *.class
29 | local.properties
30 | *.log
31 | release/
32 |
33 | # iOS
34 | *.xcuserstate
35 | *.xcworkspace/xcuserdata/
36 | *.xcodeproj/xcuserdata/
37 | *.xcodeproj/project.xcworkspace/xcuserdata/
38 | DerivedData/
39 | build/
40 | *.ipa
41 |
42 | # Fastlane
43 | fastlane/report.xml
44 | fastlane/Preview.html
45 | fastlane/screenshots
46 | fastlane/test_output
47 |
48 | # Emacs aux
49 | *~
50 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/EquationUnits.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | /**
4 | * EquationUnits model.
5 | *
6 | * @param componentA value to convert
7 | * @param componentAUnitId ID of the unit of the componentA value
8 | * @param operation mathematical representation of units exchange operation.
9 | * @param correctAnswer result of exchange.
10 | * @param answerUnitId ID of the unit of the correctAnswer value
11 | *
12 | * For example:
13 | * (5 meters = 50 decimeters)
14 | * <=>
15 | * (componentA = 5,
16 | * componentAUnitId = 1 (m),
17 | * correctAnswer = 50,
18 | * answerUnitId = 2 (dm),
19 | * operation = Operation.UnitsLength)
20 | */
21 |
22 | data class EquationUnits(
23 | val componentA: Int,
24 | val componentAUnitId: Int,
25 | val operation: Operation,
26 | val correctAnswer: Int,
27 | val answerUnitId: Int
28 | )
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/dao/UserDao.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.dao
2 |
3 | import androidx.room.*
4 | import com.octbit.rutmath.data.model.Player
5 | import com.octbit.rutmath.data.model.PlayerWithExercises
6 | import io.reactivex.Completable
7 | import io.reactivex.Single
8 |
9 | @Dao
10 | interface UserDao {
11 | @Query("SELECT * FROM Player")
12 | fun getAll(): Single>
13 |
14 | @Query("SELECT * FROM Player WHERE nick LIKE :nick")
15 | fun findByNick(nick: String): Single
16 |
17 | @Insert
18 | fun insert(player: Player): Completable
19 |
20 | @Transaction
21 | @Query("SELECT * FROM Player WHERE nick LIKE :nick")
22 | fun getPlayerWithScores(nick: String): Single>
23 |
24 | @Delete
25 | fun delete(player: Player): Completable
26 |
27 | @Update
28 | fun update(player: Player): Completable
29 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_dumbbell_solid.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/EquationUnits.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * EquationUnits model.
7 | *
8 | * @param componentA value to convert
9 | * @param componentAUnitId ID of the unit of the componentA value
10 | * @param operation mathematical representation of units exchange operation.
11 | * @param correctAnswer result of exchange.
12 | * @param answerUnitId ID of the unit of the correctAnswer value
13 | *
14 | * For example:
15 | * (5 meters = 50 decimeters)
16 | * <=>
17 | * (componentA = 5,
18 | * componentAUnitId = 1 (m),
19 | * correctAnswer = 50,
20 | * answerUnitId = 2 (dm),
21 | * operation = Operation.UnitsLength)
22 | */
23 | @Serializable
24 | data class EquationUnits(
25 | val componentA: Int,
26 | val componentAUnitId: Int,
27 | val operation: Operation,
28 | val correctAnswer: Int,
29 | val answerUnitId: Int
30 | )
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/util/base/DisposableViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.util.base
2 |
3 | import androidx.lifecycle.ViewModel
4 | import io.reactivex.disposables.CompositeDisposable
5 | import io.reactivex.disposables.Disposable
6 |
7 | /**
8 | * ViewModel that have auto disposable mechanism.
9 | * Every disposable that should be disposed in end of ViewModel cycle of life should
10 | * be added in manageDisposable block of code.
11 | *
12 | * ViewModel with autoDisposable mechanism for all Disposable objects that will be
13 | * created in the code block using manageDisposable()
14 | */
15 | open class DisposableViewModel : ViewModel() {
16 |
17 | private val compositeDisposable = CompositeDisposable()
18 |
19 | fun manageDisposable(factory: () -> Disposable) {
20 | compositeDisposable.add(factory.invoke())
21 | }
22 |
23 | override fun onCleared() {
24 | compositeDisposable.dispose()
25 | super.onCleared()
26 | }
27 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_trophy_solid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_settings_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/view/UnitsHelpDialog.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.view
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.Window
8 | import com.octbit.rutmath.databinding.UnitsHelpDialogBinding
9 |
10 |
11 | /**
12 | * Dialog after clicking help in UnitsGame
13 | *
14 | */
15 | class UnitsHelpDialog(context: Context, private val text: String) : Dialog(context) {
16 |
17 | init {
18 | setCancelable(false)
19 | }
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | val binding = UnitsHelpDialogBinding.inflate(LayoutInflater.from(context))
24 | requestWindowFeature(Window.FEATURE_NO_TITLE)
25 | setContentView(binding.root)
26 | binding.helpText.text = text
27 | binding.okButton.setOnClickListener {
28 | dismiss()
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/metadata/com.octbit.rutmath.yml:
--------------------------------------------------------------------------------
1 | Categories:
2 | - Games
3 | - Science & Education
4 | License: GPL-3.0-or-later
5 | AuthorName: RUTTeam
6 | AuthorEmail: marbor@prz.edu.pl
7 | WebSite: https://github.com/przemarbor/RUTMath
8 | SourceCode: https://github.com/przemarbor/RUTMath
9 | IssueTracker: https://github.com/przemarbor/RUTMath/issues
10 | Changelog: https://github.com/przemarbor/RUTMath/releases
11 |
12 | AutoName: RUTMath
13 | Name: RUTMath
14 |
15 | RepoType: git
16 | Repo: https://github.com/przemarbor/RUTMath.git
17 |
18 | Builds:
19 | - versionName: 0.2.5
20 | versionCode: 10
21 | commit: v0.2.5
22 | subdir: androidApp
23 | gradle:
24 | - release
25 | prebuild: echo 'org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8' >> ../gradle.properties
26 |
27 | MaintainerNotes: |
28 | This is a Kotlin Multiplatform Mobile project.
29 | The Android app is built from the androidApp subdirectory.
30 |
31 | AutoUpdateMode: Version
32 | UpdateCheckMode: Tags
33 | CurrentVersion: 0.2.5
34 | CurrentVersionCode: 10
35 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/progress_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 | -
23 |
24 |
25 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/iosApp/iosApp/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import Shared
3 |
4 | struct ContentView: View {
5 | @State private var showContent = false
6 | var body: some View {
7 | VStack {
8 | Button("Click me!") {
9 | withAnimation {
10 | showContent = !showContent
11 | }
12 | }
13 |
14 | if showContent {
15 | VStack(spacing: 16) {
16 | Image(systemName: "swift")
17 | .font(.system(size: 200))
18 | .foregroundColor(.accentColor)
19 | Text("SwiftUI: \(Greeting().greet())")
20 | }
21 | .transition(.move(edge: .top).combined(with: .opacity))
22 | }
23 | }
24 | .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
25 | .padding()
26 | }
27 | }
28 |
29 | struct ContentView_Previews: PreviewProvider {
30 | static var previews: some View {
31 | ContentView()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/scoreboard/ScoreboardAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.scoreboard
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.octbit.rutmath.data.model.Score
8 | import com.octbit.rutmath.databinding.ScoreRowBinding
9 |
10 | class ScoreboardAdapter(private val scoresList: List) :
11 | RecyclerView.Adapter() {
12 |
13 | @SuppressLint("InflateParams")
14 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScoreboardViewHolder {
15 | val binding = ScoreRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
16 | return ScoreboardViewHolder(binding)
17 | }
18 |
19 | override fun getItemCount(): Int = scoresList.size
20 |
21 | override fun onBindViewHolder(holder: ScoreboardViewHolder, position: Int) {
22 | holder.bind(position + 1, scoresList[position])
23 | }
24 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/addSubList/AddSubListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.addSubList
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import com.octbit.rutmath.data.model.ExerciseType
8 | import com.octbit.rutmath.databinding.NormalExerciseItemBinding
9 |
10 | /**
11 | * Adapter that contains exercise list.
12 | *
13 | */
14 | class AddSubListAdapter(
15 | private val exercises: ArrayList,
16 | private val clickCallback: (exerciseType: ExerciseType) -> Unit,
17 | ) : RecyclerView.Adapter() {
18 |
19 | @SuppressLint("InflateParams")
20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddSubViewHolder {
21 | val binding = NormalExerciseItemBinding.inflate(LayoutInflater.from(parent.context))
22 | return AddSubViewHolder(binding, clickCallback)
23 | }
24 | override fun getItemCount(): Int = exercises.size
25 |
26 | override fun onBindViewHolder(holder: AddSubViewHolder, position: Int) {
27 | holder.bind(exercises[position])
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/mulDivList/MulDivListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.mulDivList
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import com.octbit.rutmath.data.model.ExerciseType
8 | import com.octbit.rutmath.databinding.NormalExerciseItemBinding
9 |
10 | /**
11 | * Adapter that contains exercise list.
12 | *
13 | */
14 | class MulDivListAdapter(
15 | private val exercises: ArrayList,
16 | private val clickCallback: (exerciseType: ExerciseType) -> Unit
17 | ) : RecyclerView.Adapter() {
18 |
19 | @SuppressLint("InflateParams")
20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MulDivViewHolder {
21 | val binding = NormalExerciseItemBinding.inflate(LayoutInflater.from(parent.context))
22 | return MulDivViewHolder(binding, clickCallback)
23 | }
24 |
25 | override fun getItemCount(): Int = exercises.size
26 |
27 | override fun onBindViewHolder(holder: MulDivViewHolder, position: Int) {
28 | holder.bind(exercises[position])
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/unitsList/UnitsListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.unitsList
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.octbit.rutmath.data.model.ExerciseType
8 | import com.octbit.rutmath.databinding.UnitsExerciseItemBinding
9 |
10 | /**
11 | * Adapter that contains units exercise list.
12 | *
13 | */
14 | class UnitsListAdapter(
15 | private val exercises: ArrayList,
16 | private val clickCallback: (exerciseType: ExerciseType) -> Unit
17 | ) : RecyclerView.Adapter() {
18 |
19 | @SuppressLint("InflateParams")
20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UnitsViewHolder {
21 | val binding = UnitsExerciseItemBinding.inflate(LayoutInflater.from(parent.context))
22 | return UnitsViewHolder(binding, clickCallback)
23 | }
24 |
25 | override fun getItemCount(): Int = exercises.size
26 |
27 | override fun onBindViewHolder(holder: UnitsViewHolder, position: Int) {
28 | holder.bind(exercises[position])
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/view/NormalRateDialog.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.view
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.Window
8 | import com.octbit.rutmath.databinding.NormalRateDialogBinding
9 | import com.octbit.rutmath.util.visible
10 |
11 | /**
12 | * Dialog with stars after finishing NormalGame
13 | *
14 | */
15 | class NormalRateDialog(context: Context, private val rate: Int) : Dialog(context) {
16 |
17 | init {
18 | setCancelable(false)
19 | }
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | val binding = NormalRateDialogBinding.inflate(LayoutInflater.from(context))
24 | requestWindowFeature(Window.FEATURE_NO_TITLE)
25 | setContentView(binding.root)
26 |
27 | val stars = arrayOf(binding.star1, binding.star2, binding.star3, binding.star4, binding.star5)
28 | for (index in 0 until rate) {
29 | stars[index].visible()
30 | }
31 | binding.okButton.setOnClickListener {
32 | dismiss()
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/score_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
31 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/divisibilityList/DivisibilityListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.divisibilityList
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.octbit.rutmath.data.model.ExerciseType
8 | import com.octbit.rutmath.databinding.DivisibilityExerciseItemBinding
9 |
10 | /**
11 | * Adapter that contains divisibility exercise list.
12 | *
13 | */
14 | class DivisibilityListAdapter(
15 | private val exercises: ArrayList,
16 | private val clickCallback: (exerciseType: ExerciseType) -> Unit
17 | ) : RecyclerView.Adapter() {
18 |
19 | @SuppressLint("InflateParams")
20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DivisibilityViewHolder {
21 | val binding = DivisibilityExerciseItemBinding.inflate(LayoutInflater.from(parent.context))
22 | return DivisibilityViewHolder(binding, clickCallback)
23 | }
24 |
25 | override fun getItemCount(): Int = exercises.size
26 |
27 | override fun onBindViewHolder(holder: DivisibilityViewHolder, position: Int) {
28 | holder.bind(exercises[position])
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_exercise_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
26 |
27 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/view/TableRateDialog.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.view
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.Window
8 | import com.octbit.rutmath.databinding.TableRateDialogBinding
9 | import com.octbit.rutmath.util.visible
10 |
11 | /**
12 | * Dialog with stars after finishing TableGame
13 | *
14 | */
15 | class TableRateDialog(context: Context, private val resultPercentage: Int) : Dialog(context) {
16 |
17 | init {
18 | setCancelable(false)
19 | }
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | val binding = TableRateDialogBinding.inflate(LayoutInflater.from(context))
24 |
25 | requestWindowFeature(Window.FEATURE_NO_TITLE)
26 | setContentView(binding.root)
27 |
28 | val stars = arrayOf(binding.star1, binding.star2, binding.star3, binding.star4, binding.star5)
29 | for (index in 0 until resultPercentage/20) {
30 | stars[index].visible()
31 | }
32 | binding.scoreText.text = " $resultPercentage%"
33 | binding.okButton.setOnClickListener {
34 | dismiss()
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/dao/ExerciseTypeDao.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.dao
2 |
3 | import androidx.room.*
4 | import com.octbit.rutmath.data.model.ExerciseType
5 | import com.octbit.rutmath.data.model.Operation
6 | import io.reactivex.Completable
7 | import io.reactivex.Single
8 |
9 | @Dao
10 | interface ExerciseTypeDao {
11 | @Query("SELECT * FROM ExerciseType WHERE userNick LIKE :nick")
12 | fun getAll(nick: String): Single>
13 |
14 | @Query("SELECT * FROM ExerciseType WHERE userNick LIKE :nick AND operation IN (:operations)")
15 | fun getAll(nick: String, operations: List): Single>
16 |
17 | @Query("SELECT * FROM ExerciseType WHERE id LIKE :id")
18 | fun findById(id: String): Single
19 |
20 | @Query("SELECT * FROM ExerciseType WHERE userNick LIKE :nick AND operation LIKE :operation AND difficulty > :prevDifficulty ORDER BY difficulty LIMIT 1")
21 | fun findExerciseType(nick: String, operation:Operation, prevDifficulty: Int): Single
22 |
23 | @Insert
24 | fun insertAll(exerciseTypes: List): Completable
25 |
26 | @Delete
27 | fun delete(exerciseType: ExerciseType): Completable
28 |
29 | @Update
30 | fun update(exerciseType: ExerciseType): Completable
31 | }
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/model/ExerciseType.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * ExerciseType is a data model representing a type of mathematical exercise.
7 | *
8 | * @param operation type of mathematical operation
9 | * @param difficulty modifies difficulty of the Exercise. For example: when difficulty equals to 10
10 | * and operation equals to Operation.PLUS then user will see only exercises with answer
11 | * that is equal or less than 10.
12 | * Every operation has specific difficulty range.
13 | * For example:
14 | * Operation.PLUS can use difficulty range: (5-200).
15 | * Operation.DIVISIBILITY can use difficulty range: (1-10).
16 | * Check specific GameViewModel for specific difficulty range.
17 | * @param rate number of stars reached in this type of exercises.
18 | * @param userNick nickname of the user who played this exercise type
19 | * @param isUnlocked whether exercise is unlocked and can be accessed by the user.
20 | * @param id unique identification number.
21 | */
22 | @Serializable
23 | data class ExerciseType(
24 | val operation: Operation,
25 | val difficulty: Int,
26 | val rate: Int = 0,
27 | val userNick: String,
28 | val isUnlocked: Boolean,
29 | val id: Int = 0
30 | )
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/choosePlayer/ChoosePlayerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.choosePlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.octbit.rutmath.data.model.Player
8 | import com.octbit.rutmath.databinding.PlayerRowBinding
9 |
10 | class ChoosePlayerAdapter(
11 | private val onItemClickedListener: (Player) -> Unit
12 | ) : RecyclerView.Adapter() {
13 |
14 | private val playersList = arrayListOf()
15 |
16 | @SuppressLint("InflateParams")
17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlayerViewHolder {
18 | val binding = PlayerRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
19 | return PlayerViewHolder(
20 | binding,
21 | onItemClickedListener
22 | )
23 | }
24 |
25 | override fun getItemCount(): Int = playersList.size
26 |
27 | override fun onBindViewHolder(holder: PlayerViewHolder, position: Int) {
28 | holder.bind(position + 1, playersList[position])
29 | }
30 |
31 | fun refreshAdapter(list: List) {
32 | playersList.apply {
33 | clear()
34 | addAll(list)
35 | }
36 | notifyDataSetChanged()
37 | }
38 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/Operation.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.TypeConverter
4 |
5 | /**
6 | * Types of operations that can exists in exercises.
7 | */
8 |
9 | enum class Operation {
10 | PLUS,
11 | MINUS,
12 | PLUS_MINUS,
13 | MULTIPLY,
14 | DIVIDE,
15 | MULTIPLY_DIVIDE,
16 | DIVISIBILITY,
17 | UNITS_TIME,
18 | UNITS_LENGTH,
19 | UNITS_WEIGHT,
20 | UNITS_SURFACE,
21 | UNITS_ALL,
22 | //adding negative plus and negative minus
23 | NEGATIVE_PLUS,
24 | NEGATIVE_MINUS,
25 | NEGATIVE_PLUS_MINUS,
26 | //new code added here
27 | // NEGATIVE_PLUS_MUL,
28 | // NEGATIVE_MINUS_MUL,
29 | // NEGATIVE_PLUS_DIV,
30 | // NEGATIVE_MINUS_DIV,
31 | // NEGATIVE_PLUS_MINUS_MUL,
32 | // NEGATIVE_PLUS_MINUS_DIV
33 | NEGATIVE_MUL,
34 | NEGATIVE_DIV,
35 | NEGATIVE_MUL_DIV
36 | }
37 |
38 | /**
39 | * Converter for database. It is not primitive type then it will be stored in database as String.
40 | * When database will retrieve it will be converted from String to Operation with stringToOperation method.
41 | */
42 | class OperationConverter {
43 | @TypeConverter
44 | fun stringToOperation(value: String): Operation {
45 | return Operation.valueOf(value)
46 | }
47 |
48 | @TypeConverter
49 | fun operationToString(value: Operation): String {
50 | return value.name
51 | }
52 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/util/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.util.base
2 |
3 | import android.app.AlertDialog
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.annotation.LayoutRes
9 | import androidx.fragment.app.Fragment
10 | import com.octbit.rutmath.R
11 |
12 | /**
13 | * BaseFragment for all fragments in app. It contains logic for easier inflating view from file.
14 | *
15 | * Base class for fragments with convenience for inflating view from file.
16 | */
17 | abstract class BaseFragment : Fragment() {
18 |
19 | @get:LayoutRes
20 | abstract val layout: Int
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater, container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View? {
26 | return inflater.inflate(layout, container, false)
27 | }
28 |
29 | protected fun showSimpleDialog(title: String? = null, message: String? = null) {
30 | val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
31 | title?.let {
32 | builder.setTitle(it)
33 | }
34 | message?.let {
35 | builder.setMessage(it)
36 | }
37 | builder.setPositiveButton(
38 | getString(R.string.ok)
39 | ) { dialog, _ ->
40 | dialog.dismiss()
41 | }
42 | builder.show()
43 | }
44 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/model/ExerciseType.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import java.io.Serializable
7 |
8 | /**
9 | * ExerciseType is a database model.
10 | * @param difficulty modifies difficulty of the Exercise. For example: when difficulty equals to 10
11 | * and operation equals to Operation.PLUS then user will see only exercises with answer
12 | * that is equal or less than 10.
13 | * Every operation has specific difficulty range.
14 | * For example:
15 | * Operation.PLUS can use difficulty range: (5-200).
16 | * Operation.DIVISIBILITY can use difficulty range: (1-10).
17 | * Check specific GameViewModel for specific difficulty range.
18 | * @param rate number of stars reached in this type of exercises.
19 | * @param isUnlocked whether exercise is unlocked and can be accessed by the user.
20 | * @param id unique identification number in database.
21 | */
22 |
23 | @Entity(tableName = "ExerciseType")
24 | data class ExerciseType(
25 | @ColumnInfo(name = "operation")
26 | var operation: Operation,
27 | @ColumnInfo(name = "difficulty")
28 | var difficulty: Int,
29 | @ColumnInfo(name = "rate")
30 | var rate: Int = 0,
31 | val userNick: String,
32 | var isUnlocked: Boolean,
33 | @PrimaryKey(autoGenerate = true)
34 | var id: Int = 0
35 | ) : Serializable
36 |
--------------------------------------------------------------------------------
/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=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError
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 | org.gradle.caching=true
15 | org.gradle.configureondemand=true
16 | # AndroidX package structure to make it clearer which packages are bundled with the
17 | # Android operating system, and which are packaged with your app's APK
18 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
19 | android.useAndroidX=true
20 | # Automatically convert third-party libraries to use AndroidX
21 | android.enableJetifier=true
22 | # Kotlin code style for this project: "official" or "obsolete":
23 | kotlin.code.style=official
24 |
25 | # Kotlin Multiplatform settings
26 | kotlin.mpp.androidGradlePluginCompatibility.nowarn=true
27 | kotlin.mpp.androidSourceSetLayoutV2AndroidStyleDirs.nowarn=true
28 | kotlin.native.ignoreDisabledTargets=true
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: "Check Android signing secrets"
2 |
3 | on:
4 | workflow_dispatch: # Run manually from GitHub UI
5 |
6 | jobs:
7 | check-secrets:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: "Check if secrets exist"
11 | run: |
12 | if [ -z "${{ secrets.KEYSTORE_FILE }}" ]; then
13 | echo "❌ Secret KEYSTORE_FILE is missing"
14 | exit 1
15 | fi
16 | if [ -z "${{ secrets.KEYSTORE_PASSWORD }}" ]; then
17 | echo "❌ Secret KEYSTORE_PASSWORD is missing"
18 | exit 1
19 | fi
20 | if [ -z "${{ secrets.KEY_ALIAS }}" ]; then
21 | echo "❌ Secret KEY_ALIAS is missing"
22 | exit 1
23 | fi
24 | if [ -z "${{ secrets.KEY_PASSWORD }}" ]; then
25 | echo "❌ Secret KEY_PASSWORD is missing"
26 | exit 1
27 | fi
28 | echo "✅ All secrets exist"
29 |
30 | - name: "Decode keystore"
31 | run: echo "${{ secrets.KEYSTORE_FILE }}" | base64 --decode > release.keystore
32 |
33 | - name: "Verify keystore"
34 | run: |
35 | set +e
36 | keytool -list -v \
37 | -keystore release.keystore \
38 | -storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
39 | -keypass "${{ secrets.KEY_PASSWORD }}" \
40 | -alias "${{ secrets.KEY_ALIAS }}"
41 | if [ $? -ne 0 ]; then
42 | echo "❌ Failed to open keystore with provided secrets"
43 | exit 1
44 | fi
45 | echo "✅ Keystore and credentials are valid"
46 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/data/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.data
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import androidx.room.TypeConverters
8 | import com.octbit.rutmath.data.dao.ExerciseTypeDao
9 | import com.octbit.rutmath.data.dao.ScoreDao
10 | import com.octbit.rutmath.data.dao.SettingsDao
11 | import com.octbit.rutmath.data.dao.UserDao
12 | import com.octbit.rutmath.data.model.*
13 |
14 | /**
15 | * Main abstraction for database. It contains whole Room database implementation.
16 | */
17 |
18 | @Database(entities = [ExerciseType::class, Settings::class, Score::class, Player::class], version = 4, exportSchema = false)
19 | @TypeConverters(OperationConverter::class)
20 | abstract class AppDatabase : RoomDatabase() {
21 |
22 | companion object {
23 | const val DATABASE_FILE = "rutmath.db"
24 |
25 | @Volatile
26 | private var instance: AppDatabase? = null
27 | private val lock = Any()
28 |
29 | operator fun invoke(context: Context) = instance ?: synchronized(lock) {
30 | instance ?: buildDatabase(context).also { instance = it }
31 | }
32 |
33 | private fun buildDatabase(context: Context) = Room.databaseBuilder(
34 | context,
35 | AppDatabase::class.java,
36 | DATABASE_FILE
37 | ).build()
38 | }
39 |
40 | abstract fun exerciseTypeDao(): ExerciseTypeDao
41 |
42 | abstract fun settingsDao(): SettingsDao
43 |
44 | abstract fun scoreDao(): ScoreDao
45 |
46 | abstract fun userDao(): UserDao
47 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.AppDatabase
7 | import io.reactivex.android.schedulers.AndroidSchedulers
8 | import io.reactivex.schedulers.Schedulers
9 | import org.koin.android.ext.android.inject
10 | import io.reactivex.disposables.CompositeDisposable
11 | import java.util.*
12 |
13 | var isRecreated = false
14 | class MainActivity : AppCompatActivity() {
15 | private val database: AppDatabase by inject()
16 | private val compositeDisposable: CompositeDisposable = CompositeDisposable()
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | if (!isRecreated){
21 | database.settingsDao().getAll()
22 | .observeOn(AndroidSchedulers.mainThread())
23 | .subscribeOn(Schedulers.io())
24 | .map { databaseSettings ->
25 | if (databaseSettings.isNotEmpty()) {
26 | setLocale(databaseSettings[0].language)
27 | isRecreated = true
28 | recreate()
29 | }
30 | }.subscribe()
31 | }
32 | setContentView(R.layout.main_activity)
33 | }
34 |
35 | /**
36 | * Sets the application language
37 | */
38 | private fun setLocale(language:String){
39 | val res = resources
40 | val dm = res.displayMetrics
41 | val conf = res.configuration
42 | conf.setLocale(Locale(language))
43 | resources.updateConfiguration(conf,dm)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/androidApp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
13 |
16 |
17 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_battle_game.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
26 |
27 |
38 |
39 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/localization/StringProvider.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.localization
2 |
3 | /**
4 | * Cross-platform string provider interface for localization.
5 | * Platform-specific implementations will provide localized strings.
6 | */
7 | interface StringProvider {
8 |
9 | // Basic strings
10 | fun ok(): String
11 | fun cancel(): String
12 | fun yes(): String
13 | fun no(): String
14 | fun error(): String
15 | fun save(): String
16 |
17 | // Game strings
18 | fun score(): String
19 | fun player1(): String
20 | fun player2(): String
21 | fun scoreboard(): String
22 |
23 | // Game modes
24 | fun additionSubtraction(): String
25 | fun multiplicationDivision(): String
26 | fun divisibility(): String
27 | fun unitConversion(): String
28 | fun multiplicationTable(): String
29 |
30 | // Difficulties
31 | fun difficultyEasy(): String
32 | fun difficultyMedium(): String
33 | fun difficultyHard(): String
34 | fun difficultyVeryHard(): String
35 |
36 | // Units
37 | fun unitsTime(): String
38 | fun unitsLength(): String
39 | fun unitsWeight(): String
40 | fun unitsSurface(): String
41 | fun unitsAll(): String
42 |
43 | // Divisibility
44 | fun divisibilityQuestionPart1(): String // "Is"
45 | fun divisibilityQuestionPart2(): String // "divisible by"
46 |
47 | // Game feedback
48 | fun gameEnded(): String
49 | fun nicknameEmpty(): String
50 | fun nicknameExists(): String
51 |
52 | // Formatted strings
53 | fun duelScore(player1Name: String, player1Score: Int, player2Name: String, player2Score: Int): String
54 | fun scoreboardFormat(position: Int, playerName: String): String
55 | fun battleBonus(bonus: Int): String
56 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/units_help_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
32 |
33 |
43 |
44 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/view/GridSpacingItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.view
2 |
3 | import android.graphics.Rect
4 | import android.view.View
5 | import androidx.recyclerview.widget.RecyclerView
6 |
7 | /**
8 | * Add spacing for GridLayoutManager of RecyclerView
9 | *
10 | * Decorator for RecyclerView allowing to add spacing between views with grid layout.
11 | *
12 | * @param spanCount - columns count
13 | * @param spacing - space between views in DPI
14 | * @param includeEdge - should add space between views and edge of recyclerView
15 | */
16 | class GridSpacingItemDecoration(
17 | private val spanCount: Int,
18 | private val spacing: Int,
19 | private val includeEdge: Boolean
20 | ) : RecyclerView.ItemDecoration() {
21 |
22 | override fun getItemOffsets(
23 | outRect: Rect,
24 | view: View,
25 | parent: RecyclerView,
26 | state: RecyclerView.State
27 | ) {
28 | val position = parent.getChildAdapterPosition(view) // item position
29 | val column = position % spanCount // item column
30 |
31 | if (includeEdge) {
32 | outRect.left =
33 | spacing - column * spacing / spanCount // spacing - column * ((1f / spanCount) * spacing)
34 | outRect.right =
35 | (column + 1) * spacing / spanCount // (column + 1) * ((1f / spanCount) * spacing)
36 |
37 | if (position < spanCount) { // top edge
38 | outRect.top = spacing
39 | }
40 | outRect.bottom = spacing // item bottom
41 | } else {
42 | outRect.left = column * spacing / spanCount // column * ((1f / spanCount) * spacing)
43 | outRect.right =
44 | spacing - (column + 1) * spacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing)
45 | if (position >= spanCount) {
46 | outRect.top = spacing // item top
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
22 |
23 |
31 |
32 |
39 |
40 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_units.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
9 |
14 |
17 |
18 |
23 |
28 |
29 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: "Build App"
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - "androidApp/src/**"
7 | - "shared/src/**"
8 | - "*.gradle*"
9 | - "gradle/**"
10 | types:
11 | - "opened"
12 | - "reopened"
13 | - "synchronize"
14 | push:
15 | branches:
16 | - "main"
17 | - "master"
18 | workflow_dispatch: # Allow manual trigger from GitHub UI
19 |
20 | jobs:
21 | build:
22 | name: "Build"
23 | runs-on: ubuntu-latest
24 | permissions:
25 | contents: write
26 | pull-requests: write
27 |
28 | steps:
29 | - name: "Checkout code"
30 | uses: actions/checkout@v4
31 |
32 | - name: "Setup Java"
33 | uses: actions/setup-java@v4
34 | with:
35 | distribution: temurin
36 | java-version: 17
37 | cache: gradle
38 |
39 | - name: "Grant execute permission for gradlew"
40 | run: chmod +x gradlew
41 |
42 | - name: "Decode Keystore"
43 | run: echo "${{ secrets.SIGNING_KEYSTORE }}" | base64 --decode > androidApp/release.keystore
44 |
45 | - name: "Set up signing env"
46 | run: |
47 | echo "SIGNING_KEY_ALIAS=${{ secrets.SIGNING_KEY_ALIAS }}" >> $GITHUB_ENV
48 | echo "SIGNING_KEYSTORE_PASSWORD=${{ secrets.SIGNING_KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
49 | echo "SIGNING_KEY_PASSWORD=${{ secrets.SIGNING_KEY_PASSWORD }}" >> $GITHUB_ENV
50 |
51 | - name: "Build APK"
52 | run: ./gradlew androidApp:assembleRelease --no-daemon
53 |
54 | - name: "Upload APK artifacts"
55 | uses: actions/upload-artifact@v4
56 | with:
57 | name: "app-release"
58 | path: androidApp/build/outputs/apk/release/androidApp-release.apk
59 |
60 | - name: "Build AAB"
61 | run: ./gradlew androidApp:bundleRelease --no-daemon
62 |
63 | - name: "Upload AAB artifacts"
64 | uses: actions/upload-artifact@v4
65 | with:
66 | name: "app-release-bundle"
67 | path: androidApp/build/outputs/bundle/release/androidApp-release.aab
68 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/data/DatabaseRepository.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.data
2 |
3 | import com.octbit.rutmath.shared.model.ExerciseType
4 | import com.octbit.rutmath.shared.model.Player
5 | import com.octbit.rutmath.shared.model.Score
6 | import com.octbit.rutmath.shared.model.Settings
7 |
8 | /**
9 | * Repository interface for database operations.
10 | * This abstraction allows different platforms to implement their own database solutions.
11 | */
12 | interface DatabaseRepository {
13 |
14 | /**
15 | * Settings related operations
16 | */
17 | suspend fun getSettings(): Settings?
18 | suspend fun updateSettings(settings: Settings)
19 | suspend fun insertDefaultSettings(): Settings
20 |
21 | /**
22 | * Exercise type related operations
23 | */
24 | suspend fun getExerciseTypes(): List
25 | suspend fun getExerciseType(id: Int): ExerciseType?
26 | suspend fun updateExerciseType(exerciseType: ExerciseType)
27 | suspend fun insertExerciseType(exerciseType: ExerciseType): Int
28 | suspend fun deleteExerciseType(id: Int)
29 |
30 | /**
31 | * Score related operations
32 | */
33 | suspend fun saveScore(score: Score): Int
34 | suspend fun saveScores(scores: List)
35 | suspend fun getTopScores(limit: Int = 10): List
36 | suspend fun getAllScores(): List
37 | suspend fun deleteScore(id: Int)
38 |
39 | /**
40 | * Player related operations
41 | */
42 | suspend fun getPlayers(): List
43 | suspend fun getPlayer(id: Int): Player?
44 | suspend fun insertPlayer(player: Player): Int
45 | suspend fun updatePlayer(player: Player)
46 | suspend fun deletePlayer(id: Int)
47 | }
48 |
49 | /**
50 | * Local data source interface for caching and offline storage.
51 | */
52 | interface LocalDataSource {
53 | suspend fun saveSettings(settings: Settings)
54 | suspend fun loadSettings(): Settings?
55 | suspend fun saveExerciseTypes(types: List)
56 | suspend fun loadExerciseTypes(): List
57 | suspend fun saveScores(scores: List)
58 | suspend fun loadScores(): List
59 | suspend fun clearCache()
60 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_scoreboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
32 |
33 |
38 |
39 |
51 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/divisibilityList/DivisibilityViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.divisibilityList
2 |
3 | import androidx.core.content.ContextCompat
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.model.ExerciseType
7 | import com.octbit.rutmath.databinding.DivisibilityExerciseItemBinding
8 |
9 |
10 | class DivisibilityViewHolder(
11 | private val binding: DivisibilityExerciseItemBinding,
12 | private val clickCallback: (exerciseType: ExerciseType) -> Unit) :
13 | RecyclerView.ViewHolder(binding.root) {
14 |
15 | private val difficultyList = listOf(
16 | binding.root.resources.getString(R.string.divisibility_difficulty_1),
17 | binding.root.resources.getString(R.string.divisibility_difficulty_2),
18 | binding.root.resources.getString(R.string.divisibility_difficulty_3),
19 | binding.root.resources.getString(R.string.divisibility_difficulty_4)
20 | )
21 |
22 | fun bind(exerciseType: ExerciseType) = with(binding){
23 | title.text = when (exerciseType.difficulty) {
24 | 1,2,3 -> difficultyList[0]
25 | 4,5,6 -> difficultyList[1]
26 | 9,8,7 -> difficultyList[2]
27 | 10 -> difficultyList[3]
28 | else -> null
29 | }.plus(" ").plus(((exerciseType.difficulty-1) % 3)+1)
30 | if (exerciseType.difficulty == 10)
31 | title.text = title.text.dropLast(2)
32 |
33 | /**
34 | * Set a listener on unlocked exercise tile and change its color
35 | */
36 | if (exerciseType.isUnlocked) {
37 | root.setOnClickListener {
38 | clickCallback.invoke(exerciseType)
39 | }
40 | root.background = ContextCompat.getDrawable(root.context, R.drawable.bg_in_tile_exercise)
41 | }
42 |
43 | val stars = arrayOf(star1, star2, star3, star4, star5)
44 |
45 | // Reset all stars to the default white icon
46 | stars.forEach { star ->
47 | star.setImageResource(R.drawable.ic_star)
48 | }
49 |
50 | for (i in 1..exerciseType.rate) {
51 | stars[i - 1].setImageResource(R.drawable.ic_star_yellow_24dp)
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: "Release"
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v*" # np. v0.2.3
7 | workflow_dispatch:
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | jobs:
21 | release:
22 | name: "Release"
23 | runs-on: ubuntu-latest
24 | permissions:
25 | contents: write
26 |
27 |
28 | steps:
29 | - name: "Checkout source code"
30 | uses: actions/checkout@v4
31 |
32 | - name: "Setup Java"
33 | uses: actions/setup-java@v4
34 | with:
35 | distribution: temurin
36 | java-version: 17
37 | cache: gradle
38 |
39 | - name: "Grant execute permission for gradlew"
40 | run: chmod +x gradlew
41 |
42 | - name: "Decode keystore"
43 | run: echo "${{ secrets.SIGNING_KEYSTORE }}" | base64 --decode > androidApp/release.keystore
44 |
45 | - name: "Set up signing env"
46 | run: |
47 | echo "SIGNING_KEY_ALIAS=${{ secrets.SIGNING_KEY_ALIAS }}" >> $GITHUB_ENV
48 | echo "SIGNING_KEYSTORE_PASSWORD=${{ secrets.SIGNING_KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
49 | echo "SIGNING_KEY_PASSWORD=${{ secrets.SIGNING_KEY_PASSWORD }}" >> $GITHUB_ENV
50 |
51 | - name: "Build Release APK"
52 | run: ./gradlew androidApp:assembleRelease --no-daemon
53 |
54 | - name: "Upload APK artifact"
55 | uses: actions/upload-artifact@v4
56 | with:
57 | name: app-release
58 | path: androidApp/build/outputs/apk/release/androidApp-release.apk
59 |
60 | - name: "Build Release AAB"
61 | run: ./gradlew androidApp:bundleRelease --no-daemon
62 |
63 | - name: "Upload AAB artifact"
64 | uses: actions/upload-artifact@v4
65 | with:
66 | name: app-release-bundle
67 | path: androidApp/build/outputs/bundle/release/androidApp-release.aab
68 |
69 | - name: "Create GitHub Release"
70 | uses: softprops/action-gh-release@v1
71 | with:
72 | files: |
73 | androidApp/build/outputs/apk/release/androidApp-release.apk
74 | androidApp/build/outputs/bundle/release/androidApp-release.aab
75 | draft: false
76 | prerelease: false
77 | generate_release_notes: true
78 | env:
79 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
80 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/normal_exercise_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
27 |
28 |
33 |
34 |
39 |
40 |
45 |
46 |
51 |
52 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/com/octbit/rutmath/shared/game/EquationGenerator.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.game
2 |
3 | import com.octbit.rutmath.shared.model.Equation
4 | import com.octbit.rutmath.shared.model.EquationUnits
5 | import com.octbit.rutmath.shared.model.ExerciseType
6 | import com.octbit.rutmath.shared.model.Operation
7 |
8 | /**
9 | * Interface for generating mathematical equations based on operation type and difficulty.
10 | */
11 | interface EquationGenerator {
12 | /**
13 | * Generates a single equation based on operation and difficulty.
14 | *
15 | * @param operation The type of mathematical operation
16 | * @param difficulty The difficulty level (affects number ranges)
17 | * @return Generated equation
18 | */
19 | fun generateEquation(operation: Operation, difficulty: Int): Equation
20 |
21 | /**
22 | * Generates a units equation for unit conversion exercises.
23 | *
24 | * @param operation The type of units operation
25 | * @param difficulty The difficulty level
26 | * @return Generated units equation
27 | */
28 | fun generateUnitsEquation(operation: Operation, difficulty: Int): EquationUnits
29 |
30 | /**
31 | * Generates multiple answer choices including the correct answer.
32 | *
33 | * @param correctAnswer The correct answer to the equation
34 | * @param count Number of answer choices to generate (default 4)
35 | * @return List of answer choices (including correct answer)
36 | */
37 | fun generateAnswers(correctAnswer: Int, count: Int = 4): List
38 |
39 | /**
40 | * Generates a list of equations for a complete exercise.
41 | *
42 | * @param exerciseType The exercise type configuration
43 | * @param exerciseCount Number of equations to generate
44 | * @return List of generated equations
45 | */
46 | fun generateEquations(exerciseType: ExerciseType, exerciseCount: Int): List
47 |
48 | /**
49 | * Generates a list of units equations for a complete exercise.
50 | *
51 | * @param exerciseType The exercise type configuration
52 | * @param exerciseCount Number of equations to generate
53 | * @return List of generated units equations
54 | */
55 | fun generateUnitsEquations(exerciseType: ExerciseType, exerciseCount: Int): List
56 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/ic_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
17 |
18 |
23 |
28 |
29 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/unitsList/UnitsViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.unitsList
2 |
3 | import androidx.core.content.ContextCompat
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.model.ExerciseType
7 | import com.octbit.rutmath.data.model.Operation
8 | import com.octbit.rutmath.databinding.UnitsExerciseItemBinding
9 |
10 | class UnitsViewHolder(
11 | private val binding: UnitsExerciseItemBinding,
12 | private val clickCallback: (exerciseType: ExerciseType) -> Unit
13 | ) :
14 | RecyclerView.ViewHolder(binding.root) {
15 |
16 | private val TIME = binding.root.resources.getString(R.string.units_time)
17 | private val LENGTH = binding.root.resources.getString(R.string.units_length)
18 | private val WEIGHT = binding.root.resources.getString(R.string.units_weight)
19 | private val SURFACE = binding.root.resources.getString(R.string.units_surface)
20 | private val ALL = binding.root.resources.getString(R.string.units_all)
21 |
22 | fun bind(exerciseType: ExerciseType) = with(binding){
23 | title.text = when (exerciseType.operation) {
24 | Operation.UNITS_TIME -> TIME
25 | Operation.UNITS_LENGTH -> LENGTH
26 | Operation.UNITS_WEIGHT -> WEIGHT
27 | Operation.UNITS_SURFACE -> SURFACE
28 | Operation.UNITS_ALL -> ALL
29 | else -> null
30 | }.plus(" ").plus(((exerciseType.difficulty-1) % 3)+1)
31 | if (exerciseType.difficulty == 10)
32 | title.text = title.text.dropLast(2)
33 |
34 | /**
35 | * Set a listener on unlocked exercise tile and change its color
36 | */
37 | if (exerciseType.isUnlocked) {
38 | root.setOnClickListener {
39 | clickCallback.invoke(exerciseType)
40 | }
41 | root.background = ContextCompat.getDrawable(root.context, R.drawable.bg_in_tile_exercise)
42 | }
43 |
44 | val stars = arrayOf(star1, star2, star3, star4, star5)
45 |
46 | // Reset all stars to the default white icon
47 | stars.forEach { star ->
48 | star.setImageResource(R.drawable.ic_star)
49 | }
50 |
51 | for (i in 1..exerciseType.rate) {
52 | stars[i - 1].setImageResource(R.drawable.ic_star_yellow_24dp)
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/divisibility_exercise_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
28 |
29 |
34 |
35 |
40 |
41 |
46 |
47 |
52 |
53 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/scoreboard/ScoreboardFragment.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.scoreboard
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.octbit.rutmath.R
9 | import com.octbit.rutmath.data.AppDatabase
10 | import com.octbit.rutmath.databinding.FragmentScoreboardBinding
11 | import com.octbit.rutmath.util.base.BaseFragment
12 | import com.octbit.rutmath.util.gone
13 | import com.octbit.rutmath.util.visible
14 | import io.reactivex.android.schedulers.AndroidSchedulers
15 | import io.reactivex.disposables.CompositeDisposable
16 | import io.reactivex.schedulers.Schedulers
17 | import org.koin.android.ext.android.inject
18 |
19 | class ScoreboardFragment : BaseFragment() {
20 |
21 | override val layout = R.layout.fragment_scoreboard
22 | private var _binding: FragmentScoreboardBinding? = null
23 | private val binding get() = _binding!!
24 | private val database: AppDatabase by inject()
25 |
26 | private val disposables = CompositeDisposable()
27 | override fun onCreateView(
28 | inflater: LayoutInflater,
29 | container: ViewGroup?,
30 | savedInstanceState: Bundle?
31 | ): View? {
32 | _binding = FragmentScoreboardBinding.inflate(inflater, container, false)
33 | return binding.root
34 | }
35 | override fun onViewCreated(view: View, savedInstanceState: Bundle?){
36 | super.onViewCreated(view, savedInstanceState)
37 | disposables.add(database.scoreDao().getAll()
38 | .observeOn(AndroidSchedulers.mainThread())
39 | .subscribeOn(Schedulers.io())
40 | .subscribe { scoreList ->
41 | val sortedList = scoreList.sortedBy { it.score }.reversed()
42 | binding.recyclerView.adapter = ScoreboardAdapter(sortedList)
43 | if (sortedList.isNotEmpty()) {
44 | binding.emptyListInstruction.gone()
45 | binding.scoreBoardInfo.visible()
46 | }
47 | })
48 | binding.recyclerView.apply {
49 | layoutManager = LinearLayoutManager(context)
50 | }
51 | }
52 |
53 | override fun onDestroy() {
54 | disposables.clear()
55 | super.onDestroy()
56 | _binding = null
57 | }
58 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/units_exercise_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
29 |
30 |
35 |
36 |
41 |
42 |
47 |
48 |
53 |
54 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.di
2 |
3 | import androidx.room.Room
4 | import com.octbit.rutmath.data.AppDatabase
5 | import com.octbit.rutmath.ui.fragment.addSubList.AddSubListViewModel
6 | import com.octbit.rutmath.ui.fragment.game.battle.BattleFragmentViewModel
7 | import com.octbit.rutmath.ui.fragment.choosePlayer.ChoosePlayerViewModel
8 | import com.octbit.rutmath.ui.fragment.divisibilityList.DivisibilityListViewModel
9 | import com.octbit.rutmath.ui.fragment.game.divisibility.DivisibilityGameViewModel
10 | import com.octbit.rutmath.ui.fragment.game.normal.NormalGameViewModel
11 | import com.octbit.rutmath.ui.fragment.game.table.TableGameViewModel
12 | import com.octbit.rutmath.ui.fragment.game.units.UnitsGameViewModel
13 | import com.octbit.rutmath.ui.fragment.mulDivList.MulDivListViewModel
14 | import com.octbit.rutmath.ui.fragment.unitsList.UnitsListViewModel
15 | import com.octbit.rutmath.ui.game.SharedNormalGameViewModel
16 | import com.octbit.rutmath.ui.game.SharedBattleViewModel
17 | import com.octbit.rutmath.ui.game.SharedUnitsGameViewModel
18 | import com.octbit.rutmath.ui.game.SharedTableGameViewModel
19 | import com.octbit.rutmath.ui.game.SharedDivisibilityGameViewModel
20 | import org.koin.android.ext.koin.androidContext
21 | import org.koin.androidx.viewmodel.dsl.viewModel
22 | import org.koin.dsl.module
23 |
24 | val appModule = module {
25 |
26 | single {
27 | Room.databaseBuilder(
28 | androidContext(),
29 | AppDatabase::class.java,
30 | AppDatabase.DATABASE_FILE
31 | ).build()
32 | }
33 |
34 | viewModel { AddSubListViewModel(get()) }
35 | viewModel { MulDivListViewModel(get()) }
36 | viewModel { DivisibilityListViewModel(get()) }
37 | viewModel { UnitsListViewModel(get()) }
38 | viewModel { NormalGameViewModel() }
39 | viewModel { DivisibilityGameViewModel() }
40 | viewModel { TableGameViewModel() }
41 | viewModel { UnitsGameViewModel() }
42 | viewModel { BattleFragmentViewModel(get()) }
43 | viewModel {
44 | ChoosePlayerViewModel(
45 | get()
46 | )
47 | }
48 |
49 | viewModel { SharedNormalGameViewModel(get(), get()) }
50 | viewModel { SharedBattleViewModel(get(), get()) }
51 | viewModel { SharedUnitsGameViewModel(get(), get()) }
52 | viewModel { SharedTableGameViewModel(get(), get()) }
53 | viewModel { SharedDivisibilityGameViewModel(get(), get()) }
54 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RUTMath
2 | Rzeszów University of Technology Math is an open source (GPL) application created in order to help preschool or early school children to learn mathematics.
3 |
4 | [
](https://f-droid.org/packages/com.octbit.rutmath/)
7 |
8 | Or get the latest APK from the [Releases Section](https://github.com/przemarbor/RUTMath/releases/latest).
9 |
10 | # Requirements
11 | To use this app you need mobile device using Android Version >= 5.1.
12 |
13 | # Language
14 | This app is available in the following languages:
15 | - English
16 | - Polish
17 | - French
18 | - Portuguese
19 | - Spanish
20 | - Greek
21 | - Dutch
22 | - Slovak
23 | - Italian
24 | - German
25 | - Hungarian
26 | - Czech
27 |
28 | # License
29 | This software is licensed under the terms of the GNU General Public License version 3 (GPLv3).
30 | Full text of the license is available online https://opensource.org/licenses/gpl-3.0.html
31 |
32 | # Acknowledgements
33 | Thank you for your contribution!
34 |
35 | Code development:
36 | - [@krolik7](https://www.github.com/krolik7) (original developer)
37 | - [Arkadiusz Połeć](https://github.com/Nydeyas) (developer)
38 | - [@WegWojciech](https://github.com/WegWojciech) (developer)
39 | - [@RadimDev](https://github.com/RadimDev) (current maintainer)
40 | - [@przemarbor](https://github.com/przemarbor) (good spirit/éminence grise)
41 |
42 |
43 | Translations:
44 | - [Benoît Harrault](https://github.com/benoitharrault) (French)
45 | - [Ramon Rodrigues](https://github.com/ramonrwx) (Portuguese)
46 |
47 | # Screenshots
48 |
49 |
50 |
51 |
52 | |
53 |
54 |
55 | |
56 |
57 |
58 | |
59 |
60 |
61 | |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/addSubList/AddSubViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.addSubList
2 |
3 | import androidx.core.content.ContextCompat
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.model.ExerciseType
7 | import com.octbit.rutmath.data.model.Operation
8 | import com.octbit.rutmath.databinding.NormalExerciseItemBinding
9 |
10 | class AddSubViewHolder(private val binding: NormalExerciseItemBinding, private val clickCallback: (exerciseType: ExerciseType) -> Unit)
11 | : RecyclerView.ViewHolder(binding.root) {
12 |
13 | companion object {
14 | const val PLUS_VALUE = "+"
15 | const val MINUS_VALUE = "-"
16 | const val PLUS_MINUS_VALUE = "±"
17 | // new code here for negative number
18 | const val NEGATIVE_PLUS_VALUE="+(-)"
19 | const val NEGATIVE_MINUS_VALUE="-(-)"
20 | const val NEGATIVE_PLUS_MINUS_VALUE="±(-)"
21 | }
22 |
23 | fun bind(exerciseType: ExerciseType) = with(binding) {
24 | title.text = when (exerciseType.operation) {
25 | Operation.PLUS -> PLUS_VALUE
26 | Operation.MINUS -> MINUS_VALUE
27 | Operation.PLUS_MINUS -> PLUS_MINUS_VALUE
28 | Operation.NEGATIVE_PLUS -> NEGATIVE_PLUS_VALUE
29 | Operation.NEGATIVE_MINUS -> NEGATIVE_MINUS_VALUE
30 | Operation.NEGATIVE_PLUS_MINUS -> NEGATIVE_PLUS_MINUS_VALUE
31 | else -> null
32 | }.plus(" ").plus(exerciseType.difficulty)
33 |
34 | // Set a listener on unlocked exercise tile and change its color
35 | if (exerciseType.isUnlocked) {
36 | root.setOnClickListener {
37 | clickCallback.invoke(exerciseType)
38 | }
39 | root.background = ContextCompat.getDrawable(root.context, R.drawable.bg_in_tile_exercise)
40 | } else {
41 | root.setOnClickListener(null)
42 | root.background = ContextCompat.getDrawable(root.context, R.drawable.bg_in_tile_exercise_disabled)
43 | }
44 |
45 | val stars = arrayOf(binding.star1, binding.star2, binding.star3, binding.star4, binding.star5)
46 | // Reset all stars to the default white icon
47 | stars.forEach { star ->
48 | star.setImageResource(R.drawable.ic_star) // Use your default star icon
49 | }
50 | for (i in 1..exerciseType.rate.coerceIn(0, 5)) {
51 | stars[i - 1].setImageResource(R.drawable.ic_star_yellow_24dp)
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/MenuFragment.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.navigation.fragment.findNavController
10 | import com.octbit.rutmath.R
11 | import com.octbit.rutmath.databinding.FragmentMenuBinding
12 | import com.octbit.rutmath.util.base.BaseFragment
13 |
14 | class MenuFragment : BaseFragment() {
15 | override val layout: Int = R.layout.fragment_menu
16 | private var _binding: FragmentMenuBinding? = null
17 | private val binding get() = _binding!!
18 |
19 | override fun onCreateView(
20 | inflater: LayoutInflater,
21 | container: ViewGroup?,
22 | savedInstanceState: Bundle?
23 | ): View {
24 | _binding = FragmentMenuBinding.inflate(inflater, container, false)
25 | return binding.root
26 | }
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 | initButtons()
31 | }
32 |
33 | private fun initButtons() = with(binding) {
34 | // University Logo in top left corner - redirects to PRz Website based on language selected
35 |
36 | przLogo.setOnClickListener {
37 | startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.prz_url))))
38 | }
39 |
40 | // Faculty Logo in top center - redirects to WEiI Website based on language selected
41 | weiiLogo.setOnClickListener {
42 | startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.weii_url))))
43 | }
44 |
45 | modesButton.setOnClickListener {
46 | findNavController().navigate(
47 | MenuFragmentDirections.actionMenuFragmentToChoosePlayerFragment()
48 | )
49 | }
50 | pvpButton.setOnClickListener {
51 | findNavController().navigate(
52 | MenuFragmentDirections.actionMenuFragmentToPlayersNamesFragment()
53 | )
54 | }
55 | settingsButton.setOnClickListener {
56 | findNavController().navigate(
57 | MenuFragmentDirections.actionMenuFragmentToSettingsFragment()
58 | )
59 | }
60 | leaderboardButton.setOnClickListener {
61 | findNavController().navigate(MenuFragmentDirections.actionMenuFragmentToScoreboardFragment())
62 | }
63 | }
64 |
65 | override fun onDestroy() {
66 | super.onDestroy()
67 | _binding = null
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/shared/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id('com.android.library')
3 | id('org.jetbrains.kotlin.multiplatform')
4 | id('org.jetbrains.kotlin.plugin.serialization')
5 | id('kotlin-parcelize')
6 | }
7 |
8 | kotlin {
9 | androidTarget {
10 | compilations.all {
11 | kotlinOptions {
12 | jvmTarget = "11"
13 | }
14 | }
15 | }
16 |
17 | // iOS targets with framework configuration
18 | iosX64()
19 | iosArm64()
20 | iosSimulatorArm64()
21 |
22 | // Configure iOS framework
23 | targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) {
24 | binaries.withType(org.jetbrains.kotlin.gradle.plugin.mpp.Framework) {
25 | baseName = "RutMathShared"
26 | export("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
27 | export("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1")
28 | export("io.insert-koin:koin-core:3.5.0")
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain {
34 | dependencies {
35 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
36 | implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0'
37 | implementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.4.1'
38 | implementation 'io.insert-koin:koin-core:3.5.0'
39 | }
40 | }
41 | commonTest {
42 | dependencies {
43 | implementation 'org.jetbrains.kotlin:kotlin-test:1.9.20'
44 | }
45 | }
46 | androidMain {
47 | dependencies {
48 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
49 | implementation 'io.insert-koin:koin-android:3.5.0'
50 | implementation 'androidx.room:room-runtime:2.6.1'
51 | implementation 'androidx.room:room-ktx:2.6.1'
52 | }
53 | }
54 | androidUnitTest {
55 | dependencies {
56 | implementation 'androidx.test.ext:junit:1.1.5'
57 | implementation 'androidx.test.espresso:espresso-core:3.5.1'
58 | }
59 | }
60 | iosMain {
61 | dependencies {
62 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
63 | }
64 | }
65 | iosTest {
66 | dependencies {
67 | implementation 'org.jetbrains.kotlin:kotlin-test:1.9.20'
68 | }
69 | }
70 | }
71 | }
72 |
73 | android {
74 | namespace 'com.octbit.rutmath.shared'
75 | compileSdk 34
76 |
77 | defaultConfig {
78 | minSdk 22
79 | targetSdk 34
80 | }
81 |
82 | compileOptions {
83 | sourceCompatibility JavaVersion.VERSION_11
84 | targetCompatibility JavaVersion.VERSION_11
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/normal_rate_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
28 |
29 |
36 |
37 |
44 |
45 |
52 |
53 |
60 |
61 |
62 |
71 |
72 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_table_game.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
27 |
28 |
40 |
41 |
47 |
48 |
56 |
57 |
58 |
59 |
69 |
70 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/choosePlayer/ChoosePlayerViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.choosePlayer
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.octbit.rutmath.data.AppDatabase
6 | import com.octbit.rutmath.data.model.Player
7 | import com.octbit.rutmath.util.base.DisposableViewModel
8 | import io.reactivex.Single
9 | import io.reactivex.android.schedulers.AndroidSchedulers
10 | import io.reactivex.schedulers.Schedulers
11 |
12 | class ChoosePlayerViewModel(
13 | private val database: AppDatabase
14 | ) : DisposableViewModel() {
15 |
16 | enum class PlayerCreationEvent {
17 | SUCCESS,
18 | NICKNAME_EXISTS,
19 | NICKNAME_EMPTY
20 | }
21 |
22 | private val playersList = arrayListOf()
23 |
24 | private val refreshPlayersListEvent = MutableLiveData()
25 |
26 | private val playerCreationEvent = MutableLiveData()
27 |
28 | fun getRefreshPlayersListEvent(): LiveData = refreshPlayersListEvent
29 |
30 | fun getPlayersList(): List = playersList
31 |
32 | fun playerCreationEvent(): LiveData = playerCreationEvent
33 |
34 | fun loadPlayersList() {
35 | manageDisposable {
36 | database
37 | .userDao()
38 | .getAll()
39 | .observeOn(AndroidSchedulers.mainThread())
40 | .subscribeOn(Schedulers.io())
41 | .subscribe { list ->
42 | playersList.apply {
43 | clear()
44 | addAll(list)
45 | }
46 | refreshPlayersListEvent.postValue(Unit)
47 | }
48 | }
49 | }
50 |
51 | fun createPlayer(nick: String) {
52 | manageDisposable {
53 | database.userDao()
54 | .getAll()
55 | .observeOn(AndroidSchedulers.mainThread())
56 | .subscribeOn(Schedulers.io())
57 | .map {
58 | it.firstOrNull { player -> player.nick == nick } != null
59 | }.flatMap { nickExists ->
60 | if (nick.trim().isEmpty()) {
61 | return@flatMap Single.just(PlayerCreationEvent.NICKNAME_EMPTY)
62 | }
63 | if (nickExists) {
64 | Single.just(PlayerCreationEvent.NICKNAME_EXISTS)
65 | } else {
66 | database
67 | .userDao()
68 | .insert(Player(nick))
69 | .observeOn(AndroidSchedulers.mainThread())
70 | .subscribeOn(Schedulers.io())
71 | .andThen(Single.just(PlayerCreationEvent.SUCCESS)
72 | )
73 | }
74 | }.subscribe { result ->
75 | playerCreationEvent.postValue(result)
76 | }
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_choose_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
30 |
31 |
40 |
41 |
55 |
56 |
66 |
--------------------------------------------------------------------------------
/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 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/com/octbit/rutmath/shared/localization/IosStringProvider.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.shared.localization
2 |
3 | import platform.Foundation.NSBundle
4 | import platform.Foundation.NSString
5 | import platform.Foundation.NSLocalizedString
6 |
7 | /**
8 | * iOS implementation of StringProvider using NSLocalizedString.
9 | * For now uses hardcoded English strings, but can be extended to use iOS localization.
10 | */
11 | class IosStringProvider : StringProvider {
12 |
13 | override fun ok(): String = NSLocalizedString("OK", "")
14 | override fun cancel(): String = NSLocalizedString("Cancel", "")
15 | override fun yes(): String = NSLocalizedString("Yes", "")
16 | override fun no(): String = NSLocalizedString("No", "")
17 | override fun error(): String = NSLocalizedString("Error", "")
18 | override fun save(): String = NSLocalizedString("Save", "")
19 |
20 | override fun score(): String = NSLocalizedString("Score:", "")
21 | override fun player1(): String = NSLocalizedString("Player1", "")
22 | override fun player2(): String = NSLocalizedString("Player2", "")
23 | override fun scoreboard(): String = NSLocalizedString("Scoreboard:", "")
24 |
25 | override fun additionSubtraction(): String = NSLocalizedString("Addition and Subtraction", "")
26 | override fun multiplicationDivision(): String = NSLocalizedString("Multiplication and Division", "")
27 | override fun divisibility(): String = NSLocalizedString("Divisibility", "")
28 | override fun unitConversion(): String = NSLocalizedString("Unit conversion", "")
29 | override fun multiplicationTable(): String = NSLocalizedString("Multiplication table", "")
30 |
31 | override fun difficultyEasy(): String = NSLocalizedString("Easy", "")
32 | override fun difficultyMedium(): String = NSLocalizedString("Medium", "")
33 | override fun difficultyHard(): String = NSLocalizedString("Hard", "")
34 | override fun difficultyVeryHard(): String = NSLocalizedString("Very Hard", "")
35 |
36 | override fun unitsTime(): String = NSLocalizedString("Time", "")
37 | override fun unitsLength(): String = NSLocalizedString("Length", "")
38 | override fun unitsWeight(): String = NSLocalizedString("Weight", "")
39 | override fun unitsSurface(): String = NSLocalizedString("Surface", "")
40 | override fun unitsAll(): String = NSLocalizedString("All", "")
41 |
42 | override fun divisibilityQuestionPart1(): String = NSLocalizedString("Is", "")
43 | override fun divisibilityQuestionPart2(): String = NSLocalizedString("divisible by", "")
44 |
45 | override fun gameEnded(): String = NSLocalizedString("Game ended", "")
46 | override fun nicknameEmpty(): String = NSLocalizedString("Nickname can not be empty!", "")
47 | override fun nicknameExists(): String = NSLocalizedString("Nickname exists!", "")
48 |
49 | override fun duelScore(player1Name: String, player1Score: Int, player2Name: String, player2Score: Int): String {
50 | return "$player1Name score: $player1Score\n$player2Name score: $player2Score"
51 | }
52 |
53 | override fun scoreboardFormat(position: Int, playerName: String): String {
54 | return "$position. $playerName"
55 | }
56 |
57 | override fun battleBonus(bonus: Int): String {
58 | return "Sequential bonus +$bonus"
59 | }
60 | }
--------------------------------------------------------------------------------
/androidApp/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: "androidx.navigation.safeargs.kotlin"
4 | apply plugin: "kotlin-kapt"
5 |
6 | android {
7 | namespace "com.octbit.rutmath"
8 |
9 | signingConfigs {
10 | release {
11 | storeFile file("release.keystore") // Keystore dekodowany w workflow
12 | storePassword System.getenv("SIGNING_KEYSTORE_PASSWORD")
13 | keyAlias System.getenv("SIGNING_KEY_ALIAS")
14 | keyPassword System.getenv("SIGNING_KEY_PASSWORD")
15 | }
16 | }
17 |
18 | defaultConfig {
19 | compileSdk 34
20 | applicationId "com.octbit.rutmath"
21 | minSdkVersion 22
22 | targetSdkVersion 34
23 | versionCode 10
24 | versionName "0.2.5"
25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26 | }
27 |
28 | buildTypes {
29 | release {
30 | signingConfig signingConfigs.release
31 | minifyEnabled false
32 | shrinkResources false
33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34 | }
35 | debug {
36 | debuggable true
37 | signingConfig signingConfigs.debug
38 | }
39 | }
40 |
41 | compileOptions {
42 | sourceCompatibility JavaVersion.VERSION_11
43 | targetCompatibility JavaVersion.VERSION_11
44 | }
45 |
46 | kotlinOptions {
47 | jvmTarget = "11"
48 | }
49 |
50 | buildFeatures {
51 | viewBinding = true
52 | }
53 |
54 | dependenciesInfo {
55 | includeInApk = false
56 | includeInBundle = false
57 | }
58 | }
59 |
60 | dependencies {
61 | def nav_version = "2.5.3"
62 |
63 | implementation project(':shared')
64 |
65 | implementation fileTree(dir: 'libs', include: ['*.jar'])
66 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.20"
67 | implementation 'androidx.appcompat:appcompat:1.1.0'
68 | implementation 'androidx.core:core-ktx:1.3.0'
69 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
70 | testImplementation 'junit:junit:4.12'
71 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
72 |
73 | implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
74 | implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
75 | implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta3"
76 | implementation 'com.google.android.material:material:1.0.0'
77 |
78 | implementation "androidx.room:room-runtime:2.6.1"
79 | implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
80 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
81 | implementation 'androidx.room:room-rxjava2:2.6.1'
82 | kapt "androidx.room:room-compiler:2.6.1"
83 |
84 | implementation "io.insert-koin:koin-android:3.5.0"
85 | implementation "io.insert-koin:koin-androidx-navigation:3.5.0"
86 | implementation "io.insert-koin:koin-androidx-workmanager:3.5.0"
87 |
88 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
89 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
90 | implementation 'io.reactivex.rxjava2:rxjava:2.2.11'
91 | implementation 'com.google.android.material:material:1.0.0'
92 | }
93 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/mulDivList/MulDivViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.mulDivList
2 |
3 | import androidx.core.content.ContextCompat
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.model.ExerciseType
7 | import com.octbit.rutmath.data.model.Operation
8 | import com.octbit.rutmath.databinding.NormalExerciseItemBinding
9 |
10 | class MulDivViewHolder(
11 | private val binding: NormalExerciseItemBinding,
12 | private val clickCallback: (exerciseType: ExerciseType) -> Unit) :
13 | RecyclerView.ViewHolder(binding.root) {
14 |
15 | companion object {
16 | const val MULTIPLY_VALUE = "×"
17 | const val DIVIDE_VALUE = "÷"
18 | const val MULTIPLY_DIVIDE_VALUE = "×/÷"
19 |
20 | // const val NEGATIVE_PLUS_MUL_VALUE="×+(-)"
21 | // const val NEGATIVE_MINUS_MUL_VALUE="×-(-)"
22 | // const val NEGATIVE_PLUS_DIV_VALUE="÷+(-)"
23 | // const val NEGATIVE_MINUS_DIV_VALUE="÷-(-)"
24 | //
25 | // const val NEGATIVE_PLUS_MINUS_MULTIPLY_VALUE = "×±(-)"
26 | // const val NEGATIVE_PLUS_MINUS_DIVIDE_VALUE = "÷±(-)"
27 | const val NEGATIVE_MUL = "× -"
28 | const val NEGATIVE_DIV = "÷ -"
29 | const val NEGATIVE_MUL_DIV = "×/÷ -"
30 |
31 |
32 | }
33 |
34 | fun bind(exerciseType: ExerciseType) = with(binding){
35 | title.text = when (exerciseType.operation) {
36 | Operation.MULTIPLY-> MULTIPLY_VALUE
37 | Operation.DIVIDE-> DIVIDE_VALUE
38 | Operation.MULTIPLY_DIVIDE -> MULTIPLY_DIVIDE_VALUE
39 |
40 | Operation.NEGATIVE_MUL -> NEGATIVE_MUL
41 | Operation.NEGATIVE_DIV -> NEGATIVE_DIV
42 | Operation.NEGATIVE_MUL_DIV -> NEGATIVE_MUL_DIV
43 | //new code here
44 | // Operation.NEGATIVE_PLUS_MUL->NEGATIVE_PLUS_MUL_VALUE
45 | // Operation.NEGATIVE_MINUS_MUL-> NEGATIVE_MINUS_MUL_VALUE
46 | // Operation.NEGATIVE_PLUS_DIV->NEGATIVE_PLUS_DIV_VALUE
47 | // Operation.NEGATIVE_MINUS_DIV-> NEGATIVE_MINUS_DIV_VALUE
48 | // Operation.NEGATIVE_PLUS_MINUS_MUL-> NEGATIVE_PLUS_MINUS_MULTIPLY_VALUE
49 | // Operation.NEGATIVE_PLUS_MINUS_DIV-> NEGATIVE_PLUS_MINUS_DIVIDE_VALUE
50 | else -> null
51 | }.plus(" ").plus(exerciseType.difficulty)
52 |
53 | /**
54 | * Set a listener on unlocked exercise tile and change its color
55 | */
56 |
57 | if (exerciseType.isUnlocked) {
58 | root.setOnClickListener {
59 | clickCallback.invoke(exerciseType)
60 | }
61 | root.background = ContextCompat.getDrawable(root.context,R.drawable.bg_in_tile_exercise)
62 | }
63 | else
64 | {
65 | root.setOnClickListener(null)
66 | root.background = ContextCompat.getDrawable(root.context,R.drawable.bg_in_tile_exercise_disabled)
67 | }
68 |
69 |
70 | val stars = arrayOf(star1, star2, star3, star4, star5)
71 |
72 | // Reset all stars to the default white icon
73 | stars.forEach { star ->
74 | star.setImageResource(R.drawable.ic_star)
75 | }
76 |
77 | for (i in 1..exerciseType.rate) {
78 | stars[i - 1].setImageResource(R.drawable.ic_star_yellow_24dp)
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/ui/fragment/chooseMode/ChooseModeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.ui.fragment.chooseMode
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.navigation.fragment.findNavController
8 | import androidx.navigation.fragment.navArgs
9 | import com.octbit.rutmath.util.base.BaseFragment
10 | import com.octbit.rutmath.R
11 | import com.octbit.rutmath.databinding.FragmentChooseModeBinding
12 | import com.octbit.rutmath.ui.view.TableRateDialog
13 |
14 |
15 | class ChooseModeFragment : BaseFragment() {
16 | override val layout: Int = R.layout.fragment_choose_mode
17 | private var _binding: FragmentChooseModeBinding? = null
18 | private val binding get() = _binding!!
19 | private val args: ChooseModeFragmentArgs by navArgs()
20 |
21 | override fun onCreateView(
22 | inflater: LayoutInflater,
23 | container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View? {
26 | _binding = FragmentChooseModeBinding.inflate(inflater, container, false)
27 | return binding.root
28 | }
29 |
30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
31 | super.onViewCreated(view, savedInstanceState)
32 | args.res.let {
33 | if (args.res > 0){
34 | TableRateDialog(requireContext(), args.res).show()
35 | }}
36 | initButtons()
37 | }
38 |
39 | private fun initButtons() = with(binding){
40 | addSubLayout.setOnClickListener {
41 | findNavController().navigate(
42 | ChooseModeFragmentDirections.actionChooseModeFragmentToAddSubListFragment(
43 | rate = -1,
44 | exerciseType = null,
45 | player = args.player
46 | )
47 | )
48 | }
49 | mulDivLayout.setOnClickListener {
50 | findNavController().navigate(
51 | ChooseModeFragmentDirections.actionChooseModeFragmentToMulDivListFragment(
52 | rate = -1,
53 | exerciseType = null,
54 | player = args.player
55 | )
56 | )
57 | }
58 | divisibilityLayout.setOnClickListener {
59 | findNavController().navigate(
60 | ChooseModeFragmentDirections.actionChooseModeFragmentToDivisibilityListFragment(
61 | rate = -1,
62 | exerciseType = null,
63 | player = args.player
64 | )
65 | )
66 | }
67 | unitsLayout.setOnClickListener {
68 | findNavController().navigate(
69 | ChooseModeFragmentDirections.actionChooseModeFragmentToUnitsListFragment(
70 | rate = -1,
71 | exerciseType = null,
72 | player = args.player
73 | )
74 | )
75 | }
76 | tableLayout.setOnClickListener {
77 | findNavController().navigate(
78 | ChooseModeFragmentDirections.actionChooseModeFragmentToTableGameFragment(
79 | args.player
80 | )
81 | )
82 | }
83 | }
84 |
85 | override fun onDestroy() {
86 | super.onDestroy()
87 | _binding = null
88 | }
89 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/font_certs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @array/com_google_android_gms_fonts_certs_dev
5 | - @array/com_google_android_gms_fonts_certs_prod
6 |
7 |
8 | -
9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
10 |
11 |
12 |
13 | -
14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/com/octbit/rutmath/util/base/BaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.octbit.rutmath.util.base
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import com.octbit.rutmath.R
6 | import com.octbit.rutmath.data.AppDatabase
7 | import com.octbit.rutmath.data.model.Settings
8 | import com.octbit.rutmath.di.appModule
9 | import com.octbit.rutmath.shared.di.androidSharedModule
10 | import com.octbit.rutmath.shared.di.sharedModule
11 | import com.octbit.rutmath.shared.usecase.DataUseCase
12 | import io.reactivex.Completable
13 | import io.reactivex.android.schedulers.AndroidSchedulers
14 | import io.reactivex.schedulers.Schedulers
15 | import kotlinx.coroutines.CoroutineScope
16 | import kotlinx.coroutines.Dispatchers
17 | import kotlinx.coroutines.SupervisorJob
18 | import kotlinx.coroutines.launch
19 | import org.koin.android.ext.android.inject
20 | //import org.koin.android.ext.android.startKoin
21 | import org.koin.android.ext.koin.androidContext
22 | import org.koin.core.context.startKoin
23 |
24 | /**
25 | * Main application object.
26 | */
27 | class BaseApplication : Application() {
28 |
29 | private val database: AppDatabase by inject()
30 | private val dataUseCase: DataUseCase by inject()
31 |
32 | // Application scope for coroutines
33 | private val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
34 |
35 | override fun onCreate() {
36 | super.onCreate()
37 | startKoin {
38 | androidContext(this@BaseApplication)
39 | modules(
40 | appModule, // Existing Android module
41 | sharedModule, // Shared KMP module
42 | androidSharedModule // Android-specific shared module
43 | )
44 | }
45 | initDatabaseIfNeeded()
46 | initSharedData()
47 | }
48 |
49 | @SuppressLint("CheckResult")
50 | private fun initDatabaseIfNeeded() {
51 | database.settingsDao().getAll()
52 | .observeOn(AndroidSchedulers.mainThread())
53 | .subscribeOn(Schedulers.io())
54 | .flatMapCompletable { databaseSettings ->
55 | if (databaseSettings.isEmpty()) {
56 | database.settingsDao()
57 | .insertAll(
58 | arrayListOf(
59 | Settings(
60 | maxNumberInBattleMode = 100,
61 | lastNickname1 = getString(R.string.player1),
62 | lastNickname2 = getString(R.string.player2),
63 | language = "en"
64 | )
65 | )
66 | )
67 | .observeOn(AndroidSchedulers.mainThread())
68 | .subscribeOn(Schedulers.io())
69 | } else {
70 | Completable.complete()
71 | }
72 | }
73 | .subscribe()
74 | }
75 |
76 | /**
77 | * Initialize shared data using the new KMP architecture.
78 | */
79 | private fun initSharedData() {
80 | applicationScope.launch {
81 | try {
82 | // Initialize default exercise types if needed
83 | dataUseCase.initializeDefaultExercisesIfNeeded()
84 |
85 | // Ensure settings exist
86 | dataUseCase.getSettings()
87 | } catch (e: Exception) {
88 | // Log error in production
89 | e.printStackTrace()
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/androidApp/src/main/res/drawable/logo.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
57 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Zrušit
5 | Ano
6 | Ne
7 | Chyba
8 | Uložit
9 | Prázdné
10 | Tabulka výsledků:
11 | Hráč1
12 | Hráč2
13 | Skóre:
14 | %s skóre: %d\n%s skóre: %d
15 | %d. %s
16 | Přezdívka nemůže být prázdná!
17 | Vybrat jazyk
18 | Max. číslo pro souboj
19 | Technická univerzita Rzeszów
20 | Postupný bonus +%d
21 | Vyberte cvičení ze seznamu:
22 | Sčítání a odčítání
23 | Násobení a dělení
24 | Dělitelnost
25 | Převod jednotek
26 | Násobilka
27 | Vyberte hráče ze seznamu\nnebo vytvořte nového tlačítkem plus
28 | Zadejte jména hráčů
29 | Přezdívka Hráče1 (nahoře):
30 | Přezdívka Hráče2 (dole):
31 | Start
32 | Seznam výsledků je prázdný.\nHrajte v bojovém režimu, abyste viděli nejlepší výsledky hráčů!
33 | Nápověda
34 | Hodnota nemůže být větší než: %1$d
35 | Hodnota nemůže být menší než: %1$d
36 | Hra skončena
37 | Zadejte přezdívku nového hráče:
38 | Přezdívka již existuje!
39 | Lehké
40 | Střední
41 | Těžké
42 | Velmi těžké
43 | Je
44 | dělitelné
45 | Čas
46 | Délka
47 | Hmotnost
48 | Plocha
49 | Všechny
50 | d,h,min,sek
51 | \?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Cvičení
55 | Nastavení
56 | Souboj
57 | Žebříček
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Zrušiť
5 | Áno
6 | Nie
7 | Chyba
8 | Uložiť
9 | Prázdne
10 | Tabuľka výsledkov:
11 | Hráč1
12 | Hráč2
13 | Skóre:
14 | %s skóre: %d\n%s skóre: %d
15 | %d. %s
16 | Prezývka nemôže byť prázdna!
17 | Vybrať jazyk
18 | Max. číslo pre súboj
19 | Technická univerzita Rzeszów
20 | Postupný bonus +%d
21 | Vyberte cvičenie zo zoznamu:
22 | Sčítanie a odčítanie
23 | Násobenie a delenie
24 | Deliteľnosť
25 | Konverzia jednotiek
26 | Násobiaca tabuľka
27 | Vyberte hráča zo zoznamu\nalebo vytvorte nového tlačidlom plus
28 | Zadajte mená hráčov
29 | Prezývka Hráča1 (hore):
30 | Prezývka Hráča2 (dole):
31 | Štart
32 | Zoznam výsledkov je prázdny.\nHrajte v súbojovom režime, aby ste videli najlepšie výsledky hráčov!
33 | Nápoveda
34 | Hodnota nemôže byť väčšia ako: %1$d
35 | Hodnota nemôže byť menšia ako: %1$d
36 | Hra skončená
37 | Zadajte prezývku nového hráča:
38 | Prezývka už existuje!
39 | Ľahké
40 | Stredné
41 | Ťažké
42 | Veľmi ťažké
43 | Je
44 | deliteľné
45 | Čas
46 | Dĺžka
47 | Hmotnosť
48 | Plocha
49 | Všetky
50 | d,h,min,sek
51 | \?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Cvičenia
55 | Nastavenia
56 | Súboj
57 | Rebríček
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Anuluj
5 | Tak
6 | Nie
7 | Błąd
8 | Zapisz
9 | Pusto
10 | Tablica wyników:
11 | Gracz1
12 | Gracz2
13 | Wynik:
14 | %s wynik: %d\n%s wynik: %d
15 | %d. %s
16 | Nazwa nie może być pusta!
17 | Wybierz język
18 | Maks. liczba dla pojedynku
19 | Politechnika Rzeszowska
20 | Bonus za sekwencję +%d
21 | Wybierz ćwiczenie z listy:
22 | Dodawanie i odejmowanie
23 | Mnożenie i dzielenie
24 | Podzielność
25 | Zamiana jednostek
26 | Tabliczka mnożenia
27 | Wybierz gracza z listy\nlub stwórz nowego za pomocą plusa
28 | Podaj nazwy graczy
29 | Nazwa Gracza1 (góra):
30 | Nazwa Gracza2 (dół):
31 | Rozpocznij
32 | Tablica wyników jest pusta.\nGraj w trybie bitwy by zobaczyć najlepsze wyniki!
33 | Podpowiedź
34 | Wartość nie może być większa niż: %1$d
35 | Wartość nie może być mniejsza niż: %1$d
36 | Gra zakończona
37 | Podaj nazwę nowego gracza:
38 | Nazwa już istnieje!
39 | Łatwy
40 | Średni
41 | Trudny
42 | Bardzo Trudny
43 | Czy
44 | jest podzielne przez
45 | Czas
46 | Długość
47 | Waga
48 | Powierzchnia
49 | Wszystkie
50 | d,godz,min,sek
51 | \?
52 | https://w.prz.edu.pl
53 | https://weii.prz.edu.pl
54 | Ćwiczenia
55 | Ustawienia
56 | Pojedynek
57 | Wyniki
58 |
59 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RUTMath
3 | OK
4 | Cancel
5 | Yes
6 | No
7 | Error
8 | Save
9 | Empty
10 | Scoreboard:
11 | Player1
12 | Player2
13 | Score:
14 | %s score: %d\n%s score: %d
15 | %d. %s
16 | Nickname can not be empty!
17 | Select language
18 | Max. number for duel
19 | Rzeszów University of Technology
20 | Sequential bonus +%d
21 | Select an exercise from the list:
22 | Addition and Subtraction
23 | Multiplication and Division
24 | Divisibility
25 | Unit conversion
26 | Multiplication table
27 | Choose a player from the list\nor create new one with plus button
28 | Enter players nicknames
29 | Player1 (top) nickname:
30 | Player2 (bottom) nickname:
31 | Start
32 | Scores list is empty.\nPlay in battle mode to see best players results!
33 | Hint
34 | Value can not be bigger than: %1$d
35 | Value can not be smaller than: %1$d
36 | Game ended
37 | Enter nickname of new player:
38 | Nickname exists!
39 | Easy
40 | Medium
41 | Hard
42 | Very Hard
43 | Is
44 | divisible by
45 | Time
46 | Length
47 | Weight
48 | Surface
49 | All
50 | d,h,min,sec
51 | ?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Exercises
55 | Settings
56 | Battle
57 | Leaderboard
58 |
59 |
60 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/layout/fragment_units_game.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
27 |
28 |
38 |
39 |
49 |
50 |
61 |
62 |
68 |
69 |
77 |
78 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Mégse
5 | Igen
6 | Nem
7 | Hiba
8 | Mentés
9 | Üres
10 | Eredménytábla:
11 | Játékos1
12 | Játékos2
13 | Pontszám:
14 | %s pontszám: %d\n%s pontszám: %d
15 | %d. %s
16 | A becenév nem lehet üres!
17 | Nyelv kiválasztása
18 | Max. szám párbajhoz
19 | Rzeszówi Műszaki Egyetem
20 | Egymást követő bónusz +%d
21 | Válasszon gyakorlatot a listából:
22 | Összeadás és kivonás
23 | Szorzás és osztás
24 | Oszthatóság
25 | Mértékegység átváltás
26 | Szorzótábla
27 | Válasszon játékost a listából\nvagy hozzon létre újat a plusz gombbal
28 | Adja meg a játékosok neveit
29 | Játékos1 (felső) becenév:
30 | Játékos2 (alsó) becenév:
31 | Indítás
32 | Az eredménylista üres.\nJátsszon csata módban a legjobb játékos eredmények megtekintéséhez!
33 | Tipp
34 | Az érték nem lehet nagyobb mint: %1$d
35 | Az érték nem lehet kisebb mint: %1$d
36 | Játék befejezve
37 | Adja meg az új játékos becenevét:
38 | A becenév már létezik!
39 | Könnyű
40 | Közepes
41 | Nehéz
42 | Nagyon nehéz
43 | Osztható-e
44 | ezzel
45 | Idő
46 | Hosszúság
47 | Súly
48 | Felület
49 | Összes
50 | n,ó,perc,mp
51 | \?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Gyakorlatok
55 | Beállítások
56 | Csata
57 | Ranglista
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Annuleren
5 | Ja
6 | Nee
7 | Fout
8 | Opslaan
9 | Leeg
10 | Scorebord:
11 | Speler1
12 | Speler2
13 | Score:
14 | %s score: %d\n%s score: %d
15 | %d. %s
16 | Bijnaam mag niet leeg zijn!
17 | Selecteer taal
18 | Max. getal voor duel
19 | Universiteit van Technologie Rzeszów
20 | Opeenvolgende bonus +%d
21 | Selecteer een oefening uit de lijst:
22 | Optellen en aftrekken
23 | Vermenigvuldigen en delen
24 | Deelbaarheid
25 | Eenheidsconversie
26 | Vermenigvuldigingstafel
27 | Kies een speler uit de lijst\nof maak een nieuwe aan met de plus knop
28 | Voer spelersnamen in
29 | Speler1 (boven) bijnaam:
30 | Speler2 (onder) bijnaam:
31 | Start
32 | Scorelijst is leeg.\nSpeel in gevechtsmode om de beste spelerresultaten te zien!
33 | Hint
34 | Waarde mag niet groter zijn dan: %1$d
35 | Waarde mag niet kleiner zijn dan: %1$d
36 | Spel beëindigd
37 | Voer bijnaam van nieuwe speler in:
38 | Bijnaam bestaat al!
39 | Makkelijk
40 | Gemiddeld
41 | Moeilijk
42 | Zeer moeilijk
43 | Is
44 | deelbaar door
45 | Tijd
46 | Lengte
47 | Gewicht
48 | Oppervlakte
49 | Alle
50 | d,u,min,sec
51 | \?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Oefeningen
55 | Instellingen
56 | Gevecht
57 | Klassement
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OK
3 | Cancelar
4 | Sim
5 | Não
6 | Error
7 | Salvar
8 | Vazio
9 | Placar:
10 | Jogador1
11 | Jogador2
12 | Pontuação:
13 | %s pontos: %d\n%s pontos: %d
14 | %d. %s
15 | Apelido não pode ser vazio!
16 | Selecionar linguagem
17 | Número máximo para duelos
18 | Universidade de Tecnologia de Rzeszów
19 | Bônus de sequência +%d
20 | Selecione um exercício da lista:
21 | Adição e Subtração
22 | Multiplicação e Divisão
23 | Divisibilidade
24 | Conversão de unidades
25 | Tabela de multiplicação
26 | Escolha um jogador da lista\nou crie um novo com o botão mais
27 | Entre com os apelidos dos jogadores
28 | Apelido Jogador1 (cima):
29 | Apelido Jogador2 (baixo):
30 | Iniciar
31 | A lista de pontuações está vazia.\nJogue no modo de batalha para ver os melhores resultados dos jogadores!
32 | Dica
33 | O valor não pode ser maior do que: %1$d
34 | O valor não pode ser menor do que: %1$d
35 | Jogo encerrado
36 | Digite o apelido do novo jogador:
37 | O apelido já existe!
38 | Fácil
39 | Médio
40 | Difícil
41 | Muito Difícil
42 | É
43 | Divisível por
44 | Tempo
45 | Comprimento
46 | Peso
47 | Área
48 | Todos
49 | d,h,min,seg
50 | \?
51 | https://w.prz.edu.pl/en/
52 | https://weii.prz.edu.pl/en/
53 | Exercícios
54 | Configurações
55 | Batalha
56 | Lista de Pontuações
57 |
58 |
59 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Abbrechen
5 | Ja
6 | Nein
7 | Fehler
8 | Speichern
9 | Leer
10 | Punktetafel:
11 | Spieler1
12 | Spieler2
13 | Punkte:
14 | %s Punkte: %d\n%s Punkte: %d
15 | %d. %s
16 | Spitzname darf nicht leer sein!
17 | Sprache auswählen
18 | Max. Zahl für Duell
19 | Technische Universität Rzeszów
20 | Aufeinanderfolgender Bonus +%d
21 | Wählen Sie eine Übung aus der Liste:
22 | Addition und Subtraktion
23 | Multiplikation und Division
24 | Teilbarkeit
25 | Einheitenumrechnung
26 | Multiplikationstabelle
27 | Wählen Sie einen Spieler aus der Liste\noder erstellen Sie einen neuen mit dem Plus-Button
28 | Spielernamen eingeben
29 | Spieler1 (oben) Spitzname:
30 | Spieler2 (unten) Spitzname:
31 | Start
32 | Die Punkteliste ist leer.\nSpielen Sie im Kampfmodus, um die besten Spielerergebnisse zu sehen!
33 | Hinweis
34 | Wert darf nicht größer sein als: %1$d
35 | Wert darf nicht kleiner sein als: %1$d
36 | Spiel beendet
37 | Spitzname des neuen Spielers eingeben:
38 | Spitzname existiert bereits!
39 | Einfach
40 | Mittel
41 | Schwer
42 | Sehr schwer
43 | Ist
44 | teilbar durch
45 | Zeit
46 | Länge
47 | Gewicht
48 | Fläche
49 | Alle
50 | T,Std,Min,Sek
51 | \?
52 | https://w.prz.edu.pl/en/
53 | https://weii.prz.edu.pl/en/
54 | Übungen
55 | Einstellungen
56 | Kampf
57 | Bestenliste
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OK
3 | Annuler
4 | Oui
5 | Non
6 | Erreur
7 | Enregistrer
8 | Vide
9 | Tableau des scores :
10 | Joueur1
11 | Joueur2
12 | Score :
13 | %s score : %d\n%s score : %d
14 | %d. %s
15 | Le nom ne peut pas être vide !
16 | Sélectionnez la langue
17 | Nombre maximal pour les duels
18 | Université de Technologie de Rzeszów
19 | Bonus de séquence : +%d
20 | Choisissez un exercice dans la liste :
21 | Additions et Soustractions
22 | Multiplications et Divisions
23 | Divisibilité
24 | Conversion d\'unités
25 | Tables de multiplications
26 | Choisissez une joueur dans la liste\nou ajoutez un joueur avec le bouton +
27 | Entrez le nom des joueurs
28 | Joueur1 (en haut) :
29 | Joueur2 (en bas) :
30 | Démarrer
31 | La liste des scores est vide. Jouez en mode duel pour savoir qui est le meilleur joueur !
32 | Conseil
33 | La valeur ne peut pas être plus grande que : %1$d
34 | La valeur ne peut pas être plus petite que : %1$d
35 | Partie terminée
36 | Entrez le nom du nouveau joueur :
37 | Ce nom existe déjà !
38 | Facile
39 | Intermédiaire
40 | Difficile
41 | Très difficile
42 | Est-ce que
43 | est divisible par
44 | Durée
45 | Poids
46 | Surface
47 | Tout
48 | j,h,min,sec
49 | Longueur
50 | \?
51 | https://w.prz.edu.pl/en/
52 | https://weii.prz.edu.pl/en/
53 | Exercices
54 | Paramètres
55 | Duel
56 | Liste des Scores
57 |
58 |
59 |
--------------------------------------------------------------------------------