diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 2b436cba..7a748e40 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -11,6 +11,9 @@
+
+
+
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 6e6eec11..79ee123c 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ae3bdb82..565fa15a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -25,4 +25,33 @@ There are handy DSL that allows write content in the typesafe way.
- All app content should be placed into `com.github.braillesystems.learnbraille.res` package.
- Use `DslTest.kt` file as DSL tutorial.
-Symbols that are not from particular alphabet and does not exist on classical american keyboard should be treated as special and added via `enum class`.
+Information correctness should be checked in compile time or in app initialization runtime as much as possible. If some additional info is need, do not hardcode it. Just make request to the new DSL feature via github issues.
+
+Adding rules, prevent lambda of capturing context that will be invalid next time fragment entered, so use `Fragment.getString` outside of lambdas.
+
+#### Adding course
+
+1. Create lessons by `lessons` delegate.
+2. Create course in `CourseBuilder` and add lessons to it.
+
+Always use `com.github.braillesystems.learnbraille.res.content` value to get materials, they are indexed here in proper way.
+
+#### Adding deck
+
+1. Add new deck tag to `DeckTags`.
+2. Map tag to deck's predicate in `DecksBuilder`.
+3. Map deck's tag to user-visible string in `deckTagToName`.
+
+#### Adding materials
+
+1. Create materials by one of delegates: `markers` or `symbols`.
+2. Add created materials to the `contens` (`materials` delegate).
+3. Add to `inputSymbolPrintRules` and `showSymbolPrintRules`, or to `inputMarkerPrintRules` and `showMarkerPrintRules`.
+
+Symbols that are not from particular alphabet and does not exist on classical american keyboard should be treated as special and be added via `enum class`.
+
+New materials can be marked as known by default in `knownMaterials` (`known` delegate).
+
+## Database
+
+Database scheme is described [here](https://github.com/braille-systems/learn-braille/blob/master/database.md).
diff --git a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabaseTest.kt b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabaseTest.kt
index f4e735ba..f67a9ab5 100644
--- a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabaseTest.kt
+++ b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabaseTest.kt
@@ -15,10 +15,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
-
-/**
- * Tests data serialization first of all.
- */
@RunWith(AndroidJUnit4::class)
class LearnBrailleDatabaseTest {
@@ -87,7 +83,7 @@ class LearnBrailleDatabaseTest {
id = 3,
data = ShowDots(
text = "Перед Вами полное шеститочие",
- dots = BrailleDots(F, F, F, F, F, F)
+ brailleDots = BrailleDots(F, F, F, F, F, F)
),
lessonId = 1, courseId = 1
),
@@ -95,7 +91,7 @@ class LearnBrailleDatabaseTest {
id = 4,
data = InputDots(
text = "Введите все шесть точек",
- dots = BrailleDots(F, F, F, F, F, F)
+ brailleDots = BrailleDots(F, F, F, F, F, F)
),
lessonId = 2, courseId = 1
),
@@ -157,30 +153,30 @@ class LearnBrailleDatabaseTest {
@Test
fun testUsers() = runBlocking {
- assertEquals("default", db.userDao.getUser(1)!!.login)
+ assertEquals("default", db.userDao.user(1)!!.login)
}
@Test
fun testMaterials() = runBlocking {
- val data = db.materialDao.getMaterial(1)!!.data
+ val data = db.materialDao.material(1)!!.data
require(data is Symbol)
assertEquals(BrailleDots(F, E, E, E, E, E), data.brailleDots)
}
@Test
fun testDecks() = runBlocking {
- assertEquals("Ru letters", db.deckDao.getDeck(1)!!.tag)
+ assertEquals("Ru letters", db.deckDao.deck(1)!!.tag)
}
@Test
fun testCourses() = runBlocking {
- assertEquals("Super course", db.courseDao.getCourse(1)!!.name)
+ assertEquals("Super course", db.courseDao.course(1)!!.name)
}
@Test
fun testSteps() = runBlocking {
for ((i, step) in steps.withIndex()) {
- val fromDb = db.stepDao.getStep(i + 1L)!!
+ val fromDb = db.stepDao.step(i + 1L)!!
assertEquals(step, fromDb)
}
}
diff --git a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepositoryTest.kt b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepositoryTest.kt
index df040714..4109b78b 100644
--- a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepositoryTest.kt
+++ b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepositoryTest.kt
@@ -55,6 +55,11 @@ class ActionsRepositoryTest {
@Test
fun getAll() = runBlocking {
- assertEquals(actions.toList(), repo.getActionsFrom(Days(100)))
+ assertEquals(actions.toList(), repo.actionsFrom(Days(100)))
+ }
+
+ @Test
+ fun getSince() = runBlocking {
+ assertEquals(listOf(actions.first()), repo.actionsFrom(Days(25)))
}
}
diff --git a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepositoryTest.kt b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepositoryTest.kt
new file mode 100644
index 00000000..a98408d0
--- /dev/null
+++ b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepositoryTest.kt
@@ -0,0 +1,239 @@
+package com.github.braillesystems.learnbraille.data.repository
+
+import androidx.room.Room
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.github.braillesystems.learnbraille.data.db.LearnBrailleDatabase
+import com.github.braillesystems.learnbraille.data.entities.*
+import com.github.braillesystems.learnbraille.data.entities.BrailleDot.E
+import com.github.braillesystems.learnbraille.data.entities.BrailleDot.F
+import com.github.braillesystems.learnbraille.res.MarkerType
+import com.github.braillesystems.learnbraille.res.SymbolType
+import com.github.braillesystems.learnbraille.utils.unreachable
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.IOException
+
+@RunWith(AndroidJUnit4::class)
+class MaterialsRepositoryTest {
+
+ private lateinit var db: LearnBrailleDatabase
+ private lateinit var repo: MaterialsRepository
+
+ private val users = listOf(
+ User(
+ login = "default",
+ name = "John Smith"
+ )
+ )
+
+ private val materials = listOf(
+ Material(
+ 1,
+ Symbol(
+ char = 'А',
+ brailleDots = BrailleDots(F, E, E, E, E, E),
+ type = SymbolType.ru
+ )
+ ),
+ Material(
+ 2,
+ MarkerSymbol(
+ type = MarkerType.GreekCapital,
+ brailleDots = BrailleDots(F, F, F, E, E, E)
+ )
+ ),
+ Material(
+ 3,
+ Symbol(
+ char = 'B',
+ brailleDots = BrailleDots(F, F, F, E, E, F),
+ type = SymbolType.digit
+ )
+ )
+ )
+
+ private val knownMaterials = listOf(
+ KnownMaterial(1, 2),
+ KnownMaterial(1, 3)
+ )
+
+ private val decks = listOf(
+ Deck(
+ id = 1,
+ tag = "Ru letters"
+ ),
+ Deck(
+ id = 2,
+ tag = "Another useless deck"
+ )
+ )
+
+ private val cards = listOf(
+ Card(
+ deckId = 1,
+ materialId = 1
+ ),
+ Card(
+ deckId = 2,
+ materialId = 1
+ ),
+ Card(
+ deckId = 1,
+ materialId = 2
+ )
+ )
+
+ private val courses = listOf(
+ Course(
+ id = 1,
+ name = "Super course",
+ description = "Oh, it's so good"
+ )
+ )
+
+ private val lessons = listOf(
+ Lesson(
+ id = 1,
+ name = "First",
+ description = "First First First",
+ courseId = 1
+ ),
+ Lesson(
+ id = 2,
+ name = "Last",
+ description = "Last Last Last",
+ courseId = 1
+ )
+ )
+
+ private val steps = listOf(
+ Step(
+ id = 1,
+ data = FirstInfo("FirstInfo"),
+ lessonId = 1, courseId = 1
+ )
+ )
+
+ private val annotations = listOf(
+ StepAnnotation(id = 1, name = "a1"),
+ StepAnnotation(id = 2, name = "a2")
+ )
+
+ private val stepAnnotations = listOf(
+ StepHasAnnotation(
+ courseId = 1,
+ lessonId = 3,
+ stepId = 2,
+ annotationId = 1
+ )
+ )
+
+ @Before
+ fun createDB() {
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ db = Room
+ .inMemoryDatabaseBuilder(context, LearnBrailleDatabase::class.java)
+ .allowMainThreadQueries()
+ .build().apply {
+ runBlocking {
+ userDao.insert(users)
+ materialDao.insert(materials)
+ knownMaterialDao.insert(knownMaterials)
+ deckDao.insert(decks)
+ cardDao.insert(cards)
+ courseDao.insert(courses)
+ lessonDao.insert(lessons)
+ stepDao.insert(steps)
+ stepAnnotationDao.insert(annotations)
+ stepHasAnnotationDao.insert(stepAnnotations)
+ }
+ }
+
+ repo = MaterialsRepositoryImpl(
+ db.deckDao, db.cardDao,
+ object : PreferenceRepository {
+ override val buzzEnabled: Boolean
+ get() = unreachable
+ override val toastsEnabled: Boolean
+ get() = unreachable
+ override val golubinaBookStepsEnabled: Boolean
+ get() = unreachable
+ override val slateStylusStepsEnabled: Boolean
+ get() = unreachable
+ override val traverseDotsInEnumerationOrder: Boolean
+ get() = unreachable
+ override val inputOnFlyCheck: Boolean
+ get() = unreachable
+ override val additionalAnnouncementsEnabled: Boolean
+ get() = unreachable
+ override val practiceUseOnlyKnownMaterials: Boolean
+ get() = true
+ override val extendedAccessibilityEnabled: Boolean
+ get() = unreachable
+ override val additionalQrCodeButtonEnabled: Boolean
+ get() = unreachable
+ override val currentUserId: DBid
+ get() = 1
+
+ override suspend fun getCurrentUser(): User = users.first()
+ }
+ )
+ }
+
+ @After
+ @Throws(IOException::class)
+ fun closeDB() {
+ db.close()
+ }
+
+ @Test
+ fun randomMaterialFromDeck() = runBlocking {
+ val material = repo.randomMaterialFromDeck(2)
+ assertTrue(material in materials.filter { Card(2, it.id) in cards })
+ }
+
+ @Test
+ fun randomKnownMaterialFromDeck() = runBlocking {
+ val material = repo.randomKnownMaterialFromDeck(1)
+ assertTrue(material in materials.filter { Card(1, it.id) in cards })
+ assertTrue(material!!.id in knownMaterials.map { it.materialId })
+ }
+
+ @Test
+ fun allMaterialsFromDeck() = runBlocking {
+ assertEquals(
+ materials.filter { Card(2, it.id) in cards },
+ repo.allMaterialsFromDeck(2)
+ )
+ }
+
+ @Test
+ fun allDecks() = runBlocking {
+ assertEquals(
+ decks,
+ repo.allDecks()
+ )
+ }
+
+ @Test
+ fun availableDecks() = runBlocking {
+ assertEquals(listOf(decks.first()), repo.availableDecks())
+ }
+
+ @Test
+ fun allDecksWithAvailability() = runBlocking {
+ assertEquals(
+ listOf(
+ DeckWithAvailability(decks[0], true),
+ DeckWithAvailability(decks[1], false)
+ ),
+ repo.allDecksWithAvailability()
+ )
+ }
+}
diff --git a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepositoryTest.kt b/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepositoryTest.kt
deleted file mode 100644
index 11cca30e..00000000
--- a/app/src/androidTest/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepositoryTest.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.github.braillesystems.learnbraille.data.repository
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class PracticeRepositoryTest {
-
- @Test
- fun practiceRepo() {
- // TODO
- }
-}
diff --git a/app/src/androidTest/java/com/github/braillesystems/learnbraille/ui/screens/DotsCheckerTest.kt b/app/src/androidTest/java/com/github/braillesystems/learnbraille/ui/screens/DotsCheckerTest.kt
deleted file mode 100644
index b6036631..00000000
--- a/app/src/androidTest/java/com/github/braillesystems/learnbraille/ui/screens/DotsCheckerTest.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.github.braillesystems.learnbraille.ui.screens
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class DotsCheckerTest {
-
- @Test
- fun dotsChecker() {
- // TODO
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 18285f0c..5a937f5c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,8 +2,6 @@
-
-
-
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/LearnBrailleApplication.kt b/app/src/main/java/com/github/braillesystems/learnbraille/LearnBrailleApplication.kt
index 92c26699..596d7fbb 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/LearnBrailleApplication.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/LearnBrailleApplication.kt
@@ -2,7 +2,7 @@ package com.github.braillesystems.learnbraille
import android.app.Application
import com.github.braillesystems.learnbraille.data.db.LearnBrailleDatabase
-import com.github.braillesystems.learnbraille.data.dsl.UsersCourse
+import com.github.braillesystems.learnbraille.data.dsl.DevelopersCourse
import com.github.braillesystems.learnbraille.data.entities.BrailleDots
import com.github.braillesystems.learnbraille.data.repository.*
import com.github.braillesystems.learnbraille.ui.screens.practice.CardViewModelFactory
@@ -45,33 +45,36 @@ class LearnBrailleApplication : Application() {
)
}
+ factory {
+ val db = get()
+ MaterialsRepositoryImpl(db.deckDao, db.cardDao, get())
+ }
+
factory {
val db = get()
PracticeRepositoryImpl(
this@LearnBrailleApplication,
- db.deckDao, db.cardDao, get()
+ db.deckDao, get(), get()
)
}
factory {
val db = get()
PracticeRepositoryImpl(
this@LearnBrailleApplication,
- db.deckDao, db.cardDao, get()
+ db.deckDao, get(), get()
)
}
factory {
- val db = get()
BrowserRepositoryImpl(
this@LearnBrailleApplication,
- get(), db.deckDao, db.cardDao
+ get(), get()
)
}
factory {
- val db = get()
BrowserRepositoryImpl(
this@LearnBrailleApplication,
- get(), db.deckDao, db.cardDao
+ get(), get()
)
}
@@ -96,7 +99,7 @@ class LearnBrailleApplication : Application() {
factory { (getEnteredDots: () -> BrailleDots) ->
CardViewModelFactory(
- get(), get(),
+ get(), get(), get(),
this@LearnBrailleApplication,
getEnteredDots
)
@@ -116,4 +119,4 @@ class LearnBrailleApplication : Application() {
lateinit var koin: Koin
private set
-val COURSE = UsersCourse(2L)
+val COURSE = DevelopersCourse
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabase.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabase.kt
index 850b7d22..e254d195 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabase.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/db/LearnBrailleDatabase.kt
@@ -73,7 +73,7 @@ abstract class LearnBrailleDatabase : RoomDatabase(), KoinComponent {
prepareDbJob = scope().launch {
Timber.i("Requesting value from database to force database callbacks and migrations")
Timber.i("Start database preparation")
- userDao.getUser(1).devnull
+ userDao.user(1).devnull
Timber.i("Finnish database preparation")
}
}
@@ -87,7 +87,7 @@ abstract class LearnBrailleDatabase : RoomDatabase(), KoinComponent {
const val name = "learn_braille_database"
/**
- * Try to run `build` before first user's request (mb in Application's `onCreate`)
+ * Try to run `buildDatabase` before first user's request (mb in Application's `onCreate`)
* to make DB likely prepared until it is really needed.
*/
fun buildDatabase(context: Context) = Room
@@ -208,4 +208,5 @@ private val MIGRATION_17_18 = object : Migration(17, 18), KoinComponent {
}
}
+// TODO migration that preserves current true user's position
// TODO materials migration
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/dsl/DataStorage.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/dsl/DataStorage.kt
index 76ccd1e7..23f71f28 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/dsl/DataStorage.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/dsl/DataStorage.kt
@@ -33,9 +33,9 @@ class data(
@DataBuilderMarker
class DataBuilder(
- private val _materials: MaterialsBuilder,
+ materials: MaterialsBuilder,
private val stepAnnotationNames: List,
- private val _knownMaterials: List,
+ knownMaterials: List,
block: DataBuilder.() -> Unit
) : DataStorage {
@@ -43,6 +43,7 @@ class DataBuilder(
override val users: List
get() = _users
+ private val _materials: MaterialsBuilder = materials
override val materials: List
get() = _materials.materials
@@ -74,6 +75,7 @@ class DataBuilder(
override val stepsHasAnnotations: List
get() = _stepsHasAnnotations
+ private val _knownMaterials: List = knownMaterials
override val knownMaterials: List by lazy {
_knownMaterials.map { it.copy(userId = 1) }
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Actions.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Actions.kt
index 54e41317..b2f0aa5c 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Actions.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Actions.kt
@@ -31,7 +31,7 @@ interface ActionDao {
suspend fun insert(vararg actions: Action)
@Query("select * from actions where date >= :date")
- suspend fun getAllActionsSince(date: Long): List
+ suspend fun allActionsSince(date: Long): List
@Query("delete from actions")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Cards.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Cards.kt
index 563ab229..e788ca27 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Cards.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Cards.kt
@@ -2,7 +2,6 @@ package com.github.braillesystems.learnbraille.data.entities
import androidx.room.*
-
@Entity(tableName = "cards", primaryKeys = ["deck_id", "material_id"])
data class Card(
@ColumnInfo(name = "deck_id")
@@ -26,7 +25,7 @@ interface CardDao {
order by RANDOM() limit 1
"""
)
- suspend fun getRandomMaterialFromDeck(deckId: DBid): Material?
+ suspend fun randomMaterialFromDeck(deckId: DBid): Material?
@Query(
"""
@@ -40,7 +39,7 @@ interface CardDao {
order by RANDOM() limit 1
"""
)
- suspend fun getRandomKnownMaterialFromDeck(userId: DBid, deckId: DBid): Material?
+ suspend fun randomKnownMaterialFromDeck(userId: DBid, deckId: DBid): Material?
@Query(
"""
@@ -51,7 +50,7 @@ interface CardDao {
order by m.id
"""
)
- suspend fun getAllMaterialsFromDeck(id: DBid): List
+ suspend fun allMaterialsFromDeck(id: DBid): List
@Query("delete from cards")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Courses.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Courses.kt
index 5880edbd..a3d54a60 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Courses.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Courses.kt
@@ -19,7 +19,7 @@ interface CourseDao {
suspend fun insert(courses: List)
@Query("select * from courses where id = :id")
- suspend fun getCourse(id: DBid): Course?
+ suspend fun course(id: DBid): Course?
@Query("delete from courses")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Decks.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Decks.kt
index 19a6551b..5cae21bc 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Decks.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Decks.kt
@@ -17,10 +17,10 @@ interface DeckDao {
suspend fun insert(decks: List)
@Query("select * from decks where id = :id")
- suspend fun getDeck(id: DBid): Deck?
+ suspend fun deck(id: DBid): Deck?
@Query("select * from decks")
- suspend fun getAllDecks(): List
+ suspend fun allDecks(): List
@Query(
"""
@@ -33,7 +33,7 @@ interface DeckDao {
order by d.id
"""
)
- suspend fun getAvailableDecks(userId: DBid): List
+ suspend fun availableDecks(userId: DBid): List
@Query("delete from decks")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Lessons.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Lessons.kt
index 7fe924d6..15fa45c2 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Lessons.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Lessons.kt
@@ -27,7 +27,7 @@ interface LessonDao {
order by id
"""
)
- suspend fun getAllCourseLessons(courseId: DBid): List
+ suspend fun allCourseLessons(courseId: DBid): List
@Query("delete from lessons")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/MaterialData.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/MaterialData.kt
index 788b11ec..a1ea408f 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/MaterialData.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/MaterialData.kt
@@ -23,17 +23,22 @@ class MaterialDataTypeConverters {
typealias SymbolType = String
+@Serializable
+sealed class OneBrailleSymbol : MaterialData() {
+ abstract val brailleDots: BrailleDots
+}
+
@Serializable
data class Symbol(
val char: Char,
- val brailleDots: BrailleDots,
+ override val brailleDots: BrailleDots,
@SerialName("symbol_type")
val type: SymbolType
-) : MaterialData()
+) : OneBrailleSymbol()
@Serializable
data class MarkerSymbol(
@SerialName("marker_type")
val type: MarkerType,
- val brailleDots: BrailleDots
-) : MaterialData()
+ override val brailleDots: BrailleDots
+) : OneBrailleSymbol()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Materials.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Materials.kt
index f3358a78..34482385 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Materials.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Materials.kt
@@ -17,10 +17,10 @@ interface MaterialDao {
suspend fun insert(materials: List)
@Query("select * from materials where id = :id")
- suspend fun getMaterial(id: DBid): Material?
+ suspend fun material(id: DBid): Material?
@Query("select * from materials order by RANDOM() limit 1")
- suspend fun getRandomMaterial(): Material?
+ suspend fun randomMaterial(): Material?
@Query("Delete from materials")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/StepData.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/StepData.kt
index fbb7e06c..6ca07ef8 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/StepData.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/StepData.kt
@@ -32,7 +32,9 @@ typealias HtmlText = String
* Represents step types with information.
*/
@Serializable
-sealed class BaseInfo : StepData()
+sealed class BaseInfo : StepData() {
+ abstract val text: HtmlText
+}
/**
* Step displays information text for the user.
@@ -40,7 +42,7 @@ sealed class BaseInfo : StepData()
@Serializable
data class Info(
@SerialName("info")
- val text: HtmlText
+ override val text: HtmlText
) : BaseInfo()
/**
@@ -49,7 +51,7 @@ data class Info(
@Serializable
data class FirstInfo(
@SerialName("info")
- val text: HtmlText
+ override val text: HtmlText
) : BaseInfo()
/**
@@ -58,12 +60,14 @@ data class FirstInfo(
@Serializable
data class LastInfo(
@SerialName("info")
- val text: HtmlText
+ override val text: HtmlText
) : BaseInfo()
@Serializable
-sealed class BaseInput : StepData()
+sealed class BaseInput : StepData() {
+ abstract val brailleDots: BrailleDots
+}
/**
* Step prompts the user to enter something.
@@ -71,7 +75,12 @@ sealed class BaseInput : StepData()
@Serializable
data class Input(
val material: Material
-) : BaseInput()
+) : BaseInput() {
+ override val brailleDots: BrailleDots
+ get() = when (material.data) {
+ is OneBrailleSymbol -> material.data.brailleDots
+ }
+}
/**
* Step prompts the user to enter dots with specific numbers.
@@ -82,12 +91,15 @@ data class Input(
@Serializable
data class InputDots(
val text: HtmlText?,
- val dots: BrailleDots
+ @SerialName("dots") // backward compatibility
+ override val brailleDots: BrailleDots
) : BaseInput()
@Serializable
-sealed class BaseShow : StepData()
+sealed class BaseShow : StepData() {
+ abstract val brailleDots: BrailleDots
+}
/**
* Step shows something.
@@ -95,7 +107,12 @@ sealed class BaseShow : StepData()
@Serializable
data class Show(
val material: Material
-) : BaseShow()
+) : BaseShow() {
+ override val brailleDots: BrailleDots
+ get() = when (material.data) {
+ is OneBrailleSymbol -> material.data.brailleDots
+ }
+}
/**
* Step shows Braille dots with specific numbers.
@@ -106,5 +123,6 @@ data class Show(
@Serializable
data class ShowDots(
val text: HtmlText?,
- val dots: BrailleDots
+ @SerialName("dots")
+ override val brailleDots: BrailleDots
) : BaseShow()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Steps.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Steps.kt
index 3e9cbd5f..fe68006c 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Steps.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Steps.kt
@@ -35,7 +35,7 @@ interface StepDao {
suspend fun insert(steps: List)
@Query("select * from steps where id = :id")
- suspend fun getStep(id: DBid): Step?
+ suspend fun step(id: DBid): Step?
@Query(
"""
@@ -45,7 +45,7 @@ interface StepDao {
where cs.user_id = :userId and cs.course_id = :courseId
"""
)
- suspend fun getCurrentStep(userId: DBid, courseId: DBid): Step?
+ suspend fun currentStep(userId: DBid, courseId: DBid): Step?
@Query(
"""
@@ -55,7 +55,7 @@ interface StepDao {
where ls.user_id = :userId and ls.course_id = :courseId
"""
)
- suspend fun getLastStep(userId: DBid, courseId: DBid): Step?
+ suspend fun lastStep(userId: DBid, courseId: DBid): Step?
@Query(
"""
@@ -65,7 +65,7 @@ interface StepDao {
where ls.user_id = :userId and ls.course_id = :courseId and ls.lesson_id = :lessonId
"""
)
- suspend fun getLastStep(userId: DBid, courseId: DBid, lessonId: DBid): Step?
+ suspend fun lastStep(userId: DBid, courseId: DBid, lessonId: DBid): Step?
@Query(
"""
@@ -74,7 +74,7 @@ interface StepDao {
order by steps.lesson_id, steps.id limit 1
"""
)
- suspend fun getFirstCourseStep(courseId: DBid): Step?
+ suspend fun firstCourseStep(courseId: DBid): Step?
@Query(
"""
@@ -95,7 +95,7 @@ interface StepDao {
limit 1
"""
)
- suspend fun getNextStep(
+ suspend fun nextStep(
courseId: DBid,
thisLessonId: DBid,
thisStepId: DBid,
@@ -121,7 +121,7 @@ interface StepDao {
limit 1
"""
)
- suspend fun getPrevStep(
+ suspend fun prevStep(
courseId: DBid,
thisLessonId: DBid,
thisStepId: DBid,
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Users.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Users.kt
index 5af9a2bf..995c0ea4 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Users.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/entities/Users.kt
@@ -23,10 +23,10 @@ interface UserDao {
suspend fun insert(users: List)
@Query("select * from users where :login = login limit 1")
- suspend fun getUser(login: UserLogin): User?
+ suspend fun user(login: UserLogin): User?
@Query("select * from users where :id = id limit 1")
- suspend fun getUser(id: DBid): User?
+ suspend fun user(id: DBid): User?
@Query("delete from users")
suspend fun clear()
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepository.kt
index 04783487..83dd9011 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/ActionsRepository.kt
@@ -12,7 +12,7 @@ import java.util.*
typealias Actions = List
interface ActionsRepository {
- suspend fun getActionsFrom(days: Days): Actions
+ suspend fun actionsFrom(days: Days): Actions
}
interface MutableActionsRepository : ActionsRepository {
@@ -33,9 +33,9 @@ class ActionsRepositoryImpl(
override suspend fun clearAllStats() = actionsDao.clear()
- override suspend fun getActionsFrom(days: Days): Actions =
+ override suspend fun actionsFrom(days: Days): Actions =
actionsDao
- .getAllActionsSince((getCurrDate() - days).time)
+ .allActionsSince((getCurrDate() - days).time)
.also {
scope().launch {
actionsDao.removeAllActionsBefore((getCurrDate() - keepActionsTime).time)
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/BrowserRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/BrowserRepository.kt
index b4d6e3f4..3bf4265f 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/BrowserRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/BrowserRepository.kt
@@ -2,9 +2,7 @@ package com.github.braillesystems.learnbraille.data.repository
import android.content.Context
import com.github.braillesystems.learnbraille.data.dsl.ALL_CARDS_DECK_ID
-import com.github.braillesystems.learnbraille.data.entities.CardDao
import com.github.braillesystems.learnbraille.data.entities.DBid
-import com.github.braillesystems.learnbraille.data.entities.DeckDao
import com.github.braillesystems.learnbraille.utils.preferences
interface BrowserRepository : MaterialsRepository {
@@ -18,10 +16,9 @@ interface MutableBrowserRepository : BrowserRepository {
class BrowserRepositoryImpl(
private val context: Context,
private val preferenceRepository: PreferenceRepository,
- deckDao: DeckDao,
- cardDao: CardDao
-) : MaterialsRepositoryImpl(deckDao, cardDao),
- MutableBrowserRepository {
+ private val materialsRepository: MaterialsRepository
+) : MutableBrowserRepository,
+ MaterialsRepository by materialsRepository {
private val currDeckPreference: String
get() = "browser_curr_deck_${preferenceRepository.currentUserId}"
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepository.kt
index 6a05bdb2..79654363 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/MaterialsRepository.kt
@@ -2,22 +2,46 @@ package com.github.braillesystems.learnbraille.data.repository
import com.github.braillesystems.learnbraille.data.entities.*
+data class DeckWithAvailability(
+ val deck: Deck,
+ val containsCards: Boolean
+)
+
interface MaterialsRepository {
- suspend fun getRandomMaterialFromDeck(id: DBid): Material?
- suspend fun getAllMaterialsFromDeck(id: DBid): List
- suspend fun getAllDecks(): List
+ suspend fun randomMaterialFromDeck(id: DBid): Material?
+ suspend fun randomKnownMaterialFromDeck(id: DBid): Material?
+ suspend fun allMaterialsFromDeck(id: DBid): List
+ suspend fun allDecks(): List
+ suspend fun availableDecks(): List
+ suspend fun allDecksWithAvailability(): List
}
open class MaterialsRepositoryImpl(
private val deckDao: DeckDao,
- private val cardDao: CardDao
+ private val cardDao: CardDao,
+ private val preferenceRepository: PreferenceRepository
) : MaterialsRepository {
- override suspend fun getRandomMaterialFromDeck(id: DBid): Material? =
- cardDao.getRandomMaterialFromDeck(id)
+ override suspend fun randomMaterialFromDeck(id: DBid): Material? =
+ cardDao.randomMaterialFromDeck(id)
+
+ override suspend fun randomKnownMaterialFromDeck(id: DBid): Material? =
+ cardDao.randomKnownMaterialFromDeck(preferenceRepository.currentUserId, id)
+
+ override suspend fun allMaterialsFromDeck(id: DBid): List =
+ cardDao.allMaterialsFromDeck(id)
+
+ override suspend fun allDecks(): List = deckDao.allDecks()
- override suspend fun getAllMaterialsFromDeck(id: DBid): List =
- cardDao.getAllMaterialsFromDeck(id)
+ override suspend fun availableDecks(): List =
+ deckDao.availableDecks(preferenceRepository.currentUserId)
- override suspend fun getAllDecks(): List = deckDao.getAllDecks()
+ override suspend fun allDecksWithAvailability(): List =
+ if (preferenceRepository.practiceUseOnlyKnownMaterials) {
+ val all = allDecks()
+ val available = availableDecks()
+ all.map { DeckWithAvailability(it, available.contains(it)) }
+ } else {
+ deckDao.allDecks().map { DeckWithAvailability(it, true) }
+ }
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepository.kt
index 213dbc4b..5b666efb 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PracticeRepository.kt
@@ -2,32 +2,30 @@ package com.github.braillesystems.learnbraille.data.repository
import android.content.Context
import com.github.braillesystems.learnbraille.data.dsl.ALL_CARDS_DECK_ID
-import com.github.braillesystems.learnbraille.data.entities.*
+import com.github.braillesystems.learnbraille.data.entities.DBid
+import com.github.braillesystems.learnbraille.data.entities.Deck
+import com.github.braillesystems.learnbraille.data.entities.DeckDao
+import com.github.braillesystems.learnbraille.data.entities.Material
import com.github.braillesystems.learnbraille.utils.preferences
-data class DeckNotEmpty(
- val deck: Deck,
- val containsCards: Boolean
-)
-
-interface PracticeRepository {
+interface PracticeRepository : MaterialsRepository {
val currentDeckId: DBid
- suspend fun getNextMaterial(): Material?
- suspend fun getCurrDeck(): Deck
- suspend fun getAllDecks(): List
+ suspend fun currentDeck(): Deck
+ suspend fun randomMaterial(): Material?
+ suspend fun randomKnownMaterial(): Material?
}
interface MutablePracticeRepository : PracticeRepository {
override var currentDeckId: DBid
- suspend fun getNextMaterialNotNull(): Material
}
class PracticeRepositoryImpl(
private val context: Context,
private val deckDao: DeckDao,
- private val cardDao: CardDao,
- private val preferenceRepository: PreferenceRepository
-) : MutablePracticeRepository {
+ private val preferenceRepository: PreferenceRepository,
+ private val materialsRepository: MaterialsRepository
+) : MutablePracticeRepository,
+ MaterialsRepository by materialsRepository {
private val currDeckPreference: String
get() = "practice_curr_deck_${preferenceRepository.currentUserId}"
@@ -43,42 +41,12 @@ class PracticeRepositoryImpl(
}
}
- override suspend fun getNextMaterial(): Material? =
- if (preferenceRepository.practiceUseOnlyKnownMaterials) {
- cardDao.getRandomKnownMaterialFromDeck(
- preferenceRepository.currentUserId,
- currentDeckId
- )
- } else {
- cardDao.getRandomMaterialFromDeck(currentDeckId)
- }
+ override suspend fun currentDeck(): Deck =
+ deckDao.deck(currentDeckId) ?: error("Wrong currentDeckId")
- /**
- * Deck changes automatically if `use only known materials` enabled
- * and previous `currentDeck` became not available.
- */
- override suspend fun getNextMaterialNotNull(): Material = getNextMaterial() ?: run {
- if (preferenceRepository.practiceUseOnlyKnownMaterials) {
- currentDeckId = ALL_CARDS_DECK_ID
- getNextMaterial()
- ?: error("Some materials are expected to be added as known by default")
- } else {
- error(
- "Materials are expected to be prepopulated and " +
- "user should not have possibilities to access empty deck"
- )
- }
- }
+ override suspend fun randomMaterial(): Material? =
+ materialsRepository.randomMaterialFromDeck(currentDeckId)
- override suspend fun getCurrDeck(): Deck =
- deckDao.getDeck(currentDeckId) ?: error("Current deck should always exist")
-
- override suspend fun getAllDecks(): List =
- if (preferenceRepository.practiceUseOnlyKnownMaterials) {
- val all = deckDao.getAllDecks()
- val available = deckDao.getAvailableDecks(preferenceRepository.currentUserId)
- all.map { DeckNotEmpty(it, available.contains(it)) }
- } else {
- deckDao.getAllDecks().map { DeckNotEmpty(it, true) }
- }
+ override suspend fun randomKnownMaterial(): Material? =
+ materialsRepository.randomKnownMaterialFromDeck(currentDeckId)
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PreferenceRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PreferenceRepository.kt
index 3992969e..b5c962fd 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PreferenceRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/PreferenceRepository.kt
@@ -16,7 +16,6 @@ interface PreferenceRepository {
val buzzEnabled: Boolean
val toastsEnabled: Boolean
val brailleTrainerEnabled: Boolean get() = false // Uncomment in android manifest when set true
- val speechRecognitionEnabled: Boolean
val golubinaBookStepsEnabled: Boolean
val slateStylusStepsEnabled: Boolean
val traverseDotsInEnumerationOrder: Boolean
@@ -59,13 +58,6 @@ class PreferenceRepositoryImpl(
)
}
- override val speechRecognitionEnabled: Boolean by logged {
- context.preferences.getBoolean(
- context.getString(R.string.preference_speech_recognition_enabled),
- false // To enable, set to `true` and uncomment permission in AndroidManifest
- )
- }
-
override val golubinaBookStepsEnabled: Boolean by logged {
context.preferences.getBoolean(
context.getString(R.string.preference_golubina_book_steps_enabled),
@@ -129,7 +121,7 @@ class PreferenceRepositoryImpl(
}
override suspend fun getCurrentUser(): User =
- userDao.getUser(currentUserId)
+ userDao.user(currentUserId)
?.also { Timber.i("Current user = $it") }
?: error("Current user should always exist")
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/TheoryRepository.kt b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/TheoryRepository.kt
index f80b9f26..c3582605 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/TheoryRepository.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/data/repository/TheoryRepository.kt
@@ -7,16 +7,16 @@ import com.github.braillesystems.learnbraille.utils.scope
import kotlinx.coroutines.launch
interface TheoryRepository {
- suspend fun getCurrentStep(courseId: DBid): Step
- suspend fun getLastCourseStep(courseId: DBid): Step
- suspend fun getAllCourseLessons(courseId: DBid): List
+ suspend fun currentStep(courseId: DBid): Step
+ suspend fun lastCourseStep(courseId: DBid): Step
+ suspend fun allCourseLessons(courseId: DBid): List
}
interface MutableTheoryRepository : TheoryRepository {
- suspend fun getNextStepAndUpdate(thisStep: Step, markThisAsPassed: Boolean = false): Step?
- suspend fun getPrevStepAndUpdate(thisStep: Step): Step?
- suspend fun getCurrentStepAndUpdate(courseId: DBid): Step
- suspend fun getLastLessonOrCurrentStepAndUpdate(courseId: DBid, lessonId: DBid): Step
+ suspend fun nextStepAndMove(thisStep: Step, markThisAsPassed: Boolean = false): Step?
+ suspend fun prevStepAndMove(thisStep: Step): Step?
+ suspend fun currentStepAndMove(courseId: DBid): Step
+ suspend fun lastLessonOrCurrentStepAndMove(courseId: DBid, lessonId: DBid): Step
}
class TheoryRepositoryImpl(
@@ -39,16 +39,15 @@ class TheoryRepositoryImpl(
)
@Suppress("ReturnCount")
- override suspend fun getNextStepAndUpdate(thisStep: Step, markThisAsPassed: Boolean): Step? {
+ override suspend fun nextStepAndMove(thisStep: Step, markThisAsPassed: Boolean): Step? {
val next = stepDao
- .getNextStep(
+ .nextStep(
thisStep.courseId, thisStep.lessonId, thisStep.id,
proscribedAnnotations
)
?: return null
- val curr = requireNotNull(
- stepDao.getCurrentStep(preferenceRepository.currentUserId, thisStep.courseId)
- )
+ val curr = stepDao
+ .currentStep(preferenceRepository.currentUserId, thisStep.courseId)!!
val updateAndReturn = {
updateLast(next)
@@ -72,9 +71,9 @@ class TheoryRepositoryImpl(
return updateAndReturn()
}
- override suspend fun getPrevStepAndUpdate(thisStep: Step): Step? =
+ override suspend fun prevStepAndMove(thisStep: Step): Step? =
stepDao
- .getPrevStep(
+ .prevStep(
thisStep.courseId,
thisStep.lessonId,
thisStep.id,
@@ -82,37 +81,37 @@ class TheoryRepositoryImpl(
)
?.also { updateLast(it) }
- override suspend fun getCurrentStepAndUpdate(courseId: DBid): Step =
- getCurrentStep(courseId).also { updateLast(it) }
+ override suspend fun currentStepAndMove(courseId: DBid): Step =
+ currentStep(courseId).also { updateLast(it) }
/**
* LessonId is supposed to exist for this courseId.
*/
- override suspend fun getLastLessonOrCurrentStepAndUpdate(courseId: DBid, lessonId: DBid): Step =
+ override suspend fun lastLessonOrCurrentStepAndMove(courseId: DBid, lessonId: DBid): Step =
stepDao
- .getLastStep(preferenceRepository.currentUserId, courseId, lessonId)
+ .lastStep(preferenceRepository.currentUserId, courseId, lessonId)
?.also { updateLast(it) }
?: error(
"No such lessonId ($lessonId) exists for course ($courseId) " +
"or current step is behind lesson with such lessonId"
)
- override suspend fun getCurrentStep(courseId: DBid): Step =
+ override suspend fun currentStep(courseId: DBid): Step =
stepDao
- .getCurrentStep(preferenceRepository.currentUserId, courseId)
+ .currentStep(preferenceRepository.currentUserId, courseId)
?: initCoursePos(courseId)
- override suspend fun getLastCourseStep(courseId: DBid): Step =
+ override suspend fun lastCourseStep(courseId: DBid): Step =
stepDao
- .getLastStep(preferenceRepository.currentUserId, courseId)
+ .lastStep(preferenceRepository.currentUserId, courseId)
?: initCoursePos(courseId)
- override suspend fun getAllCourseLessons(courseId: DBid): List =
- lessonDao.getAllCourseLessons(courseId)
+ override suspend fun allCourseLessons(courseId: DBid): List =
+ lessonDao.allCourseLessons(courseId)
private suspend fun initCoursePos(courseId: DBid): Step =
stepDao
- .getFirstCourseStep(courseId)
+ .firstCourseStep(courseId)
?.also { first ->
updateLast(first)
currentStepDao.update(
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/res/Data.kt b/app/src/main/java/com/github/braillesystems/learnbraille/res/Data.kt
index 0aa5b324..578dcf10 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/res/Data.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/res/Data.kt
@@ -9,20 +9,6 @@ import com.github.braillesystems.learnbraille.data.entities.Symbol
import com.github.braillesystems.learnbraille.utils.contextNotNull
import com.github.braillesystems.learnbraille.utils.lazyWithContext
-/**
- * Do not change name of this property, it is used for prepopulation.
- *
- * Use `DslTest.kt` file as DSL tutorial.
- *
- * Text in steps is parsed as HTML.
- *
- * If using `content.symbols.getValue`, `content` should be added to `data` as `materials`.
- * It is better to simply have only one value declared as `by materials`.
- *
- * Correctness of all information should be checked in compile time or in runtime.
- * If some additional info is need, do not hardcode it.
- * Just make request to the new DSL feature via github issues.
- */
val prepopulationData by data(
materials = content,
stepAnnotationNames = listOf(
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/res/GolubinaCourse.kt b/app/src/main/java/com/github/braillesystems/learnbraille/res/GolubinaCourse.kt
index 3267e619..b93cae74 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/res/GolubinaCourse.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/res/GolubinaCourse.kt
@@ -48,45 +48,48 @@ internal val golubinaIntroLessons by lessons {
})
+ShowDots(
text = "Перед Вами полное шеститочие:
точки 1, 2, 3, 4, 5, 6",
- dots = BrailleDots(F, F, F, F, F, F)
+ brailleDots = BrailleDots(F, F, F, F, F, F)
)
- +InputDots(text = "Введите все шесть точек", dots = BrailleDots(F, F, F, F, F, F))
+ +InputDots(text = "Введите все шесть точек", brailleDots = BrailleDots(F, F, F, F, F, F))
+ShowDots(
text = "Перед Вами символ шрифта Брайля -
" +
" точка номер один",
- dots = BrailleDots(F, E, E, E, E, E)
+ brailleDots = BrailleDots(F, E, E, E, E, E)
)
- +InputDots(text = "Введите точку один", dots = BrailleDots(F, E, E, E, E, E))
+ +InputDots(text = "Введите точку один", brailleDots = BrailleDots(F, E, E, E, E, E))
+ShowDots(
text = "Перед Вами символ шрифта Брайля -
" +
" точка номер три",
- dots = BrailleDots(E, E, F, E, E, E)
+ brailleDots = BrailleDots(E, E, F, E, E, E)
)
- +InputDots(text = "Введите точку три", dots = BrailleDots(E, E, F, E, E, E))
+ +InputDots(text = "Введите точку три", brailleDots = BrailleDots(E, E, F, E, E, E))
+ShowDots(
text = "Перед Вами символ шрифта Брайля -
" +
" точка номер пять",
- dots = BrailleDots(E, E, E, E, F, E)
+ brailleDots = BrailleDots(E, E, E, E, F, E)
)
- +InputDots(text = "Введите точку пять", dots = BrailleDots(E, E, E, E, F, E))
+ +InputDots(text = "Введите точку пять", brailleDots = BrailleDots(E, E, E, E, F, E))
+InputDots(
text = """Теперь выполним пять практических заданий без обучающей картинки.
Введите комбинацию точек 1 и 3""",
- dots = BrailleDots(F, E, F, E, E, E)
+ brailleDots = BrailleDots(F, E, F, E, E, E)
+ )
+ +InputDots(
+ text = "Введите комбинацию: точки 4 и 6",
+ brailleDots = BrailleDots(E, E, E, F, E, F)
)
- +InputDots(text = "Введите комбинацию: точки 4 и 6", dots = BrailleDots(E, E, E, F, E, F))
+InputDots(
text = "Введите комбинацию точек 1, 3, 4 и 6",
- dots = BrailleDots(F, E, F, F, E, F)
+ brailleDots = BrailleDots(F, E, F, F, E, F)
)
+InputDots(
text = "Введите комбинацию точек 1, 2, 3, 4 и 5",
- dots = BrailleDots(F, F, F, F, F, E)
+ brailleDots = BrailleDots(F, F, F, F, F, E)
)
+InputDots(
text = "Введите комбинацию точек 1, 2, 3, 4 и 6",
- dots = BrailleDots(F, F, F, F, E, F)
+ brailleDots = BrailleDots(F, F, F, F, E, F)
)
+Info(
"""Откройте пособие на странице 12.
@@ -95,7 +98,10 @@ internal val golubinaIntroLessons by lessons {
Начиная со второй строки - тренировочные упражнения.
Самостоятельно потренируйтесь читать отдельные комбинации точек."""
).annotate(StepAnnotation.golubinaBookRequired)
- +InputDots(text = """Введите "средние точки" 2 и 5""", dots = BrailleDots(E, F, E, E, F, E))
+ +InputDots(
+ text = """Введите "средние точки" 2 и 5""",
+ brailleDots = BrailleDots(E, F, E, E, F, E)
+ )
+Info(
"""Запишите "средние точки" 2 и 5 на брайлевском приборе.
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/res/Materials.kt b/app/src/main/java/com/github/braillesystems/learnbraille/res/Materials.kt
index d518e6f0..a6a2c6f8 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/res/Materials.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/res/Materials.kt
@@ -224,7 +224,11 @@ private val ms by markers {
* so use `Fragment.getString` outside of lambdas.
*/
+val Fragment.inputSymbolPrintRules get() = contextNotNull.inputSymbolPrintRules
+val Fragment.showSymbolPrintRules get() = contextNotNull.showSymbolPrintRules
val Fragment.captionRules get() = contextNotNull.captionRules
+val Fragment.inputMarkerPrintRules get() = contextNotNull.inputMarkerPrintRules
+val Fragment.showMarkerPrintRules get() = contextNotNull.showMarkerPrintRules
val Context.inputSymbolPrintRules by rules(
{
@@ -305,7 +309,6 @@ val Context.inputSymbolPrintRules by rules(
)
val Context.showSymbolPrintRules by rules(
-
{
val t = getString(R.string.show_letter_intro_template)
ruSymbols.map::containsKey to { c: Char -> t.format(c) }
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/res/TestCourse.kt b/app/src/main/java/com/github/braillesystems/learnbraille/res/TestCourse.kt
index 6fe348bd..5d38c1a2 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/res/TestCourse.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/res/TestCourse.kt
@@ -29,11 +29,11 @@ internal val testLessons by lessons {
)
+ShowDots(
text = "Перед Вами полное шеститочие",
- dots = BrailleDots(F, F, F, F, F, F)
+ brailleDots = BrailleDots(F, F, F, F, F, F)
)
+InputDots(
text = "Введите все шесть точек",
- dots = BrailleDots(F, F, F, F, F, F)
+ brailleDots = BrailleDots(F, F, F, F, F, F)
)
+Info(
"""Откройте пособие на странице 12.
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/Messages.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/Messages.kt
index 87aa3c78..eea7352d 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/Messages.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/Messages.kt
@@ -3,29 +3,17 @@ package com.github.braillesystems.learnbraille.ui
import android.content.Context
import androidx.fragment.app.Fragment
import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.BrailleDot
-import com.github.braillesystems.learnbraille.data.entities.BrailleDots
-import com.github.braillesystems.learnbraille.data.entities.list
-import com.github.braillesystems.learnbraille.data.entities.spelling
+import com.github.braillesystems.learnbraille.data.entities.*
+import com.github.braillesystems.learnbraille.res.inputMarkerPrintRules
import com.github.braillesystems.learnbraille.res.inputSymbolPrintRules
-import com.github.braillesystems.learnbraille.res.showSymbolPrintRules
import com.github.braillesystems.learnbraille.utils.*
-import timber.log.Timber
-enum class PrintMode {
- INPUT, SHOW
-}
-
-fun Fragment.showCorrectToast(): Unit = toast(getString(R.string.input_correct))
+fun Fragment.showCorrectToast() = toast(getString(R.string.input_correct))
-fun Fragment.showIncorrectToast(c: Char? = null): Unit =
- if (c == null) toast(getString(R.string.input_incorrect))
- else toast(
- "${getString(R.string.input_incorrect)} " +
- printString(c, PrintMode.INPUT).orEmpty()
- )
+fun Fragment.showIncorrectToast(hint: String = "") =
+ toast("${getString(R.string.input_incorrect)} $hint")
-val Context.dotsHintRules by lazyWithContext> {
+private val Context.dotsHintRules by lazyWithContext> {
listOf(
getString(R.string.input_dots_hint_1),
getString(R.string.input_dots_hint_2),
@@ -36,34 +24,24 @@ val Context.dotsHintRules by lazyWithContext> {
)
}
-fun Fragment.showHintDotsToast(expectedDots: BrailleDots) =
- getString(R.string.input_dots_hint_template)
- .format(
- expectedDots.list
- .mapIndexedNotNull { index, brailleDot ->
- if (brailleDot == BrailleDot.F) application.dotsHintRules[index] else null
- }
- .joinToString(separator = ", ")
- )
- .side { checkedToast(it) }
+fun Fragment.showHintDotsToast(expectedDots: BrailleDots) {
+ val template = getString(R.string.input_dots_hint_template)
+ val hint = expectedDots
+ .filled
+ .joinToString(separator = ", ") {
+ contextNotNull.dotsHintRules[it - 1]
+ }
+ checkedToast(template.format(hint))
+}
fun Fragment.showHintToast(expectedDots: BrailleDots) =
checkedToast(getString(R.string.input_hint_template).format(expectedDots.spelling))
-fun Context.printString(c: Char, mode: PrintMode): String? =
- when (mode) {
- PrintMode.INPUT -> inputSymbolPrintRules[c]
- PrintMode.SHOW -> showSymbolPrintRules[c]
+fun Context.inputPrint(data: MaterialData): String =
+ when (data) {
+ is Symbol -> inputSymbolPrintRules.getValue(data.char)
+ is MarkerSymbol -> inputMarkerPrintRules.getValue(data.type)
}
-fun Context.printStringNotNullLogged(c: Char, mode: PrintMode): String =
- printString(c, mode) ?: "".also { Timber.e("Intro should be available") }
-
-fun Fragment.printString(c: Char, mode: PrintMode): String? =
- (context ?: null.also { Timber.w("Context is not available") })
- ?.run { printString(c, mode) }
-
-fun Fragment.printStringNotNullLogged(c: Char, mode: PrintMode): String =
- context
- ?.printStringNotNullLogged(c, mode)
- ?: error("Context is not available")
+fun Fragment.inputPrint(data: MaterialData): String =
+ contextNotNull.inputPrint(data)
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/DotsChecker.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/DotsChecker.kt
index d5fed047..51d4cb83 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/DotsChecker.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/DotsChecker.kt
@@ -77,7 +77,10 @@ interface MutableDotsChecker : DotsChecker {
}
/**
- * Initialize lateinit callbacks firstly
+ * Initialize lateinit callbacks firstly.
+ *
+ * Callbacks are called before changing state,
+ * so they can access previous state (the next one is obvious).
*/
private class DotsCheckerImpl : MutableDotsChecker {
@@ -125,7 +128,7 @@ private class DotsCheckerImpl : MutableDotsChecker {
private val isCorrect: Boolean
get() = (enteredDots == expectedDots).also {
Timber.i(
- if (it) "Correct: "
+ if (it) "Correct"
else "Incorrect: entered = $enteredDots, expected = $expectedDots"
)
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/BrowserFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/BrowserFragment.kt
index 556657ed..dc769d42 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/BrowserFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/BrowserFragment.kt
@@ -17,7 +17,10 @@ import com.github.braillesystems.learnbraille.databinding.FragmentBrowserBinding
import com.github.braillesystems.learnbraille.res.showMarkerPrintRules
import com.github.braillesystems.learnbraille.res.showSymbolPrintRules
import com.github.braillesystems.learnbraille.ui.screens.AbstractFragmentWithHelp
-import com.github.braillesystems.learnbraille.utils.*
+import com.github.braillesystems.learnbraille.utils.getValue
+import com.github.braillesystems.learnbraille.utils.navigate
+import com.github.braillesystems.learnbraille.utils.stringify
+import com.github.braillesystems.learnbraille.utils.title
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
@@ -41,7 +44,7 @@ class BrowserFragment : AbstractFragmentWithHelp(R.string.browser_help) {
lifecycleScope.launch {
val deckId = browserRepository.currentDeckId
- val materials = browserRepository.getAllMaterialsFromDeck(deckId)
+ val materials = browserRepository.allMaterialsFromDeck(deckId)
val listener = object : BrowserItemListener {
override fun onClick(item: Material) {
val arg = stringify(Material.serializer(), item)
@@ -61,11 +64,11 @@ class BrowserFragment : AbstractFragmentWithHelp(R.string.browser_help) {
this.item = item
materialText.text = when (item.data) {
is Symbol -> getString(R.string.browser_represent_template).format(
- contextNotNull.showSymbolPrintRules[item.data.char].toString(),
+ showSymbolPrintRules.getValue(item.data.char),
item.data.brailleDots.spelling
)
is MarkerSymbol -> getString(R.string.browser_represent_template).format(
- contextNotNull.showMarkerPrintRules[item.data.type].toString(),
+ showMarkerPrintRules.getValue(item.data.type),
item.data.brailleDots.spelling
)
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/MarkerViewFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/MarkerViewFragment.kt
index eca41d12..a14a4c81 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/MarkerViewFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/MarkerViewFragment.kt
@@ -12,9 +12,8 @@ import com.github.braillesystems.learnbraille.res.showMarkerPrintRules
import com.github.braillesystems.learnbraille.ui.screens.AbstractFragmentWithHelp
import com.github.braillesystems.learnbraille.ui.views.display
import com.github.braillesystems.learnbraille.ui.views.dotsState
-import com.github.braillesystems.learnbraille.utils.contextNotNull
-import com.github.braillesystems.learnbraille.utils.get
import com.github.braillesystems.learnbraille.utils.getFragmentStringArg
+import com.github.braillesystems.learnbraille.utils.getValue
import com.github.braillesystems.learnbraille.utils.parse
class MarkerViewFragment : AbstractFragmentWithHelp(R.string.browser_marker_view_help) {
@@ -35,7 +34,7 @@ class MarkerViewFragment : AbstractFragmentWithHelp(R.string.browser_marker_view
val m: Material = parse(Material.serializer(), getFragmentStringArg("material"))
require(m.data is MarkerSymbol)
- binding.infoTextView.text = contextNotNull.showMarkerPrintRules[m.data.type]
+ binding.infoTextView.text = showMarkerPrintRules.getValue(m.data.type)
binding.brailleDots.dotsState.display(m.data.brailleDots)
}.root
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/SymbolViewFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/SymbolViewFragment.kt
index b6de0f3d..07cf99bd 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/SymbolViewFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/browser/SymbolViewFragment.kt
@@ -27,16 +27,16 @@ class SymbolViewFragment : AbstractFragmentWithHelp(R.string.browser_symbol_view
R.layout.fragment_symbol_view,
container,
false
- ).also { binding ->
+ ).apply {
setHasOptionsMenu(true)
val m: Material = parse(Material.serializer(), getFragmentStringArg("material"))
require(m.data is Symbol)
- binding.letter.text = m.data.char.toString()
- binding.letterCaption.text = captionRules.getValue(m.data)
- binding.brailleDots.dotsState.display(m.data.brailleDots)
+ letter.letter = m.data.char
+ letterCaption.text = captionRules.getValue(m.data)
+ brailleDots.dotsState.display(m.data.brailleDots)
}.root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/exit/ExitFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/exit/ExitFragment.kt
index 95ca0112..ff50e0bf 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/exit/ExitFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/exit/ExitFragment.kt
@@ -1,6 +1,5 @@
package com.github.braillesystems.learnbraille.ui.screens.exit
-import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -8,17 +7,13 @@ import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import com.github.braillesystems.learnbraille.R
import com.github.braillesystems.learnbraille.databinding.FragmentExitBinding
-import com.github.braillesystems.learnbraille.utils.SpeechRecognition
import com.github.braillesystems.learnbraille.utils.checkedAnnounce
+import com.github.braillesystems.learnbraille.utils.exitToLauncher
import com.github.braillesystems.learnbraille.utils.navigate
-import com.github.braillesystems.learnbraille.utils.updateTitle
-import org.koin.android.ext.android.get
-
+import com.github.braillesystems.learnbraille.utils.title
class ExitFragment : Fragment() {
- private lateinit var recognizer: SpeechRecognition
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -30,17 +25,11 @@ class ExitFragment : Fragment() {
false
).apply {
- val title: String = getString(R.string.exit_question)
- updateTitle(title)
+ title = getString(R.string.exit_question)
checkedAnnounce(title)
- recognizer = SpeechRecognition(this@ExitFragment, get())
-
exitButton.setOnClickListener {
- val homeIntent = Intent(Intent.ACTION_MAIN)
- homeIntent.addCategory(Intent.CATEGORY_HOME)
- homeIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
- startActivity(homeIntent)
+ exitToLauncher()
}
continueButton.setOnClickListener {
@@ -48,9 +37,4 @@ class ExitFragment : Fragment() {
}
}.root
-
- override fun onDestroy() {
- super.onDestroy()
- recognizer.onDestroy()
- }
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/menu/MenuFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/menu/MenuFragment.kt
index ccc18f7b..20d1a088 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/menu/MenuFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/menu/MenuFragment.kt
@@ -1,11 +1,8 @@
package com.github.braillesystems.learnbraille.ui.screens.menu
-import android.Manifest
import android.app.Activity.RESULT_OK
import android.content.ActivityNotFoundException
import android.content.Intent
-import android.content.pm.PackageManager
-import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -42,7 +39,6 @@ class MenuFragment : AbstractFragmentWithHelp(R.string.menu_help) {
title = getString(R.string.menu_actionbar_text_template).format(appName)
setHasOptionsMenu(true)
- requestPermissions()
val buttons = mutableListOf()
@@ -125,28 +121,6 @@ class MenuFragment : AbstractFragmentWithHelp(R.string.menu_help) {
}
}
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- when (requestCode) {
- recordAudioPermissionCode -> if (grantResults.first() != PackageManager.PERMISSION_GRANTED) {
- toast(getString(R.string.voice_record_denial))
- }
- }
- }
-
- private fun requestPermissions() {
- runIf(preferenceRepository.speechRecognitionEnabled) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return@runIf
- val permission = requireContext().checkSelfPermission(Manifest.permission.RECORD_AUDIO)
- if (permission == PackageManager.PERMISSION_GRANTED) return@runIf
- requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), recordAudioPermissionCode)
- }
- }
-
private fun interruptingOnClickListener(block: (View) -> Unit) =
View.OnClickListener {
if (db.isInitialized) block(it)
@@ -187,6 +161,5 @@ class MenuFragment : AbstractFragmentWithHelp(R.string.menu_help) {
companion object {
private const val qrRequestCode = 0
- private const val recordAudioPermissionCode = 29
}
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardFragment.kt
index 4ad4f91c..d58118be 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardFragment.kt
@@ -2,7 +2,6 @@ package com.github.braillesystems.learnbraille.ui.screens.practice
import android.os.Bundle
import android.os.Vibrator
-import android.util.TypedValue
import android.view.*
import androidx.core.content.getSystemService
import androidx.databinding.DataBindingUtil
@@ -16,10 +15,13 @@ import com.github.braillesystems.learnbraille.databinding.FragmentCardBinding
import com.github.braillesystems.learnbraille.res.captionRules
import com.github.braillesystems.learnbraille.res.deckTagToName
import com.github.braillesystems.learnbraille.res.inputMarkerPrintRules
-import com.github.braillesystems.learnbraille.ui.*
import com.github.braillesystems.learnbraille.ui.brailletrainer.BrailleTrainer
import com.github.braillesystems.learnbraille.ui.brailletrainer.BrailleTrainerSignalHandler
+import com.github.braillesystems.learnbraille.ui.inputPrint
import com.github.braillesystems.learnbraille.ui.screens.*
+import com.github.braillesystems.learnbraille.ui.showCorrectToast
+import com.github.braillesystems.learnbraille.ui.showHintToast
+import com.github.braillesystems.learnbraille.ui.showIncorrectToast
import com.github.braillesystems.learnbraille.ui.views.BrailleDotsState
import com.github.braillesystems.learnbraille.ui.views.brailleDots
import com.github.braillesystems.learnbraille.ui.views.dotsState
@@ -33,18 +35,10 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
private val preferenceRepository: PreferenceRepository by inject()
- private lateinit var viewModel: CardViewModel
+ // This value can change during ViewModel lifetime (ViewModelProvider does not call
+ // ViewModelFactory each time onCreateView runs). And once created ViewModel
+ // should be able to use up to date dotsState.
private lateinit var dotsState: BrailleDotsState
- private var buzzer: Vibrator? = null
-
- private val title: String
- get() = getString(R.string.practice_actionbar_title_template).let {
- if (::viewModel.isInitialized) it.format(
- viewModel.nCorrect,
- viewModel.nTries
- )
- else it.format(0, 0)
- }
override fun onCreateView(
inflater: LayoutInflater,
@@ -59,35 +53,32 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
Timber.i("onCreateView")
- updateTitle(title)
+ title = title()
setHasOptionsMenu(true)
if (preferenceRepository.extendedAccessibilityEnabled) {
- binding.hintButton.setSize(
- width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
- )
- binding.nextButton.setSize(
- width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
- )
- binding.markerDescription.setTextSize(
- TypedValue.COMPLEX_UNIT_SP,
- application.extendedTextSize
+ applyExtendedAccessibility(
+ leftButton = binding.hintButton,
+ rightButton = binding.nextButton,
+ textView = binding.markerDescription
)
}
- dotsState = binding.brailleDots.dotsState.apply {
- subscribe(View.OnClickListener {
- viewModel.onSoftCheck()
- })
- }
+ dotsState = binding.brailleDots.dotsState
val viewModelFactory: CardViewModelFactory by inject {
parametersOf({ dotsState.brailleDots })
}
- viewModel = ViewModelProvider(
- this, viewModelFactory
- ).get(CardViewModel::class.java)
- buzzer = activity?.getSystemService()
+ val viewModel = ViewModelProvider(this, viewModelFactory)
+ .get(CardViewModel::class.java)
+
+ dotsState.subscribe(View.OnClickListener {
+ viewModel.onSoftCheck()
+ })
+
+
+ val buzzer: Vibrator? = activity?.getSystemService()
+
BrailleTrainer.setSignalHandler(object : BrailleTrainerSignalHandler {
override fun onJoystickRight() = viewModel.onCheck()
override fun onJoystickLeft() = viewModel.onHint()
@@ -104,13 +95,13 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
is Symbol -> {
binding.letter.visibility = View.VISIBLE
binding.markerDescription.visibility = View.GONE
- binding.letter.text = it.char.toString()
+ binding.letter.letter = it.char
binding.letterCaption.text = captionRules.getValue(it)
}
is MarkerSymbol -> {
binding.letter.visibility = View.GONE
binding.markerDescription.visibility = View.VISIBLE
- binding.markerDescription.text = contextNotNull.inputMarkerPrintRules[it.type]
+ binding.markerDescription.text = inputMarkerPrintRules[it.type]
binding.letterCaption.text = ""
}
}
@@ -118,20 +109,17 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
viewModel.observeCheckedOnFly(
viewLifecycleOwner, dotsState, buzzer,
- block = { updateTitle(title) },
+ block = { title = title(viewModel) },
softBlock = ::showCorrectToast
)
viewModel.observeEventIncorrect(
viewLifecycleOwner, dotsState, buzzer
) {
- viewModel.symbol.value?.let { symbol ->
- when (symbol) {
- is Symbol -> showIncorrectToast(symbol.char)
- is MarkerSymbol -> showIncorrectToast()
- }
- } ?: checkedToast(getString(R.string.input_loading))
- updateTitle(title)
+ viewModel.symbol.value
+ ?.let { showIncorrectToast(inputPrint(it)) }
+ ?: checkedToast(getString(R.string.input_loading))
+ title = title(viewModel)
}
viewModel.observeEventHint(
@@ -144,10 +132,7 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
viewLifecycleOwner, dotsState
) {
viewModel.symbol.value?.let {
- when (it) {
- is Symbol -> announceIntro(it.char.toString())
- is MarkerSymbol -> checkedAnnounce(contextNotNull.inputMarkerPrintRules[it.type]!!)
- }
+ checkedAnnounce(inputPrint(it))
}
}
@@ -155,10 +140,7 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
viewLifecycleOwner,
Observer {
if (it == null) return@Observer
- when (it) {
- is Symbol -> announceIntro(it.char.toString())
- is MarkerSymbol -> checkedAnnounce(contextNotNull.inputMarkerPrintRules[it.type]!!)
- }
+ checkedAnnounce(inputPrint(it))
}
)
@@ -177,11 +159,11 @@ class CardFragment : AbstractFragmentWithHelp(R.string.practice_help) {
}.root
- private fun announceIntro(symbol: String) {
- require(symbol.length == 1)
- val intro = printStringNotNullLogged(symbol.first(), PrintMode.INPUT)
- checkedAnnounce(intro)
- }
+ private fun title(viewModel: CardViewModel? = null): String =
+ getString(R.string.practice_actionbar_title_template).run {
+ if (viewModel == null) format(0, 0)
+ else format(viewModel.nCorrect, viewModel.nTries)
+ }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.card_menu, menu)
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardViewModel.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardViewModel.kt
index f5dfe5d9..c7b4f623 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardViewModel.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/CardViewModel.kt
@@ -2,9 +2,11 @@ package com.github.braillesystems.learnbraille.ui.screens.practice
import android.app.Application
import androidx.lifecycle.*
+import com.github.braillesystems.learnbraille.data.dsl.ALL_CARDS_DECK_ID
import com.github.braillesystems.learnbraille.data.entities.*
import com.github.braillesystems.learnbraille.data.repository.MutableActionsRepository
import com.github.braillesystems.learnbraille.data.repository.MutablePracticeRepository
+import com.github.braillesystems.learnbraille.data.repository.PreferenceRepository
import com.github.braillesystems.learnbraille.ui.screens.DotsChecker
import com.github.braillesystems.learnbraille.ui.screens.MutableDotsChecker
import com.github.braillesystems.learnbraille.utils.retryN
@@ -18,6 +20,7 @@ import java.util.concurrent.ArrayBlockingQueue
class CardViewModelFactory(
private val practiceRepository: MutablePracticeRepository,
private val actionsRepository: MutableActionsRepository,
+ private val preferenceRepository: PreferenceRepository,
private val application: Application,
private val getEnteredDots: () -> BrailleDots
) : ViewModelProvider.Factory {
@@ -25,7 +28,13 @@ class CardViewModelFactory(
override fun create(modelClass: Class): T =
if (modelClass.isAssignableFrom(CardViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
- CardViewModel(practiceRepository, actionsRepository, application, getEnteredDots) as T
+ CardViewModel(
+ practiceRepository,
+ actionsRepository,
+ preferenceRepository,
+ application,
+ getEnteredDots
+ ) as T
} else {
throw IllegalArgumentException("Unknown ViewModel class")
}
@@ -34,6 +43,7 @@ class CardViewModelFactory(
class CardViewModel(
private val practiceRepository: MutablePracticeRepository,
private val actionsRepository: MutableActionsRepository,
+ private val preferenceRepository: PreferenceRepository,
application: Application,
private val getEnteredDots: () -> BrailleDots,
private val dotsChecker: MutableDotsChecker = MutableDotsChecker.create()
@@ -43,8 +53,8 @@ class CardViewModel(
private val _symbol = MutableLiveData()
val symbol: LiveData get() = _symbol
- private val _deckTag = MutableLiveData()
- val deckTag: LiveData get() = _deckTag
+ private val _deckTag = MutableLiveData()
+ val deckTag: LiveData get() = _deckTag
var nTries: Int = 0
private set
@@ -98,11 +108,23 @@ class CardViewModel(
}
private fun initializeCard(firstTime: Boolean = false) = uiScope.launch {
+ // If `use only known materials` turned on and current deck became unavailable
+ if (preferenceRepository.practiceUseOnlyKnownMaterials &&
+ practiceRepository.randomKnownMaterial() == null
+ ) {
+ practiceRepository.currentDeckId = ALL_CARDS_DECK_ID
+ }
+
+ if (firstTime) {
+ val deck = practiceRepository.currentDeck()
+ _deckTag.value = deck.tag
+ }
+
val material = retryN(
n = 5,
stop = { it.data !in materialsQueue },
- get = { practiceRepository.getNextMaterialNotNull() }
- ) ?: practiceRepository.getNextMaterialNotNull()
+ get = { nextMaterial()!! }
+ ) ?: nextMaterial()!!
if (material.data !in materialsQueue) {
if (materialsQueue.size == nSkipMaterials) materialsQueue.poll()
@@ -112,17 +134,15 @@ class CardViewModel(
material.data.let {
_symbol.value = it
expectedDots = when (it) {
- is Symbol -> it.brailleDots
- is MarkerSymbol -> it.brailleDots
+ is OneBrailleSymbol -> it.brailleDots
}
}
+ }
- // Should be called after getting material because deck changes automatically
- // if `use only known materials` enabled and previous `currentDeck`
- // became not available.
- if (firstTime) {
- val deck = practiceRepository.getCurrDeck()
- _deckTag.value = deck.tag
+ private suspend fun nextMaterial(): Material? =
+ if (preferenceRepository.practiceUseOnlyKnownMaterials) {
+ practiceRepository.randomKnownMaterial()
+ } else {
+ practiceRepository.randomMaterial()
}
- }
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/DecksListFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/DecksListFragment.kt
index 283e7e53..5816d222 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/DecksListFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/practice/DecksListFragment.kt
@@ -1,5 +1,6 @@
package com.github.braillesystems.learnbraille.ui.screens.practice
+import android.graphics.Typeface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -10,7 +11,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.repository.DeckNotEmpty
+import com.github.braillesystems.learnbraille.data.repository.DeckWithAvailability
import com.github.braillesystems.learnbraille.data.repository.MutablePracticeRepository
import com.github.braillesystems.learnbraille.data.repository.PreferenceRepository
import com.github.braillesystems.learnbraille.databinding.DecksListItemBinding
@@ -42,9 +43,10 @@ class DecksListFragment : Fragment() {
title = getString(R.string.decks_list_title)
lifecycleScope.launch {
- val decks = practiceRepository.getAllDecks()
+ val decks = practiceRepository.allDecksWithAvailability()
+ val currDeck = practiceRepository.currentDeck()
val listener = object : DecksItemListener {
- override fun onClick(item: DeckNotEmpty) =
+ override fun onClick(item: DeckWithAvailability) =
if (item.containsCards) {
practiceRepository.currentDeckId = item.deck.id
navigate(R.id.action_decksList_to_cardFragment)
@@ -58,6 +60,11 @@ class DecksListFragment : Fragment() {
decksList.adapter = DecksListAdapter(decks) { item ->
this.item = item
deckName.text = deckTagToName.getValue(item.deck.tag)
+ deckName.setTypeface(
+ deckName.typeface,
+ if (item.deck == currDeck) Typeface.BOLD
+ else Typeface.NORMAL
+ )
clickListener = listener
if (item.containsCards) {
deckName.setTextColor(
@@ -86,8 +93,8 @@ class DecksListFragment : Fragment() {
}
private class DecksListAdapter(
- private val decks: List,
- private val bind: DecksListItemBinding.(DeckNotEmpty) -> Unit
+ private val decks: List,
+ private val bind: DecksListItemBinding.(DeckWithAvailability) -> Unit
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
@@ -112,5 +119,5 @@ private class DeckItemViewHolder(
) : RecyclerView.ViewHolder(binding.root)
interface DecksItemListener {
- fun onClick(item: DeckNotEmpty)
+ fun onClick(item: DeckWithAvailability)
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/stats/StatsFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/stats/StatsFragment.kt
index a91581c9..51e4a846 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/stats/StatsFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/stats/StatsFragment.kt
@@ -13,6 +13,7 @@ import com.github.braillesystems.learnbraille.data.repository.ActionsRepository
import com.github.braillesystems.learnbraille.databinding.FragmentStatsBinding
import com.github.braillesystems.learnbraille.ui.screens.AbstractFragmentWithHelp
import com.github.braillesystems.learnbraille.utils.Days
+import com.github.braillesystems.learnbraille.utils.forEach
import com.github.braillesystems.learnbraille.utils.scope
import com.github.braillesystems.learnbraille.utils.title
import kotlinx.android.synthetic.main.fragment_stats.*
@@ -41,28 +42,29 @@ class StatsFragment : AbstractFragmentWithHelp(R.string.stats_help) {
setHasOptionsMenu(true)
scope(job).launch {
- val statsList = listOf(stats_week to 7, stats_month to 30)
- for (statsData in statsList) {
- val actions: Actions = actionsRepository.getActionsFrom(Days(statsData.second))
+ forEach(stats_week to 7, stats_month to 30) { (view, days) ->
+ val actions: Actions = actionsRepository.actionsFrom(Days(days))
+
val cardsMastered =
actions.count { it.type is PracticeSubmission && it.type.isCorrect }
val hintsUsed = actions.count { it.type is PracticeHintAction }
val totalAttempts = actions.count { it.type is PracticeSubmission }
+ view.apply {
+ practice_mastered_cards.text = cardsMastered.toString()
+ practice_hints.text = hintsUsed.toString()
+ practice_total_attempts.text = totalAttempts.toString()
+ }
val theoryStepsPassed = actions.count { it.type is TheoryPassStep }
val theoryInputStepsPassed =
actions.count { it.type is TheoryPassStep && it.type.isInput }
-
- statsData.first.apply {
- practice_mastered_cards.text = """$cardsMastered"""
- practice_hints.text = """$hintsUsed"""
- practice_total_attempts.text = """$totalAttempts"""
-
- theory_steps_passed.text = """$theoryStepsPassed"""
- theory_input_steps_passed.text = """$theoryInputStepsPassed"""
+ view.apply {
+ theory_steps_passed.text = theoryStepsPassed.toString()
+ theory_input_steps_passed.text = theoryInputStepsPassed.toString()
}
}
}
+
}.root
override fun onDestroy() = super.onDestroy().also { job.cancel() }
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/TheoryFreeNavigation.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/TheoryFreeNavigation.kt
index d293e9f7..cf26d453 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/TheoryFreeNavigation.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/TheoryFreeNavigation.kt
@@ -49,7 +49,7 @@ fun AbstractStepFragment.toNextStep(
): Unit =
if (thisStep.data is LastInfo) Timber.w("Tying to access step after last")
else scope().launch {
- val nextStep = theoryRepository.getNextStepAndUpdate(thisStep, markThisAsPassed)
+ val nextStep = theoryRepository.nextStepAndMove(thisStep, markThisAsPassed)
if (nextStep != null) {
toStep(nextStep)
} else {
@@ -64,7 +64,7 @@ fun AbstractStepFragment.toPrevStep(
): Unit =
if (thisStep.data is FirstInfo) Timber.w("Trying to access step before first")
else scope().launch {
- theoryRepository.getPrevStepAndUpdate(thisStep)
+ theoryRepository.prevStepAndMove(thisStep)
?.let(::toStep)
?: error("Prev step should always exist")
}.devnull
@@ -73,7 +73,7 @@ fun AbstractStepFragment.toCurrentStep(
courseId: Long,
theoryRepository: MutableTheoryRepository = get()
): Unit = scope().launch {
- val currStep = theoryRepository.getCurrentStepAndUpdate(courseId)
+ val currStep = theoryRepository.currentStepAndMove(courseId)
toStep(currStep)
}.devnull
@@ -81,13 +81,13 @@ fun Fragment.toLastCourseStep(
courseId: Long,
theoryRepository: TheoryRepository = get()
): Unit = scope().launch {
- val lastStep = theoryRepository.getLastCourseStep(courseId)
+ val lastStep = theoryRepository.lastCourseStep(courseId)
toStep(lastStep)
}.devnull
fun Fragment.toLastLessonStep(
courseId: Long, lessonId: Long, theoryRepository: MutableTheoryRepository = get()
): Unit = scope().launch {
- val lastStep = theoryRepository.getLastLessonOrCurrentStepAndUpdate(courseId, lessonId)
+ val lastStep = theoryRepository.lastLessonOrCurrentStepAndMove(courseId, lessonId)
toStep(lastStep)
}.devnull
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/lessons/LessonsListFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/lessons/LessonsListFragment.kt
index d9ce8bab..2ea89c1b 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/lessons/LessonsListFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/lessons/LessonsListFragment.kt
@@ -1,6 +1,7 @@
package com.github.braillesystems.learnbraille.ui.screens.theory.lessons
import android.annotation.SuppressLint
+import android.graphics.Typeface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -41,8 +42,9 @@ class LessonsListFragment : Fragment() {
title = getString(R.string.lessons_title_lessons_list)
lifecycleScope.launch {
- val curr = theoryRepository.getCurrentStep(COURSE.id)
- val lessons = theoryRepository.getAllCourseLessons(COURSE.id)
+ val curr = theoryRepository.currentStep(COURSE.id)
+ val lessons = theoryRepository.allCourseLessons(COURSE.id)
+ val last = theoryRepository.lastCourseStep(curr.courseId)
val activeListener = object : LessonItemListener {
override fun onClick(item: Lesson) = toLastLessonStep(COURSE.id, item.id)
}
@@ -56,6 +58,11 @@ class LessonsListFragment : Fragment() {
val adapter = LessonsListAdapter(lessons) { item ->
lesson = item
lessonName.text = "${item.id}. ${item.name}"
+ lessonName.setTypeface(
+ lessonName.typeface,
+ if (item.id == last.lessonId) Typeface.BOLD
+ else Typeface.NORMAL
+ )
if (item.id <= curr.lessonId) {
clickListener = activeListener
lessonName.setTextColor(
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractInfoStepFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractInfoStepFragment.kt
deleted file mode 100644
index 31cf7165..00000000
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractInfoStepFragment.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
-
-import com.github.braillesystems.learnbraille.ui.screens.HelpMsgId
-
-abstract class AbstractInfoStepFragment(helpMsgId: HelpMsgId) : AbstractStepFragment(helpMsgId)
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractStepFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractStepFragment.kt
index 8f790d3b..dceb5ef1 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractStepFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/AbstractStepFragment.kt
@@ -1,26 +1,35 @@
package com.github.braillesystems.learnbraille.ui.screens.theory.steps
import android.text.method.ScrollingMovementMethod
-import android.util.TypedValue
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.widget.Button
import android.widget.TextView
-import androidx.core.text.parseAsHtml
+import androidx.databinding.ViewDataBinding
import com.github.braillesystems.learnbraille.COURSE
import com.github.braillesystems.learnbraille.R
import com.github.braillesystems.learnbraille.data.entities.Step
import com.github.braillesystems.learnbraille.data.repository.PreferenceRepository
import com.github.braillesystems.learnbraille.ui.screens.AbstractFragmentWithHelp
import com.github.braillesystems.learnbraille.ui.screens.HelpMsgId
+import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
import com.github.braillesystems.learnbraille.ui.screens.theory.toCurrentStep
import com.github.braillesystems.learnbraille.ui.screens.theory.toNextStep
import com.github.braillesystems.learnbraille.ui.screens.theory.toPrevStep
-import com.github.braillesystems.learnbraille.utils.*
+import com.github.braillesystems.learnbraille.ui.views.BrailleDotsView
+import com.github.braillesystems.learnbraille.utils.applyExtendedAccessibility
+import com.github.braillesystems.learnbraille.utils.navigate
+import com.github.braillesystems.learnbraille.utils.title
import org.koin.android.ext.android.inject
-import com.github.braillesystems.learnbraille.utils.updateTitle as utilUpdateTitle
+interface StepBinding {
+ val prevButton: Button? get() = null
+ val nextButton: Button? get() = null
+ val hintButton: Button? get() = null
+ val textView: TextView? get() = null
+ val brailleDots: BrailleDotsView? get() = null
+}
/**
* Base class for all steps.
@@ -28,62 +37,52 @@ import com.github.braillesystems.learnbraille.utils.updateTitle as utilUpdateTit
abstract class AbstractStepFragment(helpMsgId: HelpMsgId) : AbstractFragmentWithHelp(helpMsgId) {
protected val preferenceRepository: PreferenceRepository by inject()
+
protected lateinit var step: Step
+ private set
+
+ protected lateinit var stepBinding: StepBinding
+ private set
override val helpMsg: String
get() = getString(R.string.lessons_help_template).format(
super.helpMsg, getString(R.string.lessons_help_common)
)
- protected fun initialize(
- step: Step,
- prevButton: Button? = null,
- nextButton: Button? = null,
- hintButton: Button? = null
- ) {
- this.step = step
- setHasOptionsMenu(true)
- if (preferenceRepository.extendedAccessibilityEnabled) {
- prevButton?.setSize(
- width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
- )
- nextButton?.setSize(
- width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
- )
- hintButton?.setSize(
- width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
- )
- }
- }
+ protected fun B.init(
+ titleId: Int,
+ binding: B.() -> StepBinding
+ ): B = init(this, titleId, binding)
- protected fun setText(text: String, infoTextView: TextView) {
- infoTextView.text = text.parseAsHtml()
- infoTextView.movementMethod = ScrollingMovementMethod()
- checkedAnnounce(text)
- if (preferenceRepository.extendedAccessibilityEnabled) {
- infoTextView.setTextSize(
- TypedValue.COMPLEX_UNIT_SP,
- application.extendedTextSize
- )
- }
- }
+ protected open fun init(
+ b: B,
+ titleId: Int,
+ binding: B.() -> StepBinding
+ ): B = b.apply {
+ setHasOptionsMenu(true)
- protected fun updateTitle(msg: String) {
- utilUpdateTitle(
- if (preferenceRepository.extendedAccessibilityEnabled) "${step.lessonId} ${step.id} $msg"
- else "${step.lessonId}.${step.id} $msg"
- )
- }
+ step = getStepArg()
+ stepBinding = binding()
- protected fun setNextButton(button: Button) {
- button.setOnClickListener {
- toNextStep(step, markThisAsPassed = true)
+ val msg = getString(titleId)
+ title = if (preferenceRepository.extendedAccessibilityEnabled) {
+ "${step.lessonId} ${step.id} $msg"
+ } else {
+ "${step.lessonId}.${step.id} $msg"
}
- }
- protected fun setPrevButton(button: Button) {
- button.setOnClickListener {
- toPrevStep(step)
+ stepBinding.run {
+ if (preferenceRepository.extendedAccessibilityEnabled) {
+ applyExtendedAccessibility(
+ leftButton = prevButton,
+ rightButton = nextButton,
+ leftMiddleButton = hintButton,
+ textView = textView
+ )
+ }
+ prevButton?.setOnClickListener { toPrevStep(step) }
+ nextButton?.setOnClickListener { toNextStep(step, markThisAsPassed = true) }
+ textView?.movementMethod = ScrollingMovementMethod()
}
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputDotsFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputDotsFragment.kt
deleted file mode 100644
index 2d0cd0ee..00000000
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputDotsFragment.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
-
-import android.os.Bundle
-import android.os.Vibrator
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.content.getSystemService
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.ViewModelProvider
-import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.BrailleDots
-import com.github.braillesystems.learnbraille.data.entities.InputDots
-import com.github.braillesystems.learnbraille.data.entities.spelling
-import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputDotsBinding
-import com.github.braillesystems.learnbraille.ui.screens.observeCheckedOnFly
-import com.github.braillesystems.learnbraille.ui.screens.observeEventHint
-import com.github.braillesystems.learnbraille.ui.screens.observeEventIncorrect
-import com.github.braillesystems.learnbraille.ui.screens.observeEventPassHint
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
-import com.github.braillesystems.learnbraille.ui.screens.theory.toNextStep
-import com.github.braillesystems.learnbraille.ui.screens.theory.toPrevStep
-import com.github.braillesystems.learnbraille.ui.showCorrectToast
-import com.github.braillesystems.learnbraille.ui.showHintDotsToast
-import com.github.braillesystems.learnbraille.ui.showIncorrectToast
-import com.github.braillesystems.learnbraille.ui.views.*
-import com.github.braillesystems.learnbraille.utils.application
-import com.github.braillesystems.learnbraille.utils.checkedAnnounce
-import com.github.braillesystems.learnbraille.utils.checkedBuzz
-import timber.log.Timber
-
-class InputDotsFragment : AbstractStepFragment(R.string.lessons_help_input_dots) {
-
- private lateinit var expectedDots: BrailleDots
- private lateinit var dotsState: BrailleDotsState
- private var userTouchedDots: Boolean = false
- private var buzzer: Vibrator? = null
- private lateinit var viewModel: InputViewModel
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ) = DataBindingUtil.inflate(
- inflater,
- R.layout.fragment_lessons_input_dots,
- container,
- false
- ).apply {
-
- Timber.i("Start initialize input dots fragment")
-
- val step = getStepArg()
- require(step.data is InputDots)
- initialize(step, prevButton, nextButton, hintButton)
-
- val infoText = step.data.text
- ?: getString(R.string.lessons_show_dots_info_template).format(step.data.dots.spelling)
- setText(
- text = infoText,
- infoTextView = infoTextView
- )
- checkedAnnounce(infoText)
- brailleDots.dotsState.display(step.data.dots)
-
- updateTitle(getString(R.string.lessons_title_input_dots))
-
- expectedDots = step.data.dots
- userTouchedDots = false
- dotsState = brailleDots.dotsState.apply {
- uncheck()
- clickable(true)
- subscribe(View.OnClickListener {
- userTouchedDots = true
- viewModel.onSoftCheck()
- })
- }
-
-
- val viewModelFactory = InputViewModelFactory(application, expectedDots) {
- dotsState.brailleDots
- }
- viewModel = ViewModelProvider(
- this@InputDotsFragment, viewModelFactory
- ).get(InputViewModel::class.java)
- buzzer = activity?.getSystemService()
-
-
- inputViewModel = viewModel
- lifecycleOwner = this@InputDotsFragment
-
-
- prevButton.setOnClickListener {
- toPrevStep(step)
- }
-
- viewModel.observeCheckedOnFly(
- viewLifecycleOwner, dotsState, buzzer,
- block = { toNextStep(step, markThisAsPassed = true) },
- softBlock = ::showCorrectToast
- )
-
- viewModel.observeEventIncorrect(
- viewLifecycleOwner, dotsState
- ) {
- val notify = {
- showIncorrectToast()
- buzzer.checkedBuzz(preferenceRepository.incorrectBuzzPattern, preferenceRepository)
- }
- if (userTouchedDots) notify()
- else toNextStep(step, markThisAsPassed = false) { notify() }
- }
-
- viewModel.observeEventHint(
- viewLifecycleOwner, dotsState
- ) {
- showHintDotsToast(expectedDots)
- userTouchedDots = true
- }
-
- viewModel.observeEventPassHint(
- viewLifecycleOwner, dotsState
- )
-
- }.root
-}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputMarkerFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputMarkerFragment.kt
deleted file mode 100644
index f793ae5e..00000000
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputMarkerFragment.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
-
-import android.os.Bundle
-import android.os.Vibrator
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.content.getSystemService
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.ViewModelProvider
-import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.BrailleDots
-import com.github.braillesystems.learnbraille.data.entities.Input
-import com.github.braillesystems.learnbraille.data.entities.MarkerSymbol
-import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputMarkerBinding
-import com.github.braillesystems.learnbraille.res.inputMarkerPrintRules
-import com.github.braillesystems.learnbraille.ui.screens.observeCheckedOnFly
-import com.github.braillesystems.learnbraille.ui.screens.observeEventHint
-import com.github.braillesystems.learnbraille.ui.screens.observeEventIncorrect
-import com.github.braillesystems.learnbraille.ui.screens.observeEventPassHint
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
-import com.github.braillesystems.learnbraille.ui.screens.theory.toNextStep
-import com.github.braillesystems.learnbraille.ui.screens.theory.toPrevStep
-import com.github.braillesystems.learnbraille.ui.showCorrectToast
-import com.github.braillesystems.learnbraille.ui.showHintToast
-import com.github.braillesystems.learnbraille.ui.showIncorrectToast
-import com.github.braillesystems.learnbraille.ui.views.*
-import com.github.braillesystems.learnbraille.utils.*
-import timber.log.Timber
-
-class InputMarkerFragment : AbstractStepFragment(R.string.lessons_help_input_marker) {
-
- private lateinit var expectedDots: BrailleDots
- private lateinit var dotsState: BrailleDotsState
- private var userTouchedDots: Boolean = false
- private var buzzer: Vibrator? = null
- private lateinit var viewModel: InputViewModel
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ) = DataBindingUtil.inflate(
- inflater,
- R.layout.fragment_lessons_input_marker,
- container,
- false
- ).also { binding ->
-
- Timber.i("Start initialize input dots fragment")
-
- val step = getStepArg()
- require(step.data is Input)
- initialize(
- step,
- binding.prevButton,
- binding.nextButton,
- binding.hintButton
- )
-
- val data = step.data.material.data
- require(data is MarkerSymbol)
- val infoText = contextNotNull.inputMarkerPrintRules[data.type]
- ?: error("No input print rules for marker: ${data.type}")
- setText(
- text = infoText,
- infoTextView = binding.infoTextView
- )
- checkedAnnounce(infoText)
- binding.brailleDots.dotsState.display(data.brailleDots)
-
- updateTitle(getString(R.string.lessons_title_input_symbol))
-
- expectedDots = data.brailleDots
- userTouchedDots = false
- dotsState = binding.brailleDots.dotsState.apply {
- uncheck()
- clickable(true)
- subscribe(View.OnClickListener {
- userTouchedDots = true
- viewModel.onSoftCheck()
- })
- }
-
-
- val viewModelFactory = InputViewModelFactory(application, expectedDots) {
- dotsState.brailleDots
- }
- viewModel = ViewModelProvider(
- this@InputMarkerFragment, viewModelFactory
- ).get(InputViewModel::class.java)
- buzzer = activity?.getSystemService()
-
-
- binding.inputViewModel = viewModel
- binding.lifecycleOwner = this@InputMarkerFragment
-
-
- binding.prevButton.setOnClickListener {
- toPrevStep(step)
- }
-
- viewModel.observeCheckedOnFly(
- viewLifecycleOwner, dotsState, buzzer,
- block = { toNextStep(step, markThisAsPassed = true) },
- softBlock = ::showCorrectToast
- )
-
- viewModel.observeEventIncorrect(
- viewLifecycleOwner, dotsState
- ) {
- val notify = {
- showIncorrectToast()
- buzzer.checkedBuzz(preferenceRepository.incorrectBuzzPattern, preferenceRepository)
- }
- if (userTouchedDots) notify()
- else toNextStep(step, markThisAsPassed = false) { notify() }
- }
-
- viewModel.observeEventHint(
- viewLifecycleOwner, dotsState
- ) {
- showHintToast(expectedDots)
- userTouchedDots = true
- }
-
- viewModel.observeEventPassHint(
- viewLifecycleOwner, dotsState
- )
-
- }.root
-}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputSymbolFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputSymbolFragment.kt
deleted file mode 100644
index dccb83d1..00000000
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputSymbolFragment.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
-
-import android.os.Bundle
-import android.os.Vibrator
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.content.getSystemService
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.ViewModelProvider
-import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.BrailleDots
-import com.github.braillesystems.learnbraille.data.entities.Input
-import com.github.braillesystems.learnbraille.data.entities.Symbol
-import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputSymbolBinding
-import com.github.braillesystems.learnbraille.res.captionRules
-import com.github.braillesystems.learnbraille.ui.*
-import com.github.braillesystems.learnbraille.ui.screens.observeCheckedOnFly
-import com.github.braillesystems.learnbraille.ui.screens.observeEventHint
-import com.github.braillesystems.learnbraille.ui.screens.observeEventIncorrect
-import com.github.braillesystems.learnbraille.ui.screens.observeEventPassHint
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
-import com.github.braillesystems.learnbraille.ui.screens.theory.toNextStep
-import com.github.braillesystems.learnbraille.ui.screens.theory.toPrevStep
-import com.github.braillesystems.learnbraille.ui.views.*
-import com.github.braillesystems.learnbraille.utils.*
-import timber.log.Timber
-
-class InputSymbolFragment : AbstractStepFragment(R.string.lessons_help_input_symbol) {
-
- private lateinit var expectedDots: BrailleDots
- private lateinit var dotsState: BrailleDotsState
- private var userTouchedDots: Boolean = false
- private var buzzer: Vibrator? = null
- private lateinit var viewModel: InputViewModel
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ) = DataBindingUtil.inflate(
- inflater,
- R.layout.fragment_lessons_input_symbol,
- container,
- false
- ).apply {
-
- Timber.i("Initialize input symbol fragment")
-
- val step = getStepArg()
- require(step.data is Input)
- initialize(step, prevButton, nextButton, hintButton)
-
- require(step.data.material.data is Symbol)
- val symbol = step.data.material.data
- letter.text = symbol.char.toString()
- letterCaption.text = captionRules.getValue(symbol)
- brailleDots.dotsState.display(symbol.brailleDots)
- checkedAnnounce(printStringNotNullLogged(symbol.char, PrintMode.INPUT))
-
- updateTitle(getString(R.string.lessons_title_input_symbol))
-
- expectedDots = symbol.brailleDots
- userTouchedDots = false
- dotsState = brailleDots.dotsState.apply {
- uncheck()
- clickable(true)
- subscribe(View.OnClickListener {
- userTouchedDots = true
- viewModel.onSoftCheck()
- })
- }
-
-
- val viewModelFactory = InputViewModelFactory(application, expectedDots) {
- dotsState.brailleDots
- }
- viewModel = ViewModelProvider(
- this@InputSymbolFragment, viewModelFactory
- ).get(InputViewModel::class.java)
- buzzer = activity?.getSystemService()
-
-
- inputViewModel = viewModel
- lifecycleOwner = this@InputSymbolFragment
-
-
- prevButton.setOnClickListener {
- toPrevStep(step)
- }
-
- viewModel.observeCheckedOnFly(
- viewLifecycleOwner, dotsState, buzzer,
- block = { toNextStep(step, markThisAsPassed = true) },
- softBlock = ::showCorrectToast
- )
-
- viewModel.observeEventIncorrect(
- viewLifecycleOwner, dotsState
- ) {
- val notify = {
- showIncorrectToast(symbol.char)
- buzzer.checkedBuzz(preferenceRepository.incorrectBuzzPattern, preferenceRepository)
- }
- if (userTouchedDots) notify()
- else toNextStep(step, markThisAsPassed = false) { notify() }
- }
-
- viewModel.observeEventHint(
- viewLifecycleOwner, dotsState
- ) {
- showHintToast(expectedDots)
- userTouchedDots = true
- }
-
- viewModel.observeEventPassHint(
- viewLifecycleOwner, dotsState
- ) {
- val msg = printStringNotNullLogged(symbol.char, PrintMode.INPUT)
- announce(msg)
- }
-
- }.root
-}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/AbstractInfoStepFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/AbstractInfoStepFragment.kt
new file mode 100644
index 00000000..817833e3
--- /dev/null
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/AbstractInfoStepFragment.kt
@@ -0,0 +1,21 @@
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.info
+
+import androidx.core.text.parseAsHtml
+import com.github.braillesystems.learnbraille.data.entities.BaseInfo
+import com.github.braillesystems.learnbraille.ui.screens.HelpMsgId
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.AbstractStepFragment
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
+import com.github.braillesystems.learnbraille.utils.checkedAnnounce
+
+abstract class AbstractInfoStepFragment(helpMsgId: HelpMsgId) : AbstractStepFragment(helpMsgId) {
+
+ override fun init(b: B, titleId: Int, binding: B.() -> StepBinding): B =
+ super
+ .init(b, titleId, binding)
+ .also {
+ val data = step.data
+ require(data is BaseInfo)
+ stepBinding.textView?.text = data.text.parseAsHtml()
+ checkedAnnounce(data.text)
+ }
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/FirstInfoFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/FirstInfoFragment.kt
similarity index 66%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/FirstInfoFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/FirstInfoFragment.kt
index 4728d261..67e5f5d8 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/FirstInfoFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/FirstInfoFragment.kt
@@ -1,13 +1,14 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.info
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.FirstInfo
import com.github.braillesystems.learnbraille.databinding.FragmentLessonFirstInfoBinding
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
class FirstInfoFragment : AbstractInfoStepFragment(R.string.lessons_help_info) {
@@ -20,14 +21,13 @@ class FirstInfoFragment : AbstractInfoStepFragment(R.string.lessons_help_info) {
R.layout.fragment_lesson_first_info,
container,
false
- ).apply {
-
- val step = getStepArg()
- require(step.data is FirstInfo)
- initialize(step, null, nextButton)
- updateTitle(getString(R.string.lessons_title_info))
- setText(step.data.text, infoTextView)
- setNextButton(nextButton)
-
- }.root
+ ).init(
+ titleId = R.string.lessons_title_info,
+ binding = {
+ object : StepBinding {
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ }
+ }
+ ).root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InfoFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/InfoFragment.kt
similarity index 62%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InfoFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/InfoFragment.kt
index 1f13ca98..476dc8ba 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InfoFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/InfoFragment.kt
@@ -1,13 +1,14 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.info
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.Info
import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInfoBinding
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
class InfoFragment : AbstractInfoStepFragment(R.string.lessons_help_info) {
@@ -20,15 +21,14 @@ class InfoFragment : AbstractInfoStepFragment(R.string.lessons_help_info) {
R.layout.fragment_lessons_info,
container,
false
- ).apply {
-
- val step = getStepArg()
- require(step.data is Info)
- initialize(step, prevButton, nextButton)
- updateTitle(getString(R.string.lessons_title_info))
- setText(step.data.text, infoTextView)
- setPrevButton(prevButton)
- setNextButton(nextButton)
-
- }.root
+ ).init(
+ titleId = R.string.lessons_title_info,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ }
+ }
+ ).root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/LastInfoFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/LastInfoFragment.kt
similarity index 66%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/LastInfoFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/LastInfoFragment.kt
index bd372c30..e72486b9 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/LastInfoFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/info/LastInfoFragment.kt
@@ -1,13 +1,14 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.info
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.entities.LastInfo
import com.github.braillesystems.learnbraille.databinding.FragmentLessonLastInfoBinding
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
class LastInfoFragment : AbstractInfoStepFragment(R.string.lessons_help_last_info) {
@@ -20,14 +21,13 @@ class LastInfoFragment : AbstractInfoStepFragment(R.string.lessons_help_last_inf
R.layout.fragment_lesson_last_info,
container,
false
- ).apply {
-
- val step = getStepArg()
- require(step.data is LastInfo)
- initialize(step, prevButton, null)
- updateTitle(getString(R.string.lessons_title_last_info))
- setText(step.data.text, infoTextView)
- setPrevButton(prevButton)
-
- }.root
+ ).init(
+ titleId = R.string.lessons_title_last_info,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val textView: TextView? = this@init.infoTextView
+ }
+ }
+ ).root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/AbstractInputStepFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/AbstractInputStepFragment.kt
new file mode 100644
index 00000000..a2f27f05
--- /dev/null
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/AbstractInputStepFragment.kt
@@ -0,0 +1,94 @@
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.input
+
+import android.os.Vibrator
+import android.view.View
+import androidx.core.content.getSystemService
+import androidx.lifecycle.ViewModelProvider
+import com.github.braillesystems.learnbraille.data.entities.BaseInput
+import com.github.braillesystems.learnbraille.data.entities.StepData
+import com.github.braillesystems.learnbraille.ui.screens.*
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.AbstractStepFragment
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
+import com.github.braillesystems.learnbraille.ui.screens.theory.toNextStep
+import com.github.braillesystems.learnbraille.ui.showCorrectToast
+import com.github.braillesystems.learnbraille.ui.showHintToast
+import com.github.braillesystems.learnbraille.ui.showIncorrectToast
+import com.github.braillesystems.learnbraille.ui.views.*
+import com.github.braillesystems.learnbraille.utils.application
+import com.github.braillesystems.learnbraille.utils.checkedBuzz
+
+abstract class AbstractInputStepFragment(helpMsgId: HelpMsgId) : AbstractStepFragment(helpMsgId) {
+
+ // This value can change during ViewModel lifetime (ViewModelProvider does not call
+ // ViewModelFactory each time onCreateView runs). And once created ViewModel
+ // should be able to use up to date dotsState.
+ private lateinit var dotsState: BrailleDotsState
+
+ protected lateinit var viewModel: InputViewModel
+ private set
+
+ override fun init(b: B, titleId: Int, binding: B.() -> StepBinding): B =
+ super.init(b, titleId, binding).also {
+ val data = step.data
+ require(data is BaseInput)
+ val expectedDots = data.brailleDots
+
+ var userTouchedDots = false
+
+ dotsState = stepBinding.brailleDots!!.dotsState.apply {
+ uncheck()
+ clickable(true)
+ subscribe(View.OnClickListener {
+ viewModel.onSoftCheck()
+ userTouchedDots = true
+ })
+ }
+
+ val viewModelFactory = InputViewModelFactory(
+ application, expectedDots
+ ) { dotsState.brailleDots }
+ viewModel = ViewModelProvider(this, viewModelFactory)
+ .get(InputViewModel::class.java)
+
+ val buzzer: Vibrator? = activity?.getSystemService()
+
+ viewModel.observeCheckedOnFly(
+ viewLifecycleOwner, dotsState, buzzer,
+ block = { toNextStep(step, markThisAsPassed = true) },
+ softBlock = { showCorrectToast() }
+ )
+
+ viewModel.observeEventHint(
+ viewLifecycleOwner, dotsState
+ ) {
+ showHintToast(expectedDots)
+ userTouchedDots = true
+ }
+
+ viewModel.observeEventIncorrect(
+ viewLifecycleOwner, dotsState
+ ) {
+ fun notify() {
+ toastIncorrect(data)
+ buzzer.checkedBuzz(
+ preferenceRepository.incorrectBuzzPattern,
+ preferenceRepository
+ )
+ }
+ if (userTouchedDots) notify()
+ else toNextStep(step, markThisAsPassed = false) { notify() }
+ }
+
+ viewModel.observeEventPassHint(
+ viewLifecycleOwner, dotsState
+ ) {
+ onPassHint(data)
+ }
+ }
+
+ protected open fun toastIncorrect(data: StepData) {
+ showIncorrectToast()
+ }
+
+ protected open fun onPassHint(data: StepData) = Unit
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputDotsFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputDotsFragment.kt
new file mode 100644
index 00000000..ce0e3990
--- /dev/null
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputDotsFragment.kt
@@ -0,0 +1,51 @@
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.input
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.databinding.DataBindingUtil
+import com.github.braillesystems.learnbraille.R
+import com.github.braillesystems.learnbraille.data.entities.InputDots
+import com.github.braillesystems.learnbraille.data.entities.spelling
+import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputDotsBinding
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
+import com.github.braillesystems.learnbraille.ui.views.BrailleDotsView
+import com.github.braillesystems.learnbraille.utils.checkedAnnounce
+
+class InputDotsFragment : AbstractInputStepFragment(R.string.lessons_help_input_dots) {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = DataBindingUtil.inflate(
+ inflater,
+ R.layout.fragment_lessons_input_dots,
+ container,
+ false
+ ).init(
+ titleId = R.string.lessons_title_input_dots,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ override val brailleDots: BrailleDotsView? = this@init.brailleDots
+ }
+ }
+ ).apply {
+
+ val data = step.data
+ require(data is InputDots)
+ val text = data.text
+ ?: getString(R.string.lessons_show_dots_info_template).format(data.brailleDots.spelling)
+ infoTextView.text = text
+ checkedAnnounce(text)
+
+ inputViewModel = viewModel
+ lifecycleOwner = this@InputDotsFragment
+
+ }.root
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputMarkerFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputMarkerFragment.kt
new file mode 100644
index 00000000..095098e5
--- /dev/null
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputMarkerFragment.kt
@@ -0,0 +1,54 @@
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.input
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.databinding.DataBindingUtil
+import com.github.braillesystems.learnbraille.R
+import com.github.braillesystems.learnbraille.data.entities.Input
+import com.github.braillesystems.learnbraille.data.entities.MarkerSymbol
+import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputMarkerBinding
+import com.github.braillesystems.learnbraille.res.inputMarkerPrintRules
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
+import com.github.braillesystems.learnbraille.ui.views.BrailleDotsView
+import com.github.braillesystems.learnbraille.utils.checkedAnnounce
+import com.github.braillesystems.learnbraille.utils.getValue
+
+class InputMarkerFragment : AbstractInputStepFragment(R.string.lessons_help_input_marker) {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = DataBindingUtil.inflate(
+ inflater,
+ R.layout.fragment_lessons_input_marker,
+ container,
+ false
+ ).init(
+ titleId = R.string.lessons_title_input_symbol,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ override val brailleDots: BrailleDotsView? = this@init.brailleDots
+ }
+ }
+ ).apply {
+
+ val stepData = step.data
+ require(stepData is Input)
+ val data = stepData.material.data
+ require(data is MarkerSymbol)
+ val text = inputMarkerPrintRules.getValue(data.type)
+ infoTextView.text = text
+ checkedAnnounce(text)
+
+ inputViewModel = viewModel
+ lifecycleOwner = this@InputMarkerFragment
+
+ }.root
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputSymbolFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputSymbolFragment.kt
new file mode 100644
index 00000000..0c771c20
--- /dev/null
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputSymbolFragment.kt
@@ -0,0 +1,69 @@
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.input
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.Button
+import androidx.databinding.DataBindingUtil
+import com.github.braillesystems.learnbraille.R
+import com.github.braillesystems.learnbraille.data.entities.Input
+import com.github.braillesystems.learnbraille.data.entities.StepData
+import com.github.braillesystems.learnbraille.data.entities.Symbol
+import com.github.braillesystems.learnbraille.databinding.FragmentLessonsInputSymbolBinding
+import com.github.braillesystems.learnbraille.res.captionRules
+import com.github.braillesystems.learnbraille.res.inputSymbolPrintRules
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
+import com.github.braillesystems.learnbraille.ui.showIncorrectToast
+import com.github.braillesystems.learnbraille.ui.views.BrailleDotsView
+import com.github.braillesystems.learnbraille.utils.checkedAnnounce
+import com.github.braillesystems.learnbraille.utils.getValue
+
+class InputSymbolFragment : AbstractInputStepFragment(R.string.lessons_help_input_symbol) {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = DataBindingUtil.inflate(
+ inflater,
+ R.layout.fragment_lessons_input_symbol,
+ container,
+ false
+ ).init(
+ titleId = R.string.lessons_title_input_symbol,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val brailleDots: BrailleDotsView? = this@init.brailleDots
+ }
+ }
+ ).apply {
+
+ val stepData = step.data
+ require(stepData is Input)
+ val data = stepData.material.data
+ require(data is Symbol)
+ letter.letter = data.char
+ letterCaption.text = captionRules.getValue(data)
+ checkedAnnounce(inputSymbolPrintRules.getValue(data.char))
+
+ inputViewModel = viewModel
+ lifecycleOwner = this@InputSymbolFragment
+
+ }.root
+
+ private fun StepData.char(): Char {
+ require(this is Input)
+ require(material.data is Symbol)
+ return material.data.char
+ }
+
+ override fun toastIncorrect(data: StepData) {
+ showIncorrectToast(inputSymbolPrintRules.getValue(data.char()))
+ }
+
+ override fun onPassHint(data: StepData) {
+ checkedAnnounce(inputSymbolPrintRules.getValue(data.char()))
+ }
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputViewModel.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputViewModel.kt
similarity index 99%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputViewModel.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputViewModel.kt
index 0c4bb192..c33748ad 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/InputViewModel.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/input/InputViewModel.kt
@@ -1,4 +1,4 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.input
import android.app.Application
import androidx.lifecycle.AndroidViewModel
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowDotsFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowDotsFragment.kt
similarity index 60%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowDotsFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowDotsFragment.kt
index 480f55a7..e07f5545 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowDotsFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowDotsFragment.kt
@@ -1,18 +1,20 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.show
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
import com.github.braillesystems.learnbraille.data.entities.ShowDots
import com.github.braillesystems.learnbraille.data.entities.spelling
import com.github.braillesystems.learnbraille.databinding.FragmentLessonsShowDotsBinding
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.AbstractStepFragment
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
import com.github.braillesystems.learnbraille.ui.views.display
import com.github.braillesystems.learnbraille.ui.views.dotsState
import com.github.braillesystems.learnbraille.utils.checkedAnnounce
-import timber.log.Timber
class ShowDotsFragment : AbstractStepFragment(R.string.lessons_help_show_dots) {
@@ -25,26 +27,25 @@ class ShowDotsFragment : AbstractStepFragment(R.string.lessons_help_show_dots) {
R.layout.fragment_lessons_show_dots,
container,
false
+ ).init(
+ titleId = R.string.lessons_title_show_dots,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ }
+ }
).apply {
- Timber.i("Initialize show dots fragment")
+ val data = step.data
+ require(data is ShowDots)
- val step = getStepArg()
- require(step.data is ShowDots)
- initialize(step, prevButton, nextButton)
-
- val infoText = step.data.text
- ?: getString(R.string.lessons_show_dots_info_template).format(step.data.dots.spelling)
- setText(
- text = infoText,
- infoTextView = infoTextView
- )
- checkedAnnounce(infoText)
- brailleDots.dotsState.display(step.data.dots)
-
- updateTitle(getString(R.string.lessons_title_show_dots))
- setPrevButton(prevButton)
- setNextButton(nextButton)
+ val text = data.text
+ ?: getString(R.string.lessons_show_dots_info_template).format(data.brailleDots.spelling)
+ infoTextView.text = text
+ checkedAnnounce(text)
+ brailleDots.dotsState.display(data.brailleDots)
}.root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowMarkerFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowMarkerFragment.kt
similarity index 55%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowMarkerFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowMarkerFragment.kt
index 4e02bb61..d56361ca 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowMarkerFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowMarkerFragment.kt
@@ -1,21 +1,24 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.show
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.core.text.parseAsHtml
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
import com.github.braillesystems.learnbraille.data.entities.MarkerSymbol
import com.github.braillesystems.learnbraille.data.entities.Show
import com.github.braillesystems.learnbraille.databinding.FragmentLessonsShowMarkerBinding
import com.github.braillesystems.learnbraille.res.showMarkerPrintRules
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.AbstractStepFragment
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
import com.github.braillesystems.learnbraille.ui.views.display
import com.github.braillesystems.learnbraille.ui.views.dotsState
import com.github.braillesystems.learnbraille.utils.checkedAnnounce
-import com.github.braillesystems.learnbraille.utils.contextNotNull
-import com.github.braillesystems.learnbraille.utils.get
-import timber.log.Timber
+import com.github.braillesystems.learnbraille.utils.getValue
+import com.github.braillesystems.learnbraille.utils.removeHtmlMarkup
class ShowMarkerFragment : AbstractStepFragment(R.string.lessons_help_show_marker) {
@@ -28,28 +31,26 @@ class ShowMarkerFragment : AbstractStepFragment(R.string.lessons_help_show_marke
R.layout.fragment_lessons_show_marker,
container,
false
- ).also { binding ->
-
- Timber.i("Initialize show marker fragment")
-
- val step = getStepArg()
- require(step.data is Show)
- initialize(step, binding.prevButton, binding.nextButton)
-
- val data = step.data.material.data
+ ).init(
+ titleId = R.string.lessons_title_show_symbol,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ override val textView: TextView? = this@init.infoTextView
+ }
+ }
+ ).apply {
+
+ val stepData = step.data
+ require(stepData is Show)
+ val data = stepData.material.data
require(data is MarkerSymbol)
- val infoText = contextNotNull.showMarkerPrintRules[data.type]
- ?: error("No show print rules for marker: ${data.type}")
- setText(
- text = infoText,
- infoTextView = binding.infoTextView
- )
- checkedAnnounce(infoText)
- binding.brailleDots.dotsState.display(data.brailleDots)
- updateTitle(getString(R.string.lessons_title_show_symbol))
- setPrevButton(binding.prevButton)
- setNextButton(binding.nextButton)
+ val text = showMarkerPrintRules.getValue(data.type)
+ infoTextView.text = text
+ checkedAnnounce(text)
+ brailleDots.dotsState.display(data.brailleDots)
}.root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowSymbolFragment.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowSymbolFragment.kt
similarity index 59%
rename from app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowSymbolFragment.kt
rename to app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowSymbolFragment.kt
index caa8cdf1..2fd90fc1 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/ShowSymbolFragment.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/screens/theory/steps/show/ShowSymbolFragment.kt
@@ -1,22 +1,22 @@
-package com.github.braillesystems.learnbraille.ui.screens.theory.steps
+package com.github.braillesystems.learnbraille.ui.screens.theory.steps.show
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
+import android.widget.Button
import androidx.databinding.DataBindingUtil
import com.github.braillesystems.learnbraille.R
import com.github.braillesystems.learnbraille.data.entities.Show
import com.github.braillesystems.learnbraille.data.entities.Symbol
import com.github.braillesystems.learnbraille.databinding.FragmentLessonsShowSymbolBinding
import com.github.braillesystems.learnbraille.res.captionRules
-import com.github.braillesystems.learnbraille.ui.PrintMode
-import com.github.braillesystems.learnbraille.ui.printStringNotNullLogged
-import com.github.braillesystems.learnbraille.ui.screens.theory.getStepArg
+import com.github.braillesystems.learnbraille.res.showSymbolPrintRules
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.AbstractStepFragment
+import com.github.braillesystems.learnbraille.ui.screens.theory.steps.StepBinding
import com.github.braillesystems.learnbraille.ui.views.display
import com.github.braillesystems.learnbraille.ui.views.dotsState
import com.github.braillesystems.learnbraille.utils.checkedAnnounce
import com.github.braillesystems.learnbraille.utils.getValue
-import timber.log.Timber
class ShowSymbolFragment : AbstractStepFragment(R.string.lessons_help_show_symbol) {
@@ -29,25 +29,25 @@ class ShowSymbolFragment : AbstractStepFragment(R.string.lessons_help_show_symbo
R.layout.fragment_lessons_show_symbol,
container,
false
+ ).init(
+ titleId = R.string.lessons_title_show_symbol,
+ binding = {
+ object : StepBinding {
+ override val prevButton: Button? = this@init.prevButton
+ override val nextButton: Button? = this@init.nextButton
+ }
+ }
).apply {
- Timber.i("onCreateView")
-
- val step = getStepArg()
- require(step.data is Show)
- initialize(step, prevButton, nextButton)
-
- step.data.material.apply {
- require(data is Symbol)
- letter.text = data.char.toString()
- letterCaption.text = captionRules.getValue(data)
- brailleDots.dotsState.display(data.brailleDots)
- checkedAnnounce(printStringNotNullLogged(data.char, PrintMode.SHOW))
- }
+ val stepData = step.data
+ require(stepData is Show)
+ val data = stepData.material.data
+ require(data is Symbol)
- updateTitle(getString(R.string.lessons_title_show_symbol))
- setPrevButton(prevButton)
- setNextButton(nextButton)
+ letter.letter = data.char
+ letterCaption.text = captionRules.getValue(data)
+ checkedAnnounce(showSymbolPrintRules.getValue(data.char))
+ brailleDots.dotsState.display(data.brailleDots)
}.root
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/ui/views/BigLetterView.kt b/app/src/main/java/com/github/braillesystems/learnbraille/ui/views/BigLetterView.kt
index e6b908b2..8f12990e 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/ui/views/BigLetterView.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/ui/views/BigLetterView.kt
@@ -4,9 +4,9 @@ import android.content.Context
import android.util.AttributeSet
import android.widget.TextView
import androidx.core.widget.addTextChangedListener
-import com.github.braillesystems.learnbraille.ui.PrintMode
-import com.github.braillesystems.learnbraille.ui.printString
-import timber.log.Timber
+import com.github.braillesystems.learnbraille.res.inputSymbolPrintRules
+import com.github.braillesystems.learnbraille.res.showSymbolPrintRules
+import com.github.braillesystems.learnbraille.utils.getValue
open class BigLetterView : TextView {
@@ -20,16 +20,16 @@ open class BigLetterView : TextView {
context, attrSet, defStyleAttr
)
- protected fun addContextListener(mode: PrintMode) {
+ var letter: Char
+ get() = super.getText().first()
+ set(value) = super.setText(value.toString())
+
+ protected fun addContextListener(hintGetter: Context.(Char) -> String) {
addTextChangedListener(
afterTextChanged = { text ->
if (text == null) return@addTextChangedListener
require(text.length == 1)
- contentDescription = context
- .printString(text.first(), mode)
- ?: text.first().toLowerCase().toString().also {
- Timber.e("Symbol intro not found: $text")
- }
+ contentDescription = context.hintGetter(text.first())
}
)
}
@@ -48,7 +48,9 @@ class InputBigLetterView : BigLetterView {
)
init {
- addContextListener(PrintMode.INPUT)
+ addContextListener { c ->
+ inputSymbolPrintRules.getValue(c)
+ }
}
}
@@ -65,6 +67,8 @@ class ShowBigLetterView : BigLetterView {
)
init {
- addContextListener(PrintMode.SHOW)
+ addContextListener { c ->
+ showSymbolPrintRules.getValue(c)
+ }
}
}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/utils/SpeechRecognition.kt b/app/src/main/java/com/github/braillesystems/learnbraille/utils/SpeechRecognition.kt
deleted file mode 100644
index 20348382..00000000
--- a/app/src/main/java/com/github/braillesystems/learnbraille/utils/SpeechRecognition.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.github.braillesystems.learnbraille.utils
-
-import android.content.Intent
-import android.os.Bundle
-import android.speech.RecognitionListener
-import android.speech.RecognizerIntent
-import android.speech.SpeechRecognizer
-import android.speech.tts.TextToSpeech
-import android.speech.tts.UtteranceProgressListener
-import androidx.fragment.app.Fragment
-import com.github.braillesystems.learnbraille.R
-import com.github.braillesystems.learnbraille.data.repository.PreferenceRepository
-import timber.log.Timber
-import java.util.*
-import kotlin.collections.HashMap
-import kotlin.collections.set
-import kotlin.system.exitProcess
-
-// TODO refactor
-
-class SpeechRecognition(
- private val fragment: Fragment,
- private val preferenceRepository: PreferenceRepository
-) {
-
- private var mostRecentUtteranceID: String? = null
- private lateinit var mTTs: TextToSpeech
- private var mSpeechRecognizer: SpeechRecognizer? = null
- private var mSpeechRecognizerIntent: Intent? = null
-
- init {
- runIf(preferenceRepository.speechRecognitionEnabled) {
- try {
- initialize()
- } catch (e: Throwable) {
- Timber.e(e)
- }
- }
- }
-
- private fun initialize() = fragment.apply {
- mTTs = TextToSpeech(context, TextToSpeech.OnInitListener { status ->
- if (status == TextToSpeech.SUCCESS) {
- mTTs.language = Locale.UK
- mostRecentUtteranceID = (Random().nextInt() % 9999999).toString() + ""
-
- val params: MutableMap = HashMap()
- params[TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID] = mostRecentUtteranceID
- @Suppress("DEPRECATION", "UNCHECKED_CAST")
- mTTs.speak(
- getString(R.string.exit_question), TextToSpeech.QUEUE_FLUSH,
- params as HashMap?
- )
- mTTs.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
- override fun onDone(utteranceId: String) {
- if (utteranceId != mostRecentUtteranceID) {
- return
- }
- activity?.runOnUiThread {
- if (mSpeechRecognizer != null) {
- mSpeechRecognizer!!.startListening(mSpeechRecognizerIntent)
- }
- }
- }
-
- override fun onError(p0: String?) = Unit
- override fun onStart(p0: String?) = Unit
- })
-
- }
- })
-
- mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
- mSpeechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
- mSpeechRecognizerIntent?.putExtra(
- RecognizerIntent.EXTRA_LANGUAGE_MODEL,
- RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
- )
- mSpeechRecognizerIntent?.putExtra(
- RecognizerIntent.EXTRA_CALLING_PACKAGE,
- context?.packageName
- )
- mSpeechRecognizer?.setRecognitionListener(SpeechRecognitionListener(fragment))
- }
-
- fun onDestroy() = runIf(preferenceRepository.speechRecognitionEnabled) {
- try {
- mSpeechRecognizer?.destroy()
- } catch (e: Throwable) {
- Timber.e(e)
- }
- }
-}
-
-private class SpeechRecognitionListener(fragment: Fragment) : RecognitionListener {
-
- override fun onBeginningOfSpeech() = Unit
- override fun onBufferReceived(buffer: ByteArray) = Unit
- override fun onEndOfSpeech() = Unit
- override fun onError(error: Int) = Unit
- override fun onEvent(eventType: Int, params: Bundle) = Unit
- override fun onPartialResults(partialResults: Bundle) = Unit
- override fun onReadyForSpeech(params: Bundle) = Unit
- override fun onRmsChanged(rmsdB: Float) = Unit
-
- private val hostFragment: Fragment = fragment
-
- override fun onResults(results: Bundle) {
- try {
- val matches =
- results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
- ?: return
- Timber.i("Speech recognized: $matches")
- if (matches[0] == "да") {
- exitProcess(0)
- }
- if (matches[0] == "нет") {
- hostFragment.navigate(R.id.action_global_menuFragment)
- }
- } catch (e: Exception) {
- Timber.e(e)
- }
- }
-}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/utils/Utils.kt b/app/src/main/java/com/github/braillesystems/learnbraille/utils/Utils.kt
index 14c6959b..bdc09390 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/utils/Utils.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/utils/Utils.kt
@@ -2,7 +2,10 @@ package com.github.braillesystems.learnbraille.utils
import android.content.Context
import android.os.Vibrator
+import android.util.TypedValue
import android.view.accessibility.AccessibilityEvent
+import android.widget.Button
+import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
@@ -72,13 +75,16 @@ fun Fragment.checkedAnnounce(
val Fragment.actionBar: ActionBar?
get() = (activity as AppCompatActivity).supportActionBar
+val Fragment.actionBarNotNull: ActionBar
+ get() = actionBar ?: error("Action bar is not supported")
+
/**
* Throws if action bar is not available
*/
var Fragment.title: String
- get() = requireNotNull(actionBar).title.toString()
+ get() = actionBarNotNull.title.toString()
set(value) {
- requireNotNull(actionBar).title = value
+ actionBarNotNull.title = value
}
fun Fragment.updateTitle(title: String) {
@@ -94,3 +100,21 @@ val Context.extendedTextSize: Float by lazyWithContext {
// Size applied in runtime is different
resources.getDimension(R.dimen.lessons_info_text_size) / 5 * 3
}
+
+fun Fragment.applyExtendedAccessibility(
+ leftButton: Button? = null,
+ rightButton: Button? = null,
+ leftMiddleButton: Button? = null,
+ rightMiddleButton: Button? = null,
+ textView: TextView? = null
+) {
+ val width = resources.getDimension(R.dimen.side_buttons_extended_width).toInt()
+ leftButton?.setSize(width = width)
+ rightButton?.setSize(width = width)
+ leftMiddleButton?.setSize(width = width)
+ rightMiddleButton?.setSize(width = width)
+ textView?.setTextSize(
+ TypedValue.COMPLEX_UNIT_SP,
+ contextNotNull.extendedTextSize
+ )
+}
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Android.kt b/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Android.kt
index b8ff8be5..142d4b3f 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Android.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Android.kt
@@ -100,6 +100,14 @@ fun Fragment.navigate(action: NavDirections) = try {
Timber.e(e, "Multitouch navigation")
}
+fun Fragment.exitToLauncher() {
+ val intent = Intent(Intent.ACTION_MAIN).apply {
+ addCategory(Intent.CATEGORY_HOME)
+ flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
+ }
+ startActivity(intent)
+}
+
val Context.appName: String get() = getString(R.string.app_name)
val Fragment.appName: String get() = contextNotNull.appName
diff --git a/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Kotlin.kt b/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Kotlin.kt
index f2044211..1df93910 100644
--- a/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Kotlin.kt
+++ b/app/src/main/java/com/github/braillesystems/learnbraille/utils/_Kotlin.kt
@@ -8,10 +8,13 @@ import kotlin.reflect.KProperty
* that are not specific for particular project.
*/
-inline fun T?.side(block: (T) -> R) {
+inline fun T?.side(block: (T) -> Unit) {
if (this != null) block(this)
}
+inline fun forEach(vararg xs: T, block: (T) -> Unit) = xs.forEach(block)
+inline fun applyForEach(vararg xs: T, block: T.() -> Unit) = xs.forEach { it.block() }
+
/**
* Try to use sealed classes to avoid using `unreachable`.
*/
@@ -57,7 +60,7 @@ fun Rules.match(key: T): R? = matchF(key)?.invoke(key)
operator fun Rules.get(x: T): R? = match(x)
-fun Rules.getValue(x: T): R = match(x) ?: error("No such rule for $x")
+fun Rules.getValue(x: T): R = match(x) ?: error("No rule match value $x")
/**
* It is very useful to choose android text resource depending on some condition.
diff --git a/app/src/main/res/layout/decks_list_item.xml b/app/src/main/res/layout/decks_list_item.xml
index aae78cbe..6b38d642 100644
--- a/app/src/main/res/layout/decks_list_item.xml
+++ b/app/src/main/res/layout/decks_list_item.xml
@@ -6,7 +6,7 @@
+ type="com.github.braillesystems.learnbraille.data.repository.DeckWithAvailability" />
+ app:layout_constraintTop_toTopOf="@id/letter" />
+ type="com.github.braillesystems.learnbraille.ui.screens.theory.steps.input.InputViewModel" />
+ type="com.github.braillesystems.learnbraille.ui.screens.theory.steps.input.InputViewModel" />
+ type="com.github.braillesystems.learnbraille.ui.screens.theory.steps.input.InputViewModel" />
+ app:layout_constraintTop_toTopOf="@id/letter" />
+ app:layout_constraintTop_toTopOf="@id/letter" />
+ app:layout_constraintTop_toTopOf="@id/letter" />
materials.id]
}
```
+
+Update: `decks` does not have description.
diff --git a/navigation.md b/navigation.md
deleted file mode 100644
index 3c74fbdb..00000000
--- a/navigation.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Learn Braille navigation
-
-- main menu
- - theory
- - continue last visited course
- - courses [Golubina, ...] `no menu while we have one course`
- - continue
- - lessons [lesson 1, ...]
- - steps
- - practice
- - **browse symbols**
- - **decks [all, ru symbols, punctuation, ...]**
- - cards
- - settings
- - setting classes `no classes while we have not so much settings`
- - items
- - scan QR
- - help
- - exit
-
- Menus and items which concept has not been proved yet, are marked as **bold**.