Initial commit
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/*
|
||||||
|
/.idea - PC/*
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
app/release/*
|
||||||
19
Mental Arithmetic.iml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.id="Mental Arithmetic" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="java-gradle" name="Java-Gradle">
|
||||||
|
<configuration>
|
||||||
|
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||||
|
<option name="BUILDABLE" value="false" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
199
app/app.iml
Normal file
43
app/build.gradle
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 29
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "de.sebse.mentalarithmetic"
|
||||||
|
minSdkVersion 15
|
||||||
|
targetSdkVersion 29
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation 'androidx.core:core-ktx:1.1.0'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
|
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||||
|
implementation "androidx.preference:preference:1.1.0"
|
||||||
|
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||||
|
implementation 'com.google.android.material:material:1.2.0-alpha03'
|
||||||
|
implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
|
||||||
|
implementation 'me.relex:circleindicator:2.1.4'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
}
|
||||||
21
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package de.sebse.mentalarithmetic
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("de.sebse.mentalarithmetic", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="de.sebse.mentalarithmetic">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
BIN
app/src/main/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
100
app/src/main/java/de/sebse/mentalarithmetic/MainActivity.kt
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package de.sebse.mentalarithmetic
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentTransaction
|
||||||
|
import de.sebse.mentalarithmetic.fragments.*
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TipObject
|
||||||
|
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity(), TaskItemFragment.OnListFragmentInteractionListener,
|
||||||
|
TaskFragment.IGameListener, SummaryFragment.IGameSummaryListener {
|
||||||
|
|
||||||
|
var currentFragment: Fragment? = null
|
||||||
|
val CURRENT_FRAGMENT_STATE: String = "CURRENT_FRAGMENT_STATE"
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
savedInstanceState?.let {
|
||||||
|
//Restore the fragment's instance
|
||||||
|
Log.d("APP", "here1")
|
||||||
|
val fragment = supportFragmentManager.getFragment(savedInstanceState, CURRENT_FRAGMENT_STATE)
|
||||||
|
fragment?.let {
|
||||||
|
Log.d("APP", "here")
|
||||||
|
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||||
|
ft.replace(R.id.fragment_holder, fragment)
|
||||||
|
ft.commit()
|
||||||
|
currentFragment = fragment
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fragment = TaskPagerFragment.newInstance()
|
||||||
|
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||||
|
ft.replace(R.id.fragment_holder, fragment)
|
||||||
|
ft.commit()
|
||||||
|
currentFragment = fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onListFragmentInteraction(item: ItemObject) {
|
||||||
|
val fragment: Fragment? = if (item is TaskObject) {
|
||||||
|
item.start(applicationContext)
|
||||||
|
TaskFragment.newInstance(item)
|
||||||
|
} else if (item is TipObject) {
|
||||||
|
TipFragment.newInstance(item)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (fragment != null) {
|
||||||
|
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||||
|
ft.replace(R.id.fragment_holder, fragment)
|
||||||
|
ft.commit()
|
||||||
|
currentFragment = fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
currentFragment?.let { supportFragmentManager.putFragment(outState, CURRENT_FRAGMENT_STATE, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGameFinished(item: TaskObject) {
|
||||||
|
val fragment = SummaryFragment.newInstance(item)
|
||||||
|
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||||
|
ft.replace(R.id.fragment_holder, fragment)
|
||||||
|
ft.commit()
|
||||||
|
currentFragment = fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGameSummaryRetry(item: TaskObject) {
|
||||||
|
onListFragmentInteraction(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onGameSummaryFinished() {
|
||||||
|
goToList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun goToList() {
|
||||||
|
val fragment = TaskPagerFragment.newInstance()
|
||||||
|
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||||
|
ft.replace(R.id.fragment_holder, fragment)
|
||||||
|
ft.commit()
|
||||||
|
currentFragment = fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (currentFragment is TaskPagerFragment) {
|
||||||
|
if (!(currentFragment as TaskPagerFragment).previous()) {
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goToList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
|
||||||
|
/*import android.inputmethodservice.Keyboard
|
||||||
|
import android.inputmethodservice.KeyboardView
|
||||||
|
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener*/
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemFactory
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* Use the [SummaryFragment.newInstance] factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class SummaryFragment : Fragment() {
|
||||||
|
private lateinit var listener: IGameSummaryListener
|
||||||
|
private var item: TaskObject? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
Log.d("SummaryFragment", (savedInstanceState != null).toString())
|
||||||
|
arguments?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TaskObject
|
||||||
|
}
|
||||||
|
savedInstanceState?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TaskObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_summary, container, false)?.also { view ->
|
||||||
|
view.findViewById<Button>(R.id.retry).setOnClickListener{v -> item?.let {this.listener.onGameSummaryRetry(it)} }
|
||||||
|
view.findViewById<Button>(R.id.exit).setOnClickListener{v -> this.listener.onGameSummaryFinished() }
|
||||||
|
view.findViewById<TextView>(R.id.time).text = (item?.getLiveTime() ?: "").toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
item?.let { outState.putString(ARG_PARAM1, it.ID) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
if (context is IGameSummaryListener) {
|
||||||
|
this.listener = context
|
||||||
|
} else {
|
||||||
|
throw RuntimeException(context.toString() + " must implement IGameSummaryListener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGameSummaryListener {
|
||||||
|
fun onGameSummaryRetry(item: TaskObject)
|
||||||
|
fun onGameSummaryFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// TODO: Rename parameter arguments, choose names that match
|
||||||
|
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||||
|
private const val ARG_PARAM1 = "param1"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter 1.
|
||||||
|
* @return A new instance of fragment SummaryFragment.
|
||||||
|
*/
|
||||||
|
// TODO: Rename and change types and number of parameters
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(param1: TaskObject) =
|
||||||
|
SummaryFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString(ARG_PARAM1, param1.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
|
||||||
|
/*import android.inputmethodservice.Keyboard
|
||||||
|
import android.inputmethodservice.KeyboardView
|
||||||
|
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener*/
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.style.StrikethroughSpan
|
||||||
|
import android.text.style.StyleSpan
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemFactory
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
import de.sebse.mentalarithmetic.utils.BoardView
|
||||||
|
import de.sebse.mentalarithmetic.utils.Keyboard
|
||||||
|
import kotlinx.android.synthetic.main.fragment_task.*
|
||||||
|
import me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* Use the [TaskFragment.newInstance] factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class TaskFragment : Fragment() {
|
||||||
|
//private var mKeyboardView: KeyboardView? = null
|
||||||
|
//private var mKeyboard: Keyboard? = null
|
||||||
|
// TODO: Rename and change types of parameters
|
||||||
|
private var item: TaskObject? = null
|
||||||
|
private var inputView: TextView? = null
|
||||||
|
private var questionView: TextView? = null
|
||||||
|
private var questionCorrectView: TextView? = null
|
||||||
|
private var questionCountView: TextView? = null
|
||||||
|
private var boardView: BoardView? = null
|
||||||
|
private var gameListener: IGameListener? = null
|
||||||
|
|
||||||
|
interface IGameListener {
|
||||||
|
fun onGameFinished(item: TaskObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
Log.d("TaskFragment", (savedInstanceState != null).toString())
|
||||||
|
arguments?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TaskObject
|
||||||
|
}
|
||||||
|
savedInstanceState?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TaskObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_task, container, false)?.also { view ->
|
||||||
|
item?.let {
|
||||||
|
view.findViewById<TextView>(R.id.name).apply {
|
||||||
|
text = getString(it.NAME)
|
||||||
|
}
|
||||||
|
questionView = view.findViewById<TextView>(R.id.question).apply {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
questionCountView = view.findViewById<TextView>(R.id.question_count).apply {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
questionCorrectView = view.findViewById<TextView>(R.id.question_correct).apply {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
inputView = view.findViewById<TextView>(R.id.answer).apply {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
boardView = view.findViewById<BoardView>(R.id.keyboardview).apply {
|
||||||
|
setBtnListener(::btnListener)
|
||||||
|
setSubmitListener(::submitListener)
|
||||||
|
}
|
||||||
|
view.findViewById<TextView>(R.id.time).let { time ->
|
||||||
|
view.findViewById<MaterialProgressBar>(R.id.progress2).let { progress2 ->
|
||||||
|
val handler = Handler()
|
||||||
|
val runnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
time.text = it.getLiveTime().toString()
|
||||||
|
val twentyPercent = it.SILVER_TIME - it.GOLD_TIME
|
||||||
|
val progress100 = it.GOLD_TIME - twentyPercent
|
||||||
|
val progress0 = it.GOLD_TIME + twentyPercent * 4
|
||||||
|
val prog = min(progress0, max(progress100, (it.getLiveTime() / (it.getCountCurrent()+1) * it.getCountTotal()).toInt()))
|
||||||
|
progress2.progress =
|
||||||
|
(100 - (prog - progress100) / (twentyPercent * 0.05)).roundToInt()
|
||||||
|
handler.postDelayed(this, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler.postDelayed(runnable, 1)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
setQuestion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
setQuestion()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setQuestion() {
|
||||||
|
Log.d("ff", item?.getCurrect().toString())
|
||||||
|
item?.getCurrect()?.let {
|
||||||
|
questionView?.text = it.getQuestion()
|
||||||
|
view?.let { view ->
|
||||||
|
val keyboard = Keyboard(view.context, it.getKeyboard())
|
||||||
|
boardView?.setKeyboard(keyboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item?.let {
|
||||||
|
questionCountView?.text = getString(R.string.question_count, it.getCountCurrent())
|
||||||
|
questionCorrectView?.text = getString(R.string.question_currect, it.getCountCorrect(), it.COUNT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
item?.let { outState.putString(ARG_PARAM1, it.ID) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun btnListener(code: Int) {
|
||||||
|
item?.let {
|
||||||
|
inputView?.let {v ->
|
||||||
|
v.text = it.getCurrect()?.translate(boardView?.getText() ?: "") ?: ""
|
||||||
|
}
|
||||||
|
it.getCurrect()?.let { current ->
|
||||||
|
if (!current.getMultipleInput()) {
|
||||||
|
submit(listOf(code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun submitListener(text: List<Int>) {
|
||||||
|
submit(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun submit(text: List<Int>) {
|
||||||
|
item?.let {
|
||||||
|
val answer = text.joinToString(separator = "")
|
||||||
|
Log.d("FRAG", answer)
|
||||||
|
val (valid, correct, question) = it.answer(answer, requireContext())
|
||||||
|
it.pause()
|
||||||
|
setAnswerColor(valid, correct, it)
|
||||||
|
keyboardview?.lock()
|
||||||
|
keyboardview?.reset()
|
||||||
|
Handler().postDelayed({
|
||||||
|
if (question != null) {
|
||||||
|
unsetAnswerColor()
|
||||||
|
setQuestion()
|
||||||
|
keyboardview?.unlock()
|
||||||
|
it.resume()
|
||||||
|
} else {
|
||||||
|
val time: Long = it.getLiveTime()
|
||||||
|
val score = it.getScore(requireContext())
|
||||||
|
if (time > Integer.MIN_VALUE && time < Integer.MAX_VALUE && (score == 0 || time < score)) {
|
||||||
|
it.setScore(requireContext(), time.toInt())
|
||||||
|
}
|
||||||
|
this.gameListener?.onGameFinished(it)
|
||||||
|
keyboardview?.unlock()
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAnswerColor(valid: Boolean, correct: String, item: TaskObject) {
|
||||||
|
context?.let {context ->
|
||||||
|
val correctFormatted = item.getCurrect()?.translate(correct) ?: ""
|
||||||
|
val color = if (valid) {
|
||||||
|
ContextCompat.getColor(context, android.R.color.holo_green_light)
|
||||||
|
} else {
|
||||||
|
ContextCompat.getColor(context, android.R.color.holo_red_light)
|
||||||
|
}
|
||||||
|
keyboardview?.apply {
|
||||||
|
setBackgroundColor(color)
|
||||||
|
}
|
||||||
|
inputView?.apply {
|
||||||
|
setBackgroundColor(color)
|
||||||
|
if (!valid) {
|
||||||
|
text = SpannableString("$text $correctFormatted").apply {
|
||||||
|
setSpan(
|
||||||
|
StrikethroughSpan(),
|
||||||
|
0, text.length,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
setSpan(
|
||||||
|
StyleSpan(Typeface.BOLD),
|
||||||
|
text.length, "$text $correctFormatted".length,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unsetAnswerColor() {
|
||||||
|
context?.let {context ->
|
||||||
|
val color = ContextCompat.getColor(context, R.color.colorPrimaryDark)
|
||||||
|
keyboardview?.apply {
|
||||||
|
setBackgroundColor(color)
|
||||||
|
}
|
||||||
|
inputView?.apply {
|
||||||
|
setBackgroundColor(color)
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
if (context is IGameListener) {
|
||||||
|
this.gameListener = context
|
||||||
|
} else {
|
||||||
|
throw RuntimeException(context.toString() + " must implement IGameListener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// TODO: Rename parameter arguments, choose names that match
|
||||||
|
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||||
|
private const val ARG_PARAM1 = "param1"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter 1.
|
||||||
|
* @return A new instance of fragment TaskFragment.
|
||||||
|
*/
|
||||||
|
// TODO: Rename and change types and number of parameters
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(param1: TaskObject) =
|
||||||
|
TaskFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString(ARG_PARAM1, param1.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.google.android.material.textview.MaterialTextView
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
|
||||||
|
|
||||||
|
import de.sebse.mentalarithmetic.fragments.TaskItemFragment.OnListFragmentInteractionListener
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TipObject
|
||||||
|
import de.sebse.mentalarithmetic.types.getString
|
||||||
|
|
||||||
|
import kotlinx.android.synthetic.main.fragment_taskitem.view.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_taskitem.view.content
|
||||||
|
import kotlinx.android.synthetic.main.fragment_tipitem.view.*
|
||||||
|
import me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [RecyclerView.Adapter] that can display a [TaskObject] and makes a call to the
|
||||||
|
* specified [OnListFragmentInteractionListener].
|
||||||
|
* TODO: Replace the implementation with code for your data type.
|
||||||
|
*/
|
||||||
|
class TaskItemAdapter(
|
||||||
|
private val mValues: List<ItemObject>,
|
||||||
|
private val mListener: OnListFragmentInteractionListener?
|
||||||
|
) : RecyclerView.Adapter<TaskItemAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
private val mOnClickListener: View.OnClickListener
|
||||||
|
|
||||||
|
init {
|
||||||
|
mOnClickListener = View.OnClickListener { v ->
|
||||||
|
val item = v.tag as ItemObject
|
||||||
|
// Notify the active callbacks interface (the activity, if the fragment is attached to
|
||||||
|
// one) that an item has been selected.
|
||||||
|
mListener?.onListFragmentInteraction(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
return if (viewType == 0) ViewHolderTask(LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.fragment_taskitem, parent, false))
|
||||||
|
else {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.fragment_tipitem, parent, false)
|
||||||
|
Log.d("TIP", view.toString())
|
||||||
|
ViewHolderTip(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val item = mValues[position]
|
||||||
|
holder.mContentView.text = holder.mView.context.getString(item.NAME)
|
||||||
|
|
||||||
|
|
||||||
|
if (item is TaskObject) {
|
||||||
|
holder as ViewHolderTask
|
||||||
|
holder.mPersonalTime.text = holder.mView.context.getString(R.string.time, item.getScore(holder.mView.context) / 1000, item.getScore(holder.mView.context) % 1000)
|
||||||
|
holder.mGoldTime.text = (item.GOLD_TIME / 1000).toString()
|
||||||
|
holder.mSilverTime.text = (item.SILVER_TIME / 1000).toString()
|
||||||
|
|
||||||
|
val score = item.getScore(holder.mView.context)
|
||||||
|
if (score > 0) {
|
||||||
|
val twentyPercent = item.SILVER_TIME - item.GOLD_TIME
|
||||||
|
val progress100 = item.GOLD_TIME - twentyPercent
|
||||||
|
val progress0 = item.GOLD_TIME + twentyPercent * 4
|
||||||
|
val progress = min(progress0, max(progress100, score))
|
||||||
|
holder.mProgressView.progress = (100 - (progress - progress100) / (twentyPercent * 0.05)).roundToInt()
|
||||||
|
|
||||||
|
if (score < item.SILVER_TIME) {
|
||||||
|
holder.mSilverTime.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_star_silver, 0, 0, 0)
|
||||||
|
}
|
||||||
|
if (score < item.GOLD_TIME) {
|
||||||
|
holder.mGoldTime.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_star_gold, 0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder as ViewHolderTip
|
||||||
|
holder.mDescription.text = holder.mView.context.getString(item.DESCRIPTION)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position > 0) {
|
||||||
|
var previous: TaskObject?
|
||||||
|
var pos = position
|
||||||
|
do {
|
||||||
|
pos--
|
||||||
|
previous = if (mValues[pos] is TaskObject) mValues[pos] as TaskObject else null
|
||||||
|
} while (previous == null && pos > 0)
|
||||||
|
if (previous != null && (previous.getScore(holder.mView.context) == 0 || previous.getScore(holder.mView.context) > previous.SILVER_TIME)) {
|
||||||
|
holder.mView.alpha = 0.5f
|
||||||
|
with(holder.mView) {
|
||||||
|
tag = item
|
||||||
|
setOnClickListener(mOnClickListener)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.mView.alpha = 1f
|
||||||
|
with(holder.mView) {
|
||||||
|
tag = item
|
||||||
|
setOnClickListener(mOnClickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
val item = mValues[position]
|
||||||
|
return if (item is TaskObject) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = mValues.size
|
||||||
|
|
||||||
|
open inner class ViewHolder(open val mView: View): RecyclerView.ViewHolder(mView) {
|
||||||
|
val mContentView: TextView by lazy { mView.content }
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return super.toString() + " '" + mContentView.text + "'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ViewHolderTask(override val mView: View): ViewHolder(mView) {
|
||||||
|
val mProgressView: MaterialProgressBar = mView.progress2
|
||||||
|
val mGoldTime: MaterialTextView = mView.gold_time
|
||||||
|
val mSilverTime: MaterialTextView = mView.silver_time
|
||||||
|
val mPersonalTime: MaterialTextView = mView.personal_time
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ViewHolderTip(override val mView: View): ViewHolder(mView) {
|
||||||
|
val mDescription: MaterialTextView = mView.description
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import de.sebse.mentalarithmetic.types.Categories
|
||||||
|
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemFactory
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fragment representing a list of Items.
|
||||||
|
* Activities containing this fragment MUST implement the
|
||||||
|
* [TaskItemFragment.OnListFragmentInteractionListener] interface.
|
||||||
|
*/
|
||||||
|
class TaskItemFragment : Fragment() {
|
||||||
|
private val KEY_CATEGORY: String = "KEY_CATEGORY"
|
||||||
|
|
||||||
|
private var listener: OnListFragmentInteractionListener? = null
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val view = inflater.inflate(R.layout.fragment_taskitem_list, container, false)
|
||||||
|
|
||||||
|
// Set the adapter
|
||||||
|
if (view is RecyclerView) {
|
||||||
|
with(view) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = TaskItemAdapter(ItemFactory.CATEGORIES_LIST[arguments?.get(KEY_CATEGORY)] ?: ArrayList(), listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
if (context is OnListFragmentInteractionListener) {
|
||||||
|
listener = context
|
||||||
|
} else {
|
||||||
|
throw RuntimeException(context.toString() + " must implement OnListFragmentInteractionListener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetach() {
|
||||||
|
super.onDetach()
|
||||||
|
listener = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface must be implemented by activities that contain this
|
||||||
|
* fragment to allow an interaction in this fragment to be communicated
|
||||||
|
* to the activity and potentially other fragments contained in that
|
||||||
|
* activity.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Android Training lesson
|
||||||
|
* [Communicating with Other Fragments](http://developer.android.com/training/basics/fragments/communicating.html)
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
|
interface OnListFragmentInteractionListener {
|
||||||
|
// TODO: Update argument type and name
|
||||||
|
fun onListFragmentInteraction(item: ItemObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
// TODO: Customize parameter initialization
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(category: Categories): TaskItemFragment {
|
||||||
|
return TaskItemFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putSerializable(KEY_CATEGORY, category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemFactory
|
||||||
|
|
||||||
|
class TaskPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
Log.d("Adapter", ItemFactory.CATEGORIES.size.toString())
|
||||||
|
return ItemFactory.CATEGORIES.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createFragment(position: Int): Fragment = TaskItemFragment.newInstance(ItemFactory.CATEGORIES[position])
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import kotlinx.android.synthetic.main.fragment_taskitem_pager.view.*
|
||||||
|
import me.relex.circleindicator.CircleIndicator3
|
||||||
|
|
||||||
|
class TaskPagerFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var viewPager: ViewPager2
|
||||||
|
private lateinit var titleStrip: CircleIndicator3
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val view = inflater.inflate(R.layout.fragment_taskitem_pager, container, false)
|
||||||
|
viewPager = view.findViewById(R.id.pager)
|
||||||
|
viewPager.adapter = TaskPagerAdapter(this)
|
||||||
|
titleStrip = view.findViewById(R.id.titlestrip)
|
||||||
|
|
||||||
|
titleStrip.setViewPager(viewPager)
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
fun previous(): Boolean {
|
||||||
|
return if (viewPager.currentItem > 0) {
|
||||||
|
viewPager.currentItem--
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
// TODO: Customize parameter initialization
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance() =
|
||||||
|
TaskPagerFragment().apply {
|
||||||
|
arguments = Bundle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package de.sebse.mentalarithmetic.fragments
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Html
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import de.sebse.mentalarithmetic.types.ItemFactory
|
||||||
|
import de.sebse.mentalarithmetic.types.TaskObject
|
||||||
|
import de.sebse.mentalarithmetic.types.TipObject
|
||||||
|
import de.sebse.mentalarithmetic.utils.ImageGetter
|
||||||
|
import de.sebse.mentalarithmetic.utils.TagHandler
|
||||||
|
import kotlinx.android.synthetic.main.fragment_tip.view.*
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* Use the [TipFragment.newInstance] factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class TipFragment : Fragment() {
|
||||||
|
private var item: TipObject? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
Log.d("TaskFragment", (savedInstanceState != null).toString())
|
||||||
|
arguments?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TipObject
|
||||||
|
}
|
||||||
|
savedInstanceState?.let {
|
||||||
|
val param1 = it.getString(ARG_PARAM1)
|
||||||
|
item = ItemFactory.ITEM_MAP[param1] as TipObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_tip, container, false)?.also { view ->
|
||||||
|
item?.let {
|
||||||
|
val name = view.name
|
||||||
|
name.text = HtmlCompat.fromHtml(getString(it.HTML), HtmlCompat.FROM_HTML_MODE_LEGACY, ImageGetter(requireContext()), TagHandler())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
item?.let { outState.putString(ARG_PARAM1, it.ID) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// TODO: Rename parameter arguments, choose names that match
|
||||||
|
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||||
|
private const val ARG_PARAM1 = "param1"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter 1.
|
||||||
|
* @return A new instance of fragment TaskFragment.
|
||||||
|
*/
|
||||||
|
// TODO: Rename and change types and number of parameters
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(param1: TipObject) =
|
||||||
|
TipFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString(ARG_PARAM1, param1.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
enum class Categories {
|
||||||
|
BASIC,
|
||||||
|
TRICKS,
|
||||||
|
TIME
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
|
object ItemFactory {
|
||||||
|
/**
|
||||||
|
* An array of sample (dummy) items.
|
||||||
|
*/
|
||||||
|
val ITEMS: MutableList<ItemObject> = ArrayList()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of sample (dummy) items, by ID.
|
||||||
|
*/
|
||||||
|
val ITEM_MAP: MutableMap<String, ItemObject> = HashMap()
|
||||||
|
|
||||||
|
val CATEGORIES: MutableList<Categories> = ArrayList()
|
||||||
|
|
||||||
|
val CATEGORIES_MAP: MutableMap<Categories, MutableMap<String, ItemObject>> = EnumMap(Categories::class.java)
|
||||||
|
|
||||||
|
val CATEGORIES_LIST: MutableMap<Categories, MutableList<ItemObject>> = EnumMap(Categories::class.java)
|
||||||
|
|
||||||
|
init {
|
||||||
|
addItem(Tip0101)
|
||||||
|
addItem(Task0101)
|
||||||
|
addItem(Task0102)
|
||||||
|
addItem(Task0103)
|
||||||
|
|
||||||
|
addItem(Tip0201)
|
||||||
|
addItem(Task0201)
|
||||||
|
addItem(Tip0202)
|
||||||
|
addItem(Task0202)
|
||||||
|
addItem(Task0203)
|
||||||
|
addItem(Task0204)
|
||||||
|
addItem(Task0205)
|
||||||
|
addItem(Task0206)
|
||||||
|
addItem(Task0207)
|
||||||
|
addItem(Task0208)
|
||||||
|
addItem(Tip0203)
|
||||||
|
addItem(Task0209)
|
||||||
|
addItem(Tip0204)
|
||||||
|
addItem(Task0210)
|
||||||
|
addItem(Task0211)
|
||||||
|
addItem(Task0212)
|
||||||
|
addItem(Task0213)
|
||||||
|
addItem(Task0214)
|
||||||
|
addItem(Task0215)
|
||||||
|
addItem(Task0216)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addItem(item: ItemObject) {
|
||||||
|
val category = item.CATEGORY
|
||||||
|
if (!CATEGORIES.contains(category)) {
|
||||||
|
CATEGORIES.add(category)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CATEGORIES_MAP.containsKey(category))
|
||||||
|
CATEGORIES_MAP[category] = HashMap()
|
||||||
|
CATEGORIES_MAP[category]!![item.ID] = item
|
||||||
|
|
||||||
|
if (!CATEGORIES_LIST.containsKey(category))
|
||||||
|
CATEGORIES_LIST[category] = ArrayList()
|
||||||
|
CATEGORIES_LIST[category]!!.add(item)
|
||||||
|
|
||||||
|
ITEMS.add(item)
|
||||||
|
|
||||||
|
ITEM_MAP[item.ID] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
|
abstract class ItemObject {
|
||||||
|
abstract val ID: String
|
||||||
|
abstract val NAME: Int
|
||||||
|
abstract val DESCRIPTION: Int
|
||||||
|
abstract val CATEGORY: Categories
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
|
||||||
|
|
||||||
|
fun set(context: Context, key: String, value: Int) {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val editor = settings.edit()
|
||||||
|
editor.putInt(key, value)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(context: Context, key: String, value: String) {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val editor = settings.edit()
|
||||||
|
editor.putString(key, value)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(context: Context, key: String, value: Boolean) {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val editor = settings.edit()
|
||||||
|
editor.putBoolean(key, value)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(context: Context, key: String, value: Float) {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val editor = settings.edit()
|
||||||
|
editor.putFloat(key, value)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun getInt(context: Context, key: String): Int? {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return if (settings.contains(key)) settings.getInt(key, -1) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getString(context: Context, key: String): String? {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return if (settings.contains(key)) settings.getString(key, null) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBoolean(context: Context, key: String): Boolean? {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return if (settings.contains(key)) settings.getBoolean(key, false) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFloat(context: Context, key: String): Float? {
|
||||||
|
val settings = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return if (settings.contains(key)) settings.getFloat(key, -1f) else null
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.XmlRes
|
||||||
|
|
||||||
|
class Question(private val mQuestion: String, private val mAnswer: String, @XmlRes private val mKeyboard: Int, private val mMultipleInput: Boolean, private val translateValue: Function1<String, String>? = null) {
|
||||||
|
private var mGivenAnswer: String? = null
|
||||||
|
|
||||||
|
fun getQuestion(): String {
|
||||||
|
return mQuestion
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMultipleInput(): Boolean {
|
||||||
|
return mMultipleInput
|
||||||
|
}
|
||||||
|
|
||||||
|
fun translate(value: String): String {
|
||||||
|
return this.translateValue?.let{ it(value) } ?: value
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlRes
|
||||||
|
fun getKeyboard(): Int {
|
||||||
|
return mKeyboard
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAnswer(answer: String): Pair<Boolean, String> {
|
||||||
|
mGivenAnswer = answer
|
||||||
|
return Pair(mAnswer == mGivenAnswer, mAnswer)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
|
abstract class TaskObject: ItemObject() {
|
||||||
|
abstract val COUNT: Int
|
||||||
|
abstract val SILVER_TIME: Int
|
||||||
|
abstract val GOLD_TIME: Int
|
||||||
|
|
||||||
|
private var paused: Boolean = false
|
||||||
|
private var startTime: Long = 0
|
||||||
|
private var elapsedTime: Long = 0
|
||||||
|
private var questionCount: Int = 0
|
||||||
|
private var questionCorrect: Int = 0
|
||||||
|
private var question: Question? = null
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract fun generateQuestion(context: Context): Question
|
||||||
|
|
||||||
|
fun start(context: Context): Question? {
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
elapsedTime = 0
|
||||||
|
questionCount = 0
|
||||||
|
questionCorrect = 0
|
||||||
|
paused = false
|
||||||
|
return nextQuestion(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCurrect(): Question? = question
|
||||||
|
|
||||||
|
fun answer(answer: String, context: Context): Triple<Boolean, String, Question?> {
|
||||||
|
return question?.let {
|
||||||
|
val (valid, correct) = question!!.setAnswer(answer)
|
||||||
|
if (valid)
|
||||||
|
questionCorrect++
|
||||||
|
return Triple(valid, correct, nextQuestion(context))
|
||||||
|
} ?: Triple(true, "", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pause() {
|
||||||
|
elapsedTime += System.currentTimeMillis() - startTime
|
||||||
|
paused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resume() {
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
paused = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLiveTime(): Long {
|
||||||
|
return if (paused) {
|
||||||
|
elapsedTime
|
||||||
|
} else {
|
||||||
|
elapsedTime + System.currentTimeMillis() - startTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCountCurrent(): Int {
|
||||||
|
return questionCount
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCountCorrect(): Int {
|
||||||
|
return questionCorrect
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCountTotal(): Int {
|
||||||
|
return questionCount + COUNT - questionCorrect
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getScore(context: Context): Int {
|
||||||
|
return getInt(context, "TaskObject.$ID.score") ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setScore(context: Context, score: Int) {
|
||||||
|
set(context, "TaskObject.$ID.score", score)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextQuestion(context: Context): Question? {
|
||||||
|
questionCount++
|
||||||
|
elapsedTime += System.currentTimeMillis() - startTime
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
question = if (questionCorrect >= COUNT)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
generateQuestion(context)
|
||||||
|
return question
|
||||||
|
}
|
||||||
|
}
|
||||||
395
app/src/main/java/de/sebse/mentalarithmetic/types/TaskObjects.kt
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
object Task0101: TaskObject() {
|
||||||
|
override val ID: String = "Task-01-01"
|
||||||
|
override val NAME: Int = R.string.task_01_01_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_01_01_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 15 * 1000
|
||||||
|
override val GOLD_TIME: Int = 10 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val num: Int = (0..99).random()
|
||||||
|
return Question(num.toString(), (num % 2).toString(), R.xml.keyboard_odd, false) { value -> when (value) {
|
||||||
|
"0" -> context.getString(R.string.even)
|
||||||
|
"1" -> context.getString(R.string.odd)
|
||||||
|
else -> value
|
||||||
|
}.toUpperCase(Locale.getDefault()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0102: TaskObject() {
|
||||||
|
override val ID: String = "Task-01-02"
|
||||||
|
override val NAME: Int = R.string.task_01_02_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_01_02_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 25 * 1000
|
||||||
|
override val GOLD_TIME: Int = 15 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val sum: Int = (2..9).random()
|
||||||
|
val num1: Int = (1 until sum).random()
|
||||||
|
val num2 = sum - num1
|
||||||
|
return Question("$num1 + $num2", sum.toString(), R.xml.keyboard_decimal, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0103: TaskObject() {
|
||||||
|
override val ID: String = "Task-01-03"
|
||||||
|
override val NAME: Int = R.string.task_01_03_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_01_03_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val num1: Int = (1..9).random()
|
||||||
|
val num2: Int = (1..9).random()
|
||||||
|
val sum = num1 + num2
|
||||||
|
return Question("$num1 + $num2", sum.toString(), R.xml.keyboard_decimal_multi, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0104: TaskObject() {
|
||||||
|
override val ID: String = "Task-01-04"
|
||||||
|
override val NAME: Int = R.string.task_01_04_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_01_04_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val num1: Int = (1..9).random() + 10 * (1..3).random()
|
||||||
|
val num2: Int = (1..9).random() + 10 * (1..3).random()
|
||||||
|
val sum = num1 + num2
|
||||||
|
return Question("$num1 + $num2", sum.toString(), R.xml.keyboard_decimal_multi, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0105: TaskObject() {
|
||||||
|
override val ID: String = "Task-01-05"
|
||||||
|
override val NAME: Int = R.string.task_01_05_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_01_05_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val num1: Int = (10..99).random()
|
||||||
|
val num2: Int = (10..99).random()
|
||||||
|
val sum = num1 + num2
|
||||||
|
return Question("$num1 + $num2", sum.toString(), R.xml.keyboard_decimal_multi, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0201: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-01"
|
||||||
|
override val NAME: Int = R.string.task_02_01_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_01_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val res: Int = (0..6).random()
|
||||||
|
val question = when (res) {
|
||||||
|
0 -> context.getString(R.string.sunday)
|
||||||
|
1 -> context.getString(R.string.monday)
|
||||||
|
2 -> context.getString(R.string.tuesday)
|
||||||
|
3 -> context.getString(R.string.wednesday)
|
||||||
|
4 -> context.getString(R.string.thursday)
|
||||||
|
5 -> context.getString(R.string.friday)
|
||||||
|
6 -> context.getString(R.string.saturday)
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0202: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-02"
|
||||||
|
override val NAME: Int = R.string.task_02_02_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_02_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (0..2).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0203: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-03"
|
||||||
|
override val NAME: Int = R.string.task_02_03_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_03_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (3..5).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0204: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-04"
|
||||||
|
override val NAME: Int = R.string.task_02_04_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_04_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (0..5).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0205: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-05"
|
||||||
|
override val NAME: Int = R.string.task_02_05_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_05_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (6..8).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0206: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-06"
|
||||||
|
override val NAME: Int = R.string.task_02_06_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_06_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (9..11).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0207: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-07"
|
||||||
|
override val NAME: Int = R.string.task_02_07_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_07_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (6..11).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0208: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-08"
|
||||||
|
override val NAME: Int = R.string.task_02_08_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_08_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val month: Int = (0..11).random()
|
||||||
|
val (res, question) = getMonthDetails(month, context)
|
||||||
|
return Question(question, res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0209: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-09"
|
||||||
|
override val NAME: Int = R.string.task_02_09_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_09_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val day: Int = (0..31).random()
|
||||||
|
val res = day % 7
|
||||||
|
return Question("$day mod 7", res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0210: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-10"
|
||||||
|
override val NAME: Int = R.string.task_02_10_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_10_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val res = year / 4
|
||||||
|
return Question("$year div 4", res.toString(), R.xml.keyboard_decimal_multi, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0211: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-11"
|
||||||
|
override val NAME: Int = R.string.task_02_11_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_11_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 15
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val res = year + (year / 4)
|
||||||
|
return Question("$year + ($year div 4)", res.toString(), R.xml.keyboard_decimal_multi, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0212: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-12"
|
||||||
|
override val NAME: Int = R.string.task_02_12_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_12_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val year2 = year + (year / 4)
|
||||||
|
val res = year2 % 7
|
||||||
|
return Question("$year2 % 7", res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0213: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-13"
|
||||||
|
override val NAME: Int = R.string.task_02_13_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_13_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 10
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val year2 = year + (year / 4)
|
||||||
|
val res = year2 % 7
|
||||||
|
return Question("($year + ($year div 4)) % 7", res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0214: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-14"
|
||||||
|
override val NAME: Int = R.string.task_02_14_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_14_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 10
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val century: Int = (16..22).random()
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val year2 = year + (year / 4)
|
||||||
|
val res = year2 % 7
|
||||||
|
return Question("Year code of $century$year", res.toString(), R.xml.keyboard_dec7, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0215: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-15"
|
||||||
|
override val NAME: Int = R.string.task_02_15_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_15_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val century: Int = (16..22).random()
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val res = 2 * ((3 - century) % 4)
|
||||||
|
return Question("Century code of $century$year", res.toString(), R.xml.keyboard_decimal, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Task0216: TaskObject() {
|
||||||
|
override val ID: String = "Task-02-16"
|
||||||
|
override val NAME: Int = R.string.task_02_16_name
|
||||||
|
override val DESCRIPTION: Int = R.string.task_02_16_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val COUNT: Int = 20
|
||||||
|
override val SILVER_TIME: Int = 60 * 1000
|
||||||
|
override val GOLD_TIME: Int = 25 * 1000
|
||||||
|
|
||||||
|
override fun generateQuestion(context: Context): Question {
|
||||||
|
val century: Int = (16..22).random()
|
||||||
|
val year: Int = (0..99).random()
|
||||||
|
val res = if (year % 4 == 0 && (century % 4 == 0 || year != 0)) 1 else 0
|
||||||
|
return Question("Is $century${if (year < 10) "0" else ""}$year a leap yeaar?", res.toString(), R.xml.keyboard_yes_no, false) { value -> when (value) {
|
||||||
|
"0" -> context.getString(R.string.no)
|
||||||
|
"1" -> context.getString(R.string.yes)
|
||||||
|
else -> value
|
||||||
|
}.toUpperCase(Locale.getDefault()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun getMonthDetails(
|
||||||
|
month: Int,
|
||||||
|
context: Context
|
||||||
|
): Pair<Int, String> {
|
||||||
|
return when (month) {
|
||||||
|
0 -> Pair(0, context.getString(R.string.january))
|
||||||
|
1 -> Pair(3, context.getString(R.string.february))
|
||||||
|
2 -> Pair(3, context.getString(R.string.march))
|
||||||
|
3 -> Pair(6, context.getString(R.string.april))
|
||||||
|
4 -> Pair(1, context.getString(R.string.may))
|
||||||
|
5 -> Pair(4, context.getString(R.string.june))
|
||||||
|
6 -> Pair(6, context.getString(R.string.july))
|
||||||
|
7 -> Pair(2, context.getString(R.string.august))
|
||||||
|
8 -> Pair(5, context.getString(R.string.september))
|
||||||
|
9 -> Pair(0, context.getString(R.string.october))
|
||||||
|
10 -> Pair(3, context.getString(R.string.november))
|
||||||
|
11 -> Pair(5, context.getString(R.string.december))
|
||||||
|
else -> Pair(0, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
|
abstract class TipObject: ItemObject() {
|
||||||
|
abstract val HTML: Int
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package de.sebse.mentalarithmetic.types
|
||||||
|
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
|
||||||
|
object Tip0101: TipObject() {
|
||||||
|
override val ID: String = "Tip-01-01"
|
||||||
|
override val NAME: Int = R.string.tip_01_01_name
|
||||||
|
override val DESCRIPTION: Int = R.string.tip_01_01_desc
|
||||||
|
override val CATEGORY: Categories = Categories.BASIC
|
||||||
|
override val HTML: Int = R.string.tip_01_01_html
|
||||||
|
}
|
||||||
|
|
||||||
|
object Tip0201: TipObject() {
|
||||||
|
override val ID: String = "Tip-02-01"
|
||||||
|
override val NAME: Int = R.string.tip_02_01_name
|
||||||
|
override val DESCRIPTION: Int = R.string.tip_02_01_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val HTML: Int = R.string.tip_02_01_html
|
||||||
|
}
|
||||||
|
|
||||||
|
object Tip0202: TipObject() {
|
||||||
|
override val ID: String = "Tip-03-02"
|
||||||
|
override val NAME: Int = R.string.tip_02_02_name
|
||||||
|
override val DESCRIPTION: Int = R.string.tip_02_02_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val HTML: Int = R.string.tip_02_02_html
|
||||||
|
}
|
||||||
|
|
||||||
|
object Tip0203: TipObject() {
|
||||||
|
override val ID: String = "Tip-03-03"
|
||||||
|
override val NAME: Int = R.string.tip_02_03_name
|
||||||
|
override val DESCRIPTION: Int = R.string.tip_02_03_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val HTML: Int = R.string.tip_02_03_html
|
||||||
|
}
|
||||||
|
|
||||||
|
object Tip0204: TipObject() {
|
||||||
|
override val ID: String = "Tip-03-04"
|
||||||
|
override val NAME: Int = R.string.tip_02_04_name
|
||||||
|
override val DESCRIPTION: Int = R.string.tip_02_04_desc
|
||||||
|
override val CATEGORY: Categories = Categories.TIME
|
||||||
|
override val HTML: Int = R.string.tip_02_04_html
|
||||||
|
}
|
||||||
115
app/src/main/java/de/sebse/mentalarithmetic/utils/BoardView.kt
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package de.sebse.mentalarithmetic.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.children
|
||||||
|
import androidx.gridlayout.widget.GridLayout
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import de.sebse.mentalarithmetic.R
|
||||||
|
|
||||||
|
|
||||||
|
class BoardView(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet
|
||||||
|
) : GridLayout(context, attrs) {
|
||||||
|
|
||||||
|
private var locked: Boolean = false
|
||||||
|
private var callbackSubmit: ((List<Int>) -> Unit)? = null
|
||||||
|
private var callback: ((Int) -> Unit)? = null
|
||||||
|
|
||||||
|
var text = ArrayList<Keyboard.Key>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.setBackgroundColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
|
||||||
|
this.rowCount = 9
|
||||||
|
this.columnCount = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setKeyboard(board: Keyboard) {
|
||||||
|
this.rowCount = board.entries.size
|
||||||
|
this.columnCount = board.maxWidth
|
||||||
|
|
||||||
|
this.removeAllViews()
|
||||||
|
|
||||||
|
board.entries.forEachIndexed { index, row ->
|
||||||
|
var colIdx = 0
|
||||||
|
row.items.forEach { elem ->
|
||||||
|
if (elem is Keyboard.Key) {
|
||||||
|
this.addView(MaterialButton(context).apply {
|
||||||
|
text = elem.label
|
||||||
|
if (elem.icon != null) {
|
||||||
|
icon = ContextCompat.getDrawable(context, elem.icon)
|
||||||
|
iconGravity = MaterialButton.ICON_GRAVITY_TEXT_START
|
||||||
|
}
|
||||||
|
layoutParams = LayoutParams().apply {
|
||||||
|
height = LayoutParams.WRAP_CONTENT
|
||||||
|
width = 0
|
||||||
|
columnSpec = spec(colIdx, elem.width, 1f)
|
||||||
|
rowSpec = spec(index, 1, 1f)
|
||||||
|
}
|
||||||
|
setOnClickListener { onClick(elem) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
colIdx += elem.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onClick(key: Keyboard.Key) {
|
||||||
|
if (this.locked)
|
||||||
|
return
|
||||||
|
when (key.code) {
|
||||||
|
-1 -> {
|
||||||
|
if (text.size > 0) text.removeAt(text.size-1)
|
||||||
|
}
|
||||||
|
-2 -> {
|
||||||
|
callbackSubmit?.let{ it(text.map { it.code }) }
|
||||||
|
}
|
||||||
|
-3 -> {
|
||||||
|
text.clear()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
text.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback?.let{ it(key.code) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getText(): String {
|
||||||
|
return text.joinToString(separator = "") { it.code.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getValues(): ArrayList<Keyboard.Key> {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
text.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBtnListener(callback: Function1<Int, Unit>) {
|
||||||
|
this.callback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSubmitListener(callback: Function1<List<Int>, Unit>) {
|
||||||
|
this.callbackSubmit = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lock() {
|
||||||
|
this.locked = true
|
||||||
|
this.children.forEach {
|
||||||
|
it.isEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unlock() {
|
||||||
|
this.locked = false
|
||||||
|
this.children.forEach {
|
||||||
|
it.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package de.sebse.mentalarithmetic.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.text.Html
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
|
||||||
|
class ImageGetter(val context: Context) : Html.ImageGetter {
|
||||||
|
override fun getDrawable(source: String): Drawable? {
|
||||||
|
var id: Int
|
||||||
|
id = context.resources.getIdentifier(source, "drawable", context.packageName)
|
||||||
|
if (id == 0) { // the drawable resource wasn't found in our package, maybe it is a stock android drawable?
|
||||||
|
id = context.resources.getIdentifier(source, "drawable", "android")
|
||||||
|
}
|
||||||
|
return if (id == 0) { // prevent a crash if the resource still can't be found
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val d: Drawable? = ContextCompat.getDrawable(context, id)
|
||||||
|
d?.setBounds(0, 0, d.intrinsicWidth, d.intrinsicHeight)
|
||||||
|
d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package de.sebse.mentalarithmetic.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.XmlRes
|
||||||
|
import org.xmlpull.v1.XmlPullParser
|
||||||
|
|
||||||
|
|
||||||
|
class Keyboard(context: Context, @XmlRes res: Int) {
|
||||||
|
|
||||||
|
val entries: ArrayList<Row> = ArrayList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val parser = context.getResources().getXml(res)
|
||||||
|
var items: ArrayList<RowElement> = ArrayList()
|
||||||
|
try {
|
||||||
|
var event: Int = parser.eventType
|
||||||
|
while (event != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (event == XmlPullParser.START_TAG) {
|
||||||
|
when (parser.name) {
|
||||||
|
"Row" -> {
|
||||||
|
items = ArrayList()
|
||||||
|
}
|
||||||
|
"Key" -> {
|
||||||
|
val code = parser.getAttributeIntValue(null, "codes", -1)
|
||||||
|
val keyLabel = parser.getAttributeValue(null, "keyLabel") ?: ""
|
||||||
|
val resource = parser.getAttributeResourceValue(null, "keyIcon", -1)
|
||||||
|
val width = parser.getAttributeIntValue(null, "width", 1)
|
||||||
|
items.add(Key(code, keyLabel, if (resource == -1) null else resource, width))
|
||||||
|
}
|
||||||
|
"Gap" -> {
|
||||||
|
val width = parser.getAttributeIntValue(null, "width", 1)
|
||||||
|
items.add(Gap(width))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event == XmlPullParser.END_TAG) {
|
||||||
|
if ("Row" == parser.name) {
|
||||||
|
entries.add(Row(items))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event = parser.next()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
Log.d("Keyboard", entries.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxWidth: Int
|
||||||
|
get() {
|
||||||
|
return entries.maxBy { it.width }?.width ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Row(val items: ArrayList<RowElement>) {
|
||||||
|
val width: Int
|
||||||
|
get() {
|
||||||
|
return items.sumBy { it.width }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Key(
|
||||||
|
val code: Int,
|
||||||
|
val label: String,
|
||||||
|
@DrawableRes val icon: Int?,
|
||||||
|
override val width: Int
|
||||||
|
): RowElement
|
||||||
|
|
||||||
|
interface RowElement {
|
||||||
|
val width: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Gap(
|
||||||
|
override val width: Int
|
||||||
|
): RowElement
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package de.sebse.mentalarithmetic.utils
|
||||||
|
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.Html.TagHandler
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.style.BulletSpan
|
||||||
|
import android.text.style.LeadingMarginSpan
|
||||||
|
import android.text.style.TypefaceSpan
|
||||||
|
import android.text.style.UnderlineSpan
|
||||||
|
import android.util.Log
|
||||||
|
import org.xml.sax.XMLReader
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class TagHandler: TagHandler {
|
||||||
|
private var mListItemCount = 0
|
||||||
|
private val mListParents: Vector<String> = Vector()
|
||||||
|
override fun handleTag(
|
||||||
|
opening: Boolean,
|
||||||
|
tag: String,
|
||||||
|
output: Editable,
|
||||||
|
xmlReader: XMLReader
|
||||||
|
) {
|
||||||
|
if (tag == "ul" || tag == "ol" || tag == "dd") {
|
||||||
|
if (opening) {
|
||||||
|
mListParents.add(tag)
|
||||||
|
} else mListParents.remove(tag)
|
||||||
|
mListItemCount = 0
|
||||||
|
} else if (tag == "li" && !opening) {
|
||||||
|
handleListTag(output)
|
||||||
|
} else if (tag.equals("code", ignoreCase = true)) {
|
||||||
|
if (opening) {
|
||||||
|
output.setSpan(
|
||||||
|
TypefaceSpan("monospace"),
|
||||||
|
output.length,
|
||||||
|
output.length,
|
||||||
|
Spannable.SPAN_MARK_MARK
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Log.d("Code Tag", "Code tag encountered")
|
||||||
|
val obj = getLast(output, TypefaceSpan::class.java)
|
||||||
|
val where = output.getSpanStart(obj)
|
||||||
|
output.setSpan(TypefaceSpan("monospace"), where, output.length, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLast(text: Editable, kind: Class<*>): Any? {
|
||||||
|
val objs: Array<out Any> = text.getSpans(0, text.length, kind)
|
||||||
|
return if (objs.isEmpty()) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
for (i in objs.size downTo 1) {
|
||||||
|
if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) {
|
||||||
|
return objs[i - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleListTag(output: Editable) {
|
||||||
|
if (mListParents.lastElement().equals("ul")) {
|
||||||
|
output.append("\n")
|
||||||
|
val split = output.toString().split("\n").toTypedArray()
|
||||||
|
val lastIndex = split.size - 1
|
||||||
|
val start = output.length - split[lastIndex].length - 1
|
||||||
|
output.setSpan(BulletSpan(15 * mListParents.size), start, output.length, 0)
|
||||||
|
} else if (mListParents.lastElement().equals("ol")) {
|
||||||
|
mListItemCount++
|
||||||
|
output.append("\n")
|
||||||
|
val split = output.toString().split("\n").toTypedArray()
|
||||||
|
val lastIndex = split.size - 1
|
||||||
|
val start = output.length - split[lastIndex].length - 1
|
||||||
|
output.insert(start, "$mListItemCount. ")
|
||||||
|
output.setSpan(
|
||||||
|
LeadingMarginSpan.Standard(15 * mListParents.size),
|
||||||
|
start,
|
||||||
|
output.length,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="78.5885"
|
||||||
|
android:endY="90.9159"
|
||||||
|
android:startX="48.7653"
|
||||||
|
android:startY="61.0927"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
9
app/src/main/res/drawable/ic_backspace.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM19,15.59L17.59,17 14,13.41 10.41,17 9,15.59 12.59,12 9,8.41 10.41,7 14,10.59 17.59,7 19,8.41 15.41,12 19,15.59z"/>
|
||||||
|
</vector>
|
||||||
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#008577"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
||||||
54
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="930.9091"
|
||||||
|
android:viewportHeight="930.9091">
|
||||||
|
<group android:translateX="209.45454"
|
||||||
|
android:translateY="209.45454">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M306,83c-5.52,0 -10,4.48 -10,10s4.48,10 10,10c5.52,0 10,-4.48 10,-10S311.52,83 306,83z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M206,83c-5.52,0 -10,4.48 -10,10s4.48,10 10,10s10,-4.48 10,-10S211.52,83 206,83z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M473.123,298.882C481.706,286 486,269.927 486,256c0,-20.996 -9.327,-40.503 -25.332,-53.731C464.21,193.805 466,185.002 466,176c0,-27.855 -16.256,-53.803 -40.425,-65.92c3.667,-30.414 -16.151,-58.292 -45.52,-65.403C368.56,18.104 342.975,0 316,0c-25.11,0 -47.631,14.646 -60,36.016C243.63,14.646 221.109,0 196,0c-26.977,0 -52.562,18.104 -64.055,44.678c-29.545,7.156 -49.177,35.173 -45.52,65.402C62.257,122.196 46,148.145 46,176c0,9.002 1.79,17.805 5.332,26.269C35.327,215.498 26,235.004 26,256c0,14 4.33,30.052 12.877,42.881C30.525,310.671 26,324.644 26,339c0,18.616 7.548,36.35 20.899,49.518C40.035,430.01 73.125,472 116,472c0.31,0 0.615,-0.005 0.914,-0.014C131.129,496.508 157.515,512 186,512c29.688,0 56.216,-17.82 70,-43.494C269.784,494.18 296.312,512 326,512c28.485,0 54.871,-15.492 69.086,-40.014c0.3,0.009 0.604,0.014 0.914,0.014c37.944,0 70,-33.43 70,-73c0,-3.369 -0.296,-6.834 -0.899,-10.482C478.452,375.35 486,357.617 486,339C486,324.644 481.475,310.671 473.123,298.882zM246,151.381c-5.888,-3.415 -12.717,-5.381 -20,-5.381c-5.523,0 -10,4.477 -10,10s4.477,10 10,10c11.028,0 20,8.972 20,20v190.169C231.329,359.528 209.877,349 186,349c-5.523,0 -10,4.477 -10,10s4.477,10 10,10c33.084,0 60,26.916 60,60c0,34.149 -27.477,63 -60,63c-23.152,0 -44.465,-13.691 -54.299,-34.88c-1.813,-3.905 -5.919,-6.208 -10.2,-5.726c-0.707,0.081 -1.41,0.175 -2.113,0.271c-28.46,3.892 -60.51,-28.335 -51.834,-64.387c0.891,-3.703 -0.399,-7.589 -3.326,-10.025C52.644,367.614 46,353.671 46,339c0,-9.071 2.565,-17.948 7.338,-25.732C65.332,323.098 80.251,329 96,329c5.523,0 10,-4.477 10,-10s-4.477,-10 -10,-10c-27.139,0 -50,-24.77 -50,-53c0,-17.125 8.729,-32.879 23.352,-42.142c4.505,-2.854 5.978,-8.741 3.347,-13.38C68.254,192.639 66,184.403 66,176c0,-26.99 22.002,-53 50,-53c26.636,0 50,24.767 50,53c0,5.523 4.477,10 10,10s10,-4.477 10,-10c0,-39.57 -32.056,-73 -70,-73c-3.348,0 -6.678,0.271 -9.975,0.784C106.02,103.521 106,103.265 106,103c0,-22.317 18.117,-40 40,-40c10.682,0 20.73,4.161 28.292,11.715c3.907,3.903 10.238,3.899 14.142,-0.007c3.903,-3.908 3.9,-10.239 -0.007,-14.142c-9.123,-9.113 -20.662,-14.925 -33.167,-16.851C164.079,30.624 178.744,20 196,20c26.636,0 50,24.766 50,53V151.381zM416,329c15.75,0 30.669,-5.903 42.663,-15.729C463.435,321.054 466,329.93 466,339c0,14.671 -6.644,28.614 -18.227,38.253c-2.928,2.436 -4.217,6.323 -3.326,10.025c1.06,4.403 1.553,8.128 1.553,11.721c0,31.04 -28.075,56.126 -53.387,52.666c-0.703,-0.096 -1.407,-0.191 -2.114,-0.271c-4.287,-0.485 -8.388,1.821 -10.199,5.726C370.466,478.309 349.151,492 326,492c-32.523,0 -60,-28.851 -60,-63c0,-33.084 26.916,-60 60,-60c5.522,0 10,-4.477 10,-10s-4.478,-10 -10,-10c-23.877,0 -45.329,10.528 -60,27.169V186c0,-11.028 8.972,-20 20,-20c5.522,0 10,-4.477 10,-10s-4.478,-10 -10,-10c-7.283,0 -14.112,1.966 -20,5.381V73c0,-28.234 23.364,-53 50,-53c17.256,0 31.92,10.624 40.739,23.714c-12.504,1.926 -24.042,7.738 -33.166,16.851c-3.908,3.903 -3.912,10.234 -0.009,14.142c3.903,3.908 10.236,3.911 14.142,0.008C345.271,67.161 355.318,63 366,63c21.993,0 40,17.787 40,40c0,0.264 -0.02,0.521 -0.025,0.784C402.678,103.271 399.348,103 396,103c-37.944,0 -70,33.43 -70,73c0,5.523 4.478,10 10,10c5.522,0 10,-4.477 10,-10c0,-28.233 23.364,-53 50,-53c27.982,0 50,25.997 50,53c0,8.403 -2.254,16.639 -6.699,24.478c-2.63,4.639 -1.157,10.526 3.348,13.38C457.271,223.121 466,238.875 466,256c0,28.331 -22.941,53 -50,53c-5.522,0 -10,4.477 -10,10S410.478,329 416,329z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M223.453,214.053c-3.682,-4.116 -10.003,-4.468 -14.12,-0.786C177.265,241.952 126,219.027 126,176c0,-5.523 -4.477,-10 -10,-10s-10,4.477 -10,10c0,34.715 25.407,63.595 58.6,69.057C160.75,257.185 149.386,266 136,266c-5.523,0 -10,4.477 -10,10s4.477,10 10,10c24.357,0 44.69,-17.51 49.102,-40.602c13.907,-1.819 26.996,-7.77 37.565,-17.225C226.783,224.491 227.135,218.169 223.453,214.053z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M116,389c-5.523,0 -10,4.477 -10,10s4.477,10 10,10c26.636,0 50,24.767 50,53c0,5.523 4.477,10 10,10s10,-4.477 10,-10C186,422.43 153.944,389 116,389z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M196,309c-33.886,0 -62.98,18.585 -78.3,45.608c-2.723,4.805 -1.036,10.908 3.768,13.631c4.805,2.723 10.907,1.037 13.631,-3.768C147.034,343.415 169.68,329 196,329c5.523,0 10,-4.477 10,-10S201.523,309 196,309z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M376,266c-13.386,0 -24.75,-8.815 -28.6,-20.943C380.593,239.595 406,210.715 406,176c0,-5.523 -4.478,-10 -10,-10c-5.522,0 -10,4.477 -10,10c0,27.57 -22.43,50 -50,50c-12.316,0 -24.153,-4.522 -33.333,-12.733c-4.115,-3.682 -10.438,-3.331 -14.12,0.786c-3.683,4.116 -3.33,10.438 0.786,14.12c10.569,9.455 23.659,15.406 37.565,17.225C331.31,268.49 351.643,286 376,286c5.522,0 10,-4.477 10,-10S381.522,266 376,266z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M396,389c-37.944,0 -70,33.43 -70,73c0,5.523 4.478,10 10,10c5.522,0 10,-4.477 10,-10c0,-28.233 23.364,-53 50,-53c5.522,0 10,-4.477 10,-10S401.522,389 396,389z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M394.3,354.609C379.018,327.65 349.964,309 316,309c-5.522,0 -10,4.477 -10,10s4.478,10 10,10c26.301,0 48.964,14.411 60.899,35.471c2.727,4.811 8.834,6.489 13.631,3.769C395.335,365.517 397.022,359.414 394.3,354.609z"
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:strokeColor="#fff"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_star_border_gold.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="@color/gold"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_star_border_silver.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="@color/silver"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_star_gold.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="@color/gold"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_star_silver.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="@color/silver"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||||
|
</vector>
|
||||||
14
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fragment_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
27
app/src/main/res/layout/fragment_summary.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".fragments.SummaryFragment"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/retry"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/retry"/>
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/exit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/to_main_menu"/>
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@android:color/primary_text_light"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
117
app/src/main/res/layout/fragment_task.xml
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context=".fragments.TaskFragment">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="100sp"
|
||||||
|
android:layout_margin="10sp"
|
||||||
|
android:layout_below="@id/name"
|
||||||
|
app:cardBackgroundColor="@color/colorPrimaryDark">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/question"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:textColor="@android:color/primary_text_dark"
|
||||||
|
android:textSize="30sp"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/time"
|
||||||
|
android:layout_below="@id/card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/question_count"
|
||||||
|
android:layout_below="@id/card"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
|
android:layout_alignStart="@id/card"
|
||||||
|
android:layout_alignLeft="@id/card" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/question_correct"
|
||||||
|
android:layout_below="@id/card"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
|
android:layout_alignEnd="@id/card"
|
||||||
|
android:layout_alignRight="@id/card" />
|
||||||
|
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_below="@id/time"
|
||||||
|
android:indeterminate="false"
|
||||||
|
app:mpb_progressStyle="horizontal"
|
||||||
|
android:background="@color/gold"
|
||||||
|
app:mpb_useIntrinsicPadding="false"
|
||||||
|
app:mpb_secondaryProgressTint="@color/silver"
|
||||||
|
app:mpb_progressTint="@color/bronze"
|
||||||
|
android:secondaryProgress="80"
|
||||||
|
android:progress="60"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
|
||||||
|
android:layout_alignStart="@id/card"
|
||||||
|
android:layout_alignLeft="@id/card"
|
||||||
|
android:layout_alignEnd="@id/card"
|
||||||
|
android:layout_alignRight="@id/card" />
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/progress2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_below="@id/progress"
|
||||||
|
android:indeterminate="false"
|
||||||
|
app:mpb_progressStyle="horizontal"
|
||||||
|
android:background="@color/colorPrimaryLight"
|
||||||
|
app:mpb_useIntrinsicPadding="false"
|
||||||
|
android:secondaryProgress="100"
|
||||||
|
android:progress="0"
|
||||||
|
app:mpb_secondaryProgressTint="@color/colorPrimaryLight"
|
||||||
|
app:mpb_progressTint="@color/colorPrimary"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
|
||||||
|
android:layout_alignStart="@id/card"
|
||||||
|
android:layout_alignLeft="@id/card"
|
||||||
|
android:layout_alignEnd="@id/card"
|
||||||
|
android:layout_alignRight="@id/card" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/answer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_above="@id/keyboardview"
|
||||||
|
android:background="@color/colorPrimaryDark"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/hello_blank_fragment"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||||
|
|
||||||
|
<de.sebse.mentalarithmetic.utils.BoardView xmlns:custom="http://schemas.android.com/apk/res/de.sebse.mentalarithmetic"
|
||||||
|
android:id="@+id/keyboardview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
custom:showText="true"
|
||||||
|
custom:labelPosition="left"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
78
app/src/main/res/layout/fragment_taskitem.xml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/default_gap"
|
||||||
|
android:layout_marginBottom="0dp">
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/text_margin">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/personal_time"
|
||||||
|
android:layout_alignTop="@id/content"
|
||||||
|
android:layout_toLeftOf="@id/silver_time"
|
||||||
|
android:layout_toStartOf="@id/silver_time"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/silver_time"
|
||||||
|
android:drawableStart="@drawable/ic_star_border_silver"
|
||||||
|
android:drawableLeft="@drawable/ic_star_border_silver"
|
||||||
|
android:layout_alignTop="@id/content"
|
||||||
|
android:layout_toLeftOf="@id/gold_time"
|
||||||
|
android:layout_toStartOf="@id/gold_time"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/gold_time"
|
||||||
|
android:drawableStart="@drawable/ic_star_border_gold"
|
||||||
|
android:drawableLeft="@drawable/ic_star_border_gold"
|
||||||
|
android:layout_alignTop="@id/content"
|
||||||
|
android:layout_alignEnd="@id/progress"
|
||||||
|
android:layout_alignRight="@id/progress" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
tools:text="Test Task Name" />
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:layout_below="@id/content"
|
||||||
|
android:indeterminate="false"
|
||||||
|
app:mpb_progressStyle="horizontal"
|
||||||
|
android:background="@color/gold"
|
||||||
|
app:mpb_useIntrinsicPadding="false"
|
||||||
|
app:mpb_secondaryProgressTint="@color/silver"
|
||||||
|
app:mpb_progressTint="@color/bronze"
|
||||||
|
android:secondaryProgress="80"
|
||||||
|
android:progress="60"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal" />
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/progress2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:layout_below="@id/progress"
|
||||||
|
android:indeterminate="false"
|
||||||
|
app:mpb_progressStyle="horizontal"
|
||||||
|
android:background="@color/colorPrimaryLight"
|
||||||
|
app:mpb_useIntrinsicPadding="false"
|
||||||
|
android:secondaryProgress="100"
|
||||||
|
android:progress="0"
|
||||||
|
app:mpb_secondaryProgressTint="@color/colorPrimaryLight"
|
||||||
|
app:mpb_progressTint="@color/colorPrimary"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
13
app/src/main/res/layout/fragment_taskitem_list.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/list"
|
||||||
|
android:name="de.sebse.mentalarithmetic.fragments.TaskItemFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
app:layoutManager="LinearLayoutManager"
|
||||||
|
tools:context=".fragments.TaskItemFragment"
|
||||||
|
tools:listitem="@layout/fragment_taskitem" />
|
||||||
15
app/src/main/res/layout/fragment_taskitem_pager.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<me.relex.circleindicator.CircleIndicator3
|
||||||
|
android:id="@+id/titlestrip"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:background="@color/colorAccent"/>
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
17
app/src/main/res/layout/fragment_tip.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context=".fragments.TaskFragment">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
29
app/src/main/res/layout/fragment_tipitem.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/default_gap"
|
||||||
|
android:layout_marginBottom="0dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/text_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
tools:text="Test Task Name" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
|
tools:text="Test Task Name" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
10
app/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="BoardView">
|
||||||
|
<attr name="showText" format="boolean" />
|
||||||
|
<attr name="labelPosition" format="enum">
|
||||||
|
<enum name="left" value="0"/>
|
||||||
|
<enum name="right" value="1"/>
|
||||||
|
</attr>
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
||||||
10
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#008577</color>
|
||||||
|
<color name="colorPrimaryDark">#00574B</color>
|
||||||
|
<color name="colorPrimaryLight">#5CB1A8</color>
|
||||||
|
<color name="colorAccent">#D81B60</color>
|
||||||
|
<color name="gold">#D4AF37</color>
|
||||||
|
<color name="silver">#ACACAC</color>
|
||||||
|
<color name="bronze">#88540B</color>
|
||||||
|
</resources>
|
||||||
4
app/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="text_margin">16dp</dimen>
|
||||||
|
</resources>
|
||||||
4
app/src/main/res/values/ic_launcher_background.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#000064</color>
|
||||||
|
</resources>
|
||||||
34
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Mental Arithmetic</string>
|
||||||
|
|
||||||
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
|
<string name="even">even</string>
|
||||||
|
<string name="odd">odd</string>
|
||||||
|
<string name="retry">Retry</string>
|
||||||
|
<string name="to_main_menu">To Main Menu</string>
|
||||||
|
<string name="category_basic">Basic</string>
|
||||||
|
<string name="sunday">Sunday</string>
|
||||||
|
<string name="monday">Monday</string>
|
||||||
|
<string name="tuesday">Tuesday</string>
|
||||||
|
<string name="wednesday">Wednesday</string>
|
||||||
|
<string name="thursday">Thursday</string>
|
||||||
|
<string name="friday">Friday</string>
|
||||||
|
<string name="saturday">Saturday</string>
|
||||||
|
<string name="january">January</string>
|
||||||
|
<string name="february">February</string>
|
||||||
|
<string name="march">March</string>
|
||||||
|
<string name="april">April</string>
|
||||||
|
<string name="may">May</string>
|
||||||
|
<string name="june">June</string>
|
||||||
|
<string name="july">July</string>
|
||||||
|
<string name="august">August</string>
|
||||||
|
<string name="september">September</string>
|
||||||
|
<string name="october">October</string>
|
||||||
|
<string name="november">November</string>
|
||||||
|
<string name="december">December</string>
|
||||||
|
<string name="no">No</string>
|
||||||
|
<string name="yes">Yes</string>
|
||||||
|
<string name="question_count">Question Count: %1$d</string>
|
||||||
|
<string name="question_currect">%1$d / %2$d</string>
|
||||||
|
<string name="time">%1$d.%2$03d</string>
|
||||||
|
</resources>
|
||||||
46
app/src/main/res/values/strings_tasks.xml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="task_01_01_name">Even-Odd</string>
|
||||||
|
<string name="task_01_01_desc">Let\'s first train our reaction time!</string>
|
||||||
|
<string name="task_01_02_name">Tiny Addition 1</string>
|
||||||
|
<string name="task_01_02_desc">Train addition pairs</string>
|
||||||
|
<string name="task_01_03_name">Tiny Addition 2</string>
|
||||||
|
<string name="task_01_03_desc">Train addition pairs with carry over</string>
|
||||||
|
<string name="task_01_04_name">Larger numbers</string>
|
||||||
|
<string name="task_01_04_desc">Let\'s get large and add bigger (but easy) numbers!</string>
|
||||||
|
<string name="task_01_05_name">Addition</string>
|
||||||
|
<string name="task_01_05_desc">Add 2-digit numbers</string>
|
||||||
|
|
||||||
|
<string name="task_02_01_name">Week day codes</string>
|
||||||
|
<string name="task_02_01_desc">Each week day is assigned to a specific code</string>
|
||||||
|
<string name="task_02_02_name">Month codes: Jan - Mar</string>
|
||||||
|
<string name="task_02_02_desc">Learn the first 3 month codes!</string>
|
||||||
|
<string name="task_02_03_name">Month codes: Apr - Jun</string>
|
||||||
|
<string name="task_02_03_desc">Learn the next 3 month codes!</string>
|
||||||
|
<string name="task_02_04_name">Month codes: Jan - Jun</string>
|
||||||
|
<string name="task_02_04_desc">Show what you have learned so far!</string>
|
||||||
|
<string name="task_02_05_name">Month codes: Jul - Sep</string>
|
||||||
|
<string name="task_02_05_desc">Learn the month codes 7 to 9! Nearly!</string>
|
||||||
|
<string name="task_02_06_name">Month codes: Oct - Dec</string>
|
||||||
|
<string name="task_02_06_desc">Learn the last 3 month codes!</string>
|
||||||
|
<string name="task_02_07_name">Month codes: Jul - Dec</string>
|
||||||
|
<string name="task_02_07_desc">Are you ready for the ultimate test?</string>
|
||||||
|
<string name="task_02_08_name">Month codes</string>
|
||||||
|
<string name="task_02_08_desc">Now combine all your knowledge!</string>
|
||||||
|
<string name="task_02_09_name">Day code</string>
|
||||||
|
<string name="task_02_09_desc">What is the code of the day?</string>
|
||||||
|
<string name="task_02_10_name">Year code 1</string>
|
||||||
|
<string name="task_02_10_desc">Start simple with the first step only</string>
|
||||||
|
<string name="task_02_11_name">Year code 2</string>
|
||||||
|
<string name="task_02_11_desc">Getting more complicated</string>
|
||||||
|
<string name="task_02_12_name">Year code 3</string>
|
||||||
|
<string name="task_02_12_desc">And even more!</string>
|
||||||
|
<string name="task_02_13_name">Year code 4</string>
|
||||||
|
<string name="task_02_13_desc">And now the complete calculation!</string>
|
||||||
|
<string name="task_02_14_name">Year code 5</string>
|
||||||
|
<string name="task_02_14_desc">What is the correct year code for the last 2 digits</string>
|
||||||
|
<string name="task_02_15_name">Century code</string>
|
||||||
|
<string name="task_02_15_desc">Answer with the correct century code 0, 2, 4 or 6</string>
|
||||||
|
<string name="task_02_16_name">Leap Year</string>
|
||||||
|
<string name="task_02_16_desc">Check if the year is a leap year</string>
|
||||||
|
</resources>
|
||||||
60
app/src/main/res/values/strings_tips.xml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="tip_01_01_name">Welcome!</string>
|
||||||
|
<string name="tip_01_01_desc">Introduction</string>
|
||||||
|
<string name="tip_01_01_html"><![CDATA[ <h1>Introduction</h1>This is <b>pretty</b> <img src="ic_star_gold" />cool stuff! ]]></string>
|
||||||
|
<string name="tip_02_01_name">Week Day Calculation</string>
|
||||||
|
<string name="tip_02_01_desc">Introduction</string>
|
||||||
|
<string name="tip_02_01_html"><![CDATA[ <h1>Week Day Calculation</h1> Week days for each dayx can be calculated. We calculate a "day code", a "month code" and a "year code".<br/><br/> ]]></string>
|
||||||
|
<string name="tip_02_02_name">Month Codes</string>
|
||||||
|
<string name="tip_02_02_desc">A list of each month code</string>
|
||||||
|
<string name="tip_02_02_html"><![CDATA[ <h1>Month Codes</h1> Month codes are the only number you really have to learn. Here is a list with every code:<br/><ul>
|
||||||
|
<li>January: <b>0</b></li>
|
||||||
|
<li>February: <b>3</b></li>
|
||||||
|
<li>March: <b>3</b></li>
|
||||||
|
<li>April: <b>6</b></li>
|
||||||
|
<li>May: <b>1</b></li>
|
||||||
|
<li>June: <b>4</b></li>
|
||||||
|
<li>July: <b>6</b></li>
|
||||||
|
<li>August: <b>2</b></li>
|
||||||
|
<li>September: <b>5</b></li>
|
||||||
|
<li>October: <b>0</b></li>
|
||||||
|
<li>November: <b>3</b></li>
|
||||||
|
<li>December: <b>5</b></li>
|
||||||
|
</ul>
|
||||||
|
]]></string>
|
||||||
|
<string name="tip_02_03_name">Day Codes</string>
|
||||||
|
<string name="tip_02_03_desc">How to calculate the date codes</string>
|
||||||
|
<string name="tip_02_03_html"><![CDATA[ <h1>Day Codes</h1>
|
||||||
|
This part is relatively simple. The day code is the day of the month modulo 7. "Modulo" is the remainder when dividing by 7, as explained in the following examples.<br/><ul>
|
||||||
|
<li>0 mod 7 = 0</li>
|
||||||
|
<li>5 mod 7 = 5</li>
|
||||||
|
<li>7 mod 7 = 0</li>
|
||||||
|
<li>8 mod 7 = 1</li>
|
||||||
|
<li>14 mod 7 = 0</li>
|
||||||
|
<li>18 mod 7 = 4</li>
|
||||||
|
</ul>
|
||||||
|
]]></string>
|
||||||
|
<string name="tip_02_04_name">Year Codes</string>
|
||||||
|
<string name="tip_02_04_desc">How to calculate the year codes</string>
|
||||||
|
<string name="tip_02_04_html"><![CDATA[ <h1>Year Codes</h1>
|
||||||
|
Now it gets a bit more complicated, but don\'t worry: We break it down into small pieces and learn step by step.
|
||||||
|
|
||||||
|
<h2> division into century and year</h2>
|
||||||
|
Let\'s take the year 2013 as an example: In the following we will name the front two digits, "20", the century and the back two digits, "13", the year.
|
||||||
|
|
||||||
|
<h2>The year code</h2>
|
||||||
|
|
||||||
|
TL;DR: the formula is: (YY + (YY div 4)) mod 7
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li> dividing the year by 4 and ignoring the rest: 13 div 4 = (<b>3</b>*4 + 1) div 4 = 3</li>
|
||||||
|
<li>Totalize the last result with the year: 13 + <b>3</b> = 16</li>
|
||||||
|
<li> Divide the result by 7 and select the rest: 16 mod 7 = (2*7 + <b>2</b>) mod 7 = 2</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
The year code for 13 is 2.
|
||||||
|
|
||||||
|
Translated with www.DeepL.com/Translator (free version)
|
||||||
|
]]></string>
|
||||||
|
</resources>
|
||||||
15
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ShapeAppearance.MaterialComponents.SmallComponent">
|
||||||
|
<item name="cornerSize">10dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
18
app/src/main/res/xml/keyboard_dec7.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="4" keyLabel="4"/>
|
||||||
|
<Key codes="5" keyLabel="5"/>
|
||||||
|
<Key codes="6" keyLabel="6"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="1" keyLabel="1"/>
|
||||||
|
<Key codes="2" keyLabel="2"/>
|
||||||
|
<Key codes="3" keyLabel="3"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Gap/>
|
||||||
|
<Key codes="0" keyLabel="0"/>
|
||||||
|
<Gap/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
23
app/src/main/res/xml/keyboard_dec7_multi.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="7" keyLabel="7"/>
|
||||||
|
<Key codes="8" keyLabel="8"/>
|
||||||
|
<Key codes="9" keyLabel="9"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="4" keyLabel="4"/>
|
||||||
|
<Key codes="5" keyLabel="5"/>
|
||||||
|
<Key codes="6" keyLabel="6"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="1" keyLabel="1"/>
|
||||||
|
<Key codes="2" keyLabel="2"/>
|
||||||
|
<Key codes="3" keyLabel="3"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="-1" keyIcon="@drawable/ic_backspace"/>
|
||||||
|
<Key codes="0" keyLabel="0"/>
|
||||||
|
<Key codes="-2" keyLabel="ENTER"/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
23
app/src/main/res/xml/keyboard_decimal.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="7" keyLabel="7"/>
|
||||||
|
<Key codes="8" keyLabel="8"/>
|
||||||
|
<Key codes="9" keyLabel="9"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="4" keyLabel="4"/>
|
||||||
|
<Key codes="5" keyLabel="5"/>
|
||||||
|
<Key codes="6" keyLabel="6"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="1" keyLabel="1"/>
|
||||||
|
<Key codes="2" keyLabel="2"/>
|
||||||
|
<Key codes="3" keyLabel="3"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Gap/>
|
||||||
|
<Key codes="0" keyLabel="0"/>
|
||||||
|
<Gap/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
23
app/src/main/res/xml/keyboard_decimal_multi.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="7" keyLabel="7"/>
|
||||||
|
<Key codes="8" keyLabel="8"/>
|
||||||
|
<Key codes="9" keyLabel="9"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="4" keyLabel="4"/>
|
||||||
|
<Key codes="5" keyLabel="5"/>
|
||||||
|
<Key codes="6" keyLabel="6"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="1" keyLabel="1"/>
|
||||||
|
<Key codes="2" keyLabel="2"/>
|
||||||
|
<Key codes="3" keyLabel="3"/>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Key codes="-1" keyIcon="@drawable/ic_backspace"/>
|
||||||
|
<Key codes="0" keyLabel="0"/>
|
||||||
|
<Key codes="-2" keyLabel="ENTER"/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
7
app/src/main/res/xml/keyboard_odd.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="0" keyLabel="Even"/>
|
||||||
|
<Key codes="1" keyLabel="Odd"/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
7
app/src/main/res/xml/keyboard_yes_no.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Board>
|
||||||
|
<Row>
|
||||||
|
<Key codes="0" keyLabel="No"/>
|
||||||
|
<Key codes="1" keyLabel="Yes"/>
|
||||||
|
</Row>
|
||||||
|
</Board>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package de.sebse.mentalarithmetic
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
fun addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
build.gradle
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.3.50'
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
BIN
data/brain.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
119
data/brain.svg
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M306,83c-5.52,0-10,4.48-10,10s4.48,10,10,10c5.52,0,10-4.48,10-10S311.52,83,306,83z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M206,83c-5.52,0-10,4.48-10,10s4.48,10,10,10s10-4.48,10-10S211.52,83,206,83z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M473.123,298.882C481.706,286,486,269.927,486,256c0-20.996-9.327-40.503-25.332-53.731
|
||||||
|
C464.21,193.805,466,185.002,466,176c0-27.855-16.256-53.803-40.425-65.92c3.667-30.414-16.151-58.292-45.52-65.403
|
||||||
|
C368.56,18.104,342.975,0,316,0c-25.11,0-47.631,14.646-60,36.016C243.63,14.646,221.109,0,196,0
|
||||||
|
c-26.977,0-52.562,18.104-64.055,44.678c-29.545,7.156-49.177,35.173-45.52,65.402C62.257,122.196,46,148.145,46,176
|
||||||
|
c0,9.002,1.79,17.805,5.332,26.269C35.327,215.498,26,235.004,26,256c0,14,4.33,30.052,12.877,42.881
|
||||||
|
C30.525,310.671,26,324.644,26,339c0,18.616,7.548,36.35,20.899,49.518C40.035,430.01,73.125,472,116,472
|
||||||
|
c0.31,0,0.615-0.005,0.914-0.014C131.129,496.508,157.515,512,186,512c29.688,0,56.216-17.82,70-43.494
|
||||||
|
C269.784,494.18,296.312,512,326,512c28.485,0,54.871-15.492,69.086-40.014c0.3,0.009,0.604,0.014,0.914,0.014
|
||||||
|
c37.944,0,70-33.43,70-73c0-3.369-0.296-6.834-0.899-10.482C478.452,375.35,486,357.617,486,339
|
||||||
|
C486,324.644,481.475,310.671,473.123,298.882z M246,151.381c-5.888-3.415-12.717-5.381-20-5.381c-5.523,0-10,4.477-10,10
|
||||||
|
s4.477,10,10,10c11.028,0,20,8.972,20,20v190.169C231.329,359.528,209.877,349,186,349c-5.523,0-10,4.477-10,10s4.477,10,10,10
|
||||||
|
c33.084,0,60,26.916,60,60c0,34.149-27.477,63-60,63c-23.152,0-44.465-13.691-54.299-34.88c-1.813-3.905-5.919-6.208-10.2-5.726
|
||||||
|
c-0.707,0.081-1.41,0.175-2.113,0.271c-28.46,3.892-60.51-28.335-51.834-64.387c0.891-3.703-0.399-7.589-3.326-10.025
|
||||||
|
C52.644,367.614,46,353.671,46,339c0-9.071,2.565-17.948,7.338-25.732C65.332,323.098,80.251,329,96,329c5.523,0,10-4.477,10-10
|
||||||
|
s-4.477-10-10-10c-27.139,0-50-24.77-50-53c0-17.125,8.729-32.879,23.352-42.142c4.505-2.854,5.978-8.741,3.347-13.38
|
||||||
|
C68.254,192.639,66,184.403,66,176c0-26.99,22.002-53,50-53c26.636,0,50,24.767,50,53c0,5.523,4.477,10,10,10s10-4.477,10-10
|
||||||
|
c0-39.57-32.056-73-70-73c-3.348,0-6.678,0.271-9.975,0.784C106.02,103.521,106,103.265,106,103c0-22.317,18.117-40,40-40
|
||||||
|
c10.682,0,20.73,4.161,28.292,11.715c3.907,3.903,10.238,3.899,14.142-0.007c3.903-3.908,3.9-10.239-0.007-14.142
|
||||||
|
c-9.123-9.113-20.662-14.925-33.167-16.851C164.079,30.624,178.744,20,196,20c26.636,0,50,24.766,50,53V151.381z M416,329
|
||||||
|
c15.75,0,30.669-5.903,42.663-15.729C463.435,321.054,466,329.93,466,339c0,14.671-6.644,28.614-18.227,38.253
|
||||||
|
c-2.928,2.436-4.217,6.323-3.326,10.025c1.06,4.403,1.553,8.128,1.553,11.721c0,31.04-28.075,56.126-53.387,52.666
|
||||||
|
c-0.703-0.096-1.407-0.191-2.114-0.271c-4.287-0.485-8.388,1.821-10.199,5.726C370.466,478.309,349.151,492,326,492
|
||||||
|
c-32.523,0-60-28.851-60-63c0-33.084,26.916-60,60-60c5.522,0,10-4.477,10-10s-4.478-10-10-10c-23.877,0-45.329,10.528-60,27.169
|
||||||
|
V186c0-11.028,8.972-20,20-20c5.522,0,10-4.477,10-10s-4.478-10-10-10c-7.283,0-14.112,1.966-20,5.381V73
|
||||||
|
c0-28.234,23.364-53,50-53c17.256,0,31.92,10.624,40.739,23.714c-12.504,1.926-24.042,7.738-33.166,16.851
|
||||||
|
c-3.908,3.903-3.912,10.234-0.009,14.142c3.903,3.908,10.236,3.911,14.142,0.008C345.271,67.161,355.318,63,366,63
|
||||||
|
c21.993,0,40,17.787,40,40c0,0.264-0.02,0.521-0.025,0.784C402.678,103.271,399.348,103,396,103c-37.944,0-70,33.43-70,73
|
||||||
|
c0,5.523,4.478,10,10,10c5.522,0,10-4.477,10-10c0-28.233,23.364-53,50-53c27.982,0,50,25.997,50,53
|
||||||
|
c0,8.403-2.254,16.639-6.699,24.478c-2.63,4.639-1.157,10.526,3.348,13.38C457.271,223.121,466,238.875,466,256
|
||||||
|
c0,28.331-22.941,53-50,53c-5.522,0-10,4.477-10,10S410.478,329,416,329z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M223.453,214.053c-3.682-4.116-10.003-4.468-14.12-0.786C177.265,241.952,126,219.027,126,176c0-5.523-4.477-10-10-10
|
||||||
|
s-10,4.477-10,10c0,34.715,25.407,63.595,58.6,69.057C160.75,257.185,149.386,266,136,266c-5.523,0-10,4.477-10,10s4.477,10,10,10
|
||||||
|
c24.357,0,44.69-17.51,49.102-40.602c13.907-1.819,26.996-7.77,37.565-17.225C226.783,224.491,227.135,218.169,223.453,214.053z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M116,389c-5.523,0-10,4.477-10,10s4.477,10,10,10c26.636,0,50,24.767,50,53c0,5.523,4.477,10,10,10s10-4.477,10-10
|
||||||
|
C186,422.43,153.944,389,116,389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M196,309c-33.886,0-62.98,18.585-78.3,45.608c-2.723,4.805-1.036,10.908,3.768,13.631
|
||||||
|
c4.805,2.723,10.907,1.037,13.631-3.768C147.034,343.415,169.68,329,196,329c5.523,0,10-4.477,10-10S201.523,309,196,309z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M376,266c-13.386,0-24.75-8.815-28.6-20.943C380.593,239.595,406,210.715,406,176c0-5.523-4.478-10-10-10
|
||||||
|
c-5.522,0-10,4.477-10,10c0,27.57-22.43,50-50,50c-12.316,0-24.153-4.522-33.333-12.733c-4.115-3.682-10.438-3.331-14.12,0.786
|
||||||
|
c-3.683,4.116-3.33,10.438,0.786,14.12c10.569,9.455,23.659,15.406,37.565,17.225C331.31,268.49,351.643,286,376,286
|
||||||
|
c5.522,0,10-4.477,10-10S381.522,266,376,266z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M396,389c-37.944,0-70,33.43-70,73c0,5.523,4.478,10,10,10c5.522,0,10-4.477,10-10c0-28.233,23.364-53,50-53
|
||||||
|
c5.522,0,10-4.477,10-10S401.522,389,396,389z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#fff" fill="#fff" d="M394.3,354.609C379.018,327.65,349.964,309,316,309c-5.522,0-10,4.477-10,10s4.478,10,10,10
|
||||||
|
c26.301,0,48.964,14.411,60.899,35.471c2.727,4.811,8.834,6.489,13.631,3.769C395.335,365.517,397.022,359.414,394.3,354.609z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
2
data/data.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Icon made by [author link] from www.flaticon.com
|
||||||
|
https://www.flaticon.com/free-icon/brain_883039
|
||||||
21
gradle.properties
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
|
android.enableJetifier=true
|
||||||
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
|
kotlin.code.style=official
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#Wed Dec 04 21:08:54 CET 2019
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||||
172
gradlew
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
84
gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
2
settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
include ':app'
|
||||||
|
rootProject.name='Mental Arithmetic'
|
||||||