Skip to content

Commit

Permalink
Merge pull request #76 from cesko-digital/feature/exercise
Browse files Browse the repository at this point in the history
Basic Exercise feature
  • Loading branch information
Crustus authored Oct 9, 2023
2 parents 6271a2b + aa64337 commit a693dcb
Show file tree
Hide file tree
Showing 72 changed files with 1,595 additions and 54 deletions.
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,10 @@ dependencies {
String ktor_version = project.ktor_version
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")

// Logging
implementation 'com.jakewharton.timber:timber:5.0.1'

// Lottie animations
implementation "com.airbnb.android:lottie:6.0.1"
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package cz.movapp.app

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/cz/movapp/android/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cz.movapp.android
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.media.MediaPlayer
import android.os.Build
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.FragmentActivity
Expand All @@ -15,7 +16,8 @@ import java.text.Normalizer
*/
fun playSound(
context: Context,
assetFileName: String
assetFileName: String,
playbackSpeed: Float = 1.0f
): MediaPlayer? {
val afd: AssetFileDescriptor = context.assets.openFd(assetFileName)
var player: MediaPlayer? = MediaPlayer()
Expand All @@ -28,6 +30,13 @@ fun playSound(
player = null
}
player?.prepare()
// FIXME will not work on lower Android versions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
player?.playbackParams?.apply {
speed = playbackSpeed
player?.playbackParams = this
}
}
player?.start()

return player
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/cz/movapp/android/UtilsAndroid.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.onStart
import java.util.*
import java.util.Locale

fun RecyclerView.getSavableScrollState(): Int {
return when (this.layoutManager) {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/cz/movapp/app/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Context
import android.os.StrictMode
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import timber.log.Timber

const val TAG = "MOVAPP"

Expand All @@ -23,6 +24,7 @@ class App : Application() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.enableDefaults()
Timber.plant(Timber.DebugTree())
}
instance = this
ctx = applicationContext
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/java/cz/movapp/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber

class MainActivity : AppCompatActivity() {

Expand Down Expand Up @@ -48,7 +49,12 @@ class MainActivity : AppCompatActivity() {

navController = findNavController(R.id.nav_host_fragment_activity_main)

binding.bottomNavigation.setupWithNavController(navController)
binding.bottomNavigation.apply {
setupWithNavController(navController)
setOnItemReselectedListener {
Timber.d("menuItem $it")
}
}
}


Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/cz/movapp/app/MediaPlayerForegroundService.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package cz.movapp.app

import android.app.*
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
Expand All @@ -12,7 +16,11 @@ import android.media.MediaMetadata
import android.media.MediaPlayer
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.*
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.PowerManager
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import java.io.IOException

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/cz/movapp/app/OnBoardingActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.tabs.TabLayoutMediator
import cz.movapp.app.ui.onboarding.OnBoardingFragmentAdapter
import cz.movapp.app.databinding.ActivityOnBoardingBinding
import cz.movapp.app.ui.onboarding.OnBoardingFragmentAdapter

val ONBOARDING_PASSED_RESULT_CODE = 1
val ONBOARDING_LEFT_RESULT_CODE = 2
Expand Down
66 changes: 60 additions & 6 deletions app/src/main/java/cz/movapp/app/data/DictionaryDatasource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ package cz.movapp.app.data
import android.content.Context
import cz.movapp.android.createLangAssetsString
import cz.movapp.android.stripDiacritics
import cz.movapp.app.ui.dictionary.DictionaryMetaCategoryData
import cz.movapp.app.ui.dictionary.DictionarySectionsData
import cz.movapp.app.ui.dictionary.DictionaryTranslationsData
import org.json.JSONObject
import java.io.IOException
import java.util.*
import java.util.Locale

class DictionaryDatasource {
object DictionaryDatasource {

private val sectionsCache = mutableMapOf<String,List<DictionarySectionsData>>()
private val translationsCache = mutableMapOf<String,List<DictionaryTranslationsData>>()
private val metaCategoriesCache = mutableMapOf<String,List<DictionaryMetaCategoryData>>()

private fun loadSectionsFromAssets(context: Context, langStorageString: String): List<DictionarySectionsData> {
var jsonString: String = ""
Expand Down Expand Up @@ -101,14 +103,55 @@ class DictionaryDatasource {
return translations
}

private fun loadMetaCategoriesFromAssets(context: Context, langStorageString: String): List<DictionaryMetaCategoryData> {
var jsonString = ""
val dict = mutableListOf<DictionaryMetaCategoryData>()

try {
jsonString = context.assets.open("${langStorageString}-dictionary.json").bufferedReader().use { it.readText() }
} catch (ioException: IOException) {
ioException.printStackTrace()
}

val jsonArr = JSONObject(jsonString).getJSONArray("categories")

for (i in 0 until jsonArr.length()) {
val jsonObj = jsonArr.getJSONObject(i)

if (!jsonObj.optBoolean("metaOnly", false)) {
continue
}

val id = jsonObj.getString("id")
val jsonNameObj = jsonObj.getJSONObject("name")

val metaCategories = mutableListOf<String>()
val jsonMetaCatsArr = jsonObj.getJSONArray("metacategories")
for (j in 0 until jsonMetaCatsArr.length()) {
metaCategories.add(jsonMetaCatsArr.getString(j))
}

dict.add(DictionaryMetaCategoryData(
id,
jsonNameObj.getString("main"),
jsonNameObj.getString("source"),
metaCategories)
)
}

return dict
}

fun loadSections(context: Context, langPair: LanguagePair): List<DictionarySectionsData> {
var langStorageString = createLangAssetsString(langPair)
return lazySectionsCacheLoad(context, langStorageString)
return lazySectionsCacheLoad(context, createLangAssetsString(langPair))
}

fun loadTranslations(context: Context, langPair: LanguagePair): List<DictionaryTranslationsData> {
var langStorageString = createLangAssetsString(langPair)
return lazyTranslationsCacheLoad(context, langStorageString)
return lazyTranslationsCacheLoad(context, createLangAssetsString(langPair))
}

fun loadMetaCategories(context: Context, langPair: LanguagePair): List<DictionaryMetaCategoryData> {
return lazyMetaCategoriesCacheLoad(context, createLangAssetsString(langPair))
}

private fun lazySectionsCacheLoad(context: Context, langStorageString: String): List<DictionarySectionsData> {
Expand All @@ -132,4 +175,15 @@ class DictionaryDatasource {
selected
}
}

private fun lazyMetaCategoriesCacheLoad(context: Context, langStorageString: String): List<DictionaryMetaCategoryData> {
var selected = metaCategoriesCache[langStorageString]
return if (selected == null) {
selected = loadMetaCategoriesFromAssets(context, langStorageString)
metaCategoriesCache[langStorageString] = selected
selected
} else {
selected
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/cz/movapp/app/data/Language.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package cz.movapp.app.data
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import cz.movapp.app.R
import java.util.*
import java.util.Locale

/**
* @param isReversed whether translation is reverse to data of json see cs-uk-dictionary.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import cz.movapp.android.getSavableScrollState
import cz.movapp.android.restoreSavableScrollState
import cz.movapp.app.App
import cz.movapp.app.MainViewModel
import cz.movapp.app.databinding.FragmentAlphabetBinding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package cz.movapp.app.ui.alphabet

import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import cz.movapp.app.ui.alphabet.AlphabetDirection
import cz.movapp.app.ui.alphabet.AlphabetFragment

class AlphabetFragmentAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import cz.movapp.app.MainViewModel
import cz.movapp.app.databinding.FragmentChildrenFairyTalesSelectionBinding

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ package cz.movapp.app.ui.children

import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.media.MediaPlayer
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.setPadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.google.android.material.internal.ViewUtils.dpToPx
import cz.movapp.android.playSound
import cz.movapp.app.MainViewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package cz.movapp.app.ui.children

import android.app.Application
import android.graphics.drawable.Drawable
import androidx.lifecycle.*
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import cz.movapp.app.App
import cz.movapp.app.appModule
import cz.movapp.app.data.ChildrenDatasource
Expand Down
14 changes: 13 additions & 1 deletion app/src/main/java/cz/movapp/app/ui/dictionary/DictionaryModel.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package cz.movapp.app.ui.dictionary

data class DictionarySectionsData(val id: String, val main: String, val source: String, val phrases_ids: List<String>)
data class DictionarySectionsData(
val id: String,
val main: String,
val source: String,
val phrases_ids: List<String>
)

data class DictionaryTranslationsData(
val id: String,
Expand All @@ -17,3 +22,10 @@ data class DictionaryTranslationsData(
val source_sound_url: String,
val source_sound_local: String
)

data class DictionaryMetaCategoryData(
val id: String,
val nameSource: String,
val nameMain: String,
val metaCategories: MutableList<String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import android.content.Context
import cz.movapp.android.stripDiacritics
import cz.movapp.app.FavoritesViewModel
import cz.movapp.app.data.LanguagePair
import java.util.*
import java.util.Locale

class DictionaryPhrasesSearchAllAdapter(
private val context: Context,
Expand Down
Loading

0 comments on commit a693dcb

Please sign in to comment.