diff --git a/app/src/main/java/com/knowre/android/kal/MainActivity.kt b/app/src/main/java/com/knowre/android/kal/MainActivity.kt index f5c6cab..d5a0cd6 100644 --- a/app/src/main/java/com/knowre/android/kal/MainActivity.kt +++ b/app/src/main/java/com/knowre/android/kal/MainActivity.kt @@ -8,7 +8,6 @@ import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController -import com.google.android.material.snackbar.Snackbar import com.knowre.android.kal.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { @@ -27,10 +26,6 @@ class MainActivity : AppCompatActivity() { val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) - - binding.fab.setOnClickListener { view -> - Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() - } } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/java/com/knowre/android/kal/myscript/Candidate.kt b/app/src/main/java/com/knowre/android/kal/myscript/Candidate.kt new file mode 100644 index 0000000..b3c8343 --- /dev/null +++ b/app/src/main/java/com/knowre/android/kal/myscript/Candidate.kt @@ -0,0 +1,9 @@ +package com.knowre.android.kal.myscript + + +internal sealed class Candidate { + + class Data(val itemId: String, val label: String) : Candidate() + + class Exit() : Candidate() +} \ No newline at end of file diff --git a/app/src/main/java/com/knowre/android/kal/myscript/CandidateAdapter.kt b/app/src/main/java/com/knowre/android/kal/myscript/CandidateAdapter.kt new file mode 100644 index 0000000..44fbd33 --- /dev/null +++ b/app/src/main/java/com/knowre/android/kal/myscript/CandidateAdapter.kt @@ -0,0 +1,81 @@ +package com.knowre.android.kal.myscript + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.knowre.android.kal.databinding.ViewCandidateItemBinding + + +internal class CandidateAdapter( + private val onCandidateClicked: (Candidate.Data) -> Unit, + private val onExitClicked: () -> Unit +) : RecyclerView.Adapter() { + + private var candidates = listOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CandidateViewHolder { + return CandidateViewHolder.newInstance(parent, + onCandidateClicked = { + clear() + onCandidateClicked(it) + }, + onExitClicked = { + clear() + onExitClicked() + } + ) + } + + override fun onBindViewHolder(holder: CandidateViewHolder, position: Int) { + holder.bind(candidates[position]) + } + + override fun getItemCount() = candidates.size + + fun setCandidates(candidates: List) { + this.candidates = candidates + .toMutableList() + .apply { if (isNotEmpty()) add(Candidate.Exit()) } + .also { notifyDataSetChanged() } + } + + fun clear() { + this.candidates = listOf() + notifyDataSetChanged() + } +} + +internal class CandidateViewHolder( + private val binding: ViewCandidateItemBinding +) : RecyclerView.ViewHolder(binding.root) { + + private lateinit var candidate: Candidate + + fun bind(candidate: Candidate) { + this.candidate = candidate + when (candidate) { + is Candidate.Data -> binding.candidateText.text = candidate.label + is Candidate.Exit -> { + binding.candidateText.text = "X" + } + } + } + + companion object { + fun newInstance( + parent: ViewGroup, + onCandidateClicked: (Candidate.Data) -> Unit, + onExitClicked: () -> Unit + ): CandidateViewHolder { + return CandidateViewHolder(ViewCandidateItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply { + binding.root.setOnClickListener { + if (candidate is Candidate.Data) { + onCandidateClicked(candidate as Candidate.Data) + } else { + onExitClicked() + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowre/android/kal/myscript/MyScriptPadView.kt b/app/src/main/java/com/knowre/android/kal/myscript/MyScriptPadView.kt index 7e2ce69..a8638a8 100644 --- a/app/src/main/java/com/knowre/android/kal/myscript/MyScriptPadView.kt +++ b/app/src/main/java/com/knowre/android/kal/myscript/MyScriptPadView.kt @@ -2,19 +2,24 @@ package com.knowre.android.kal.myscript import android.content.Context import android.content.res.AssetManager +import android.content.res.ColorStateList +import android.content.res.Resources +import android.graphics.Color import android.util.AttributeSet import android.util.Log +import android.util.TypedValue import android.view.LayoutInflater import android.widget.FrameLayout +import android.widget.Toast +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.shape.MaterialShapeDrawable +import com.google.android.material.shape.ShapeAppearanceModel import com.knowre.android.kal.databinding.ViewMyscriptPadBinding -import com.knowre.android.myscript.iink.FolderProvider import com.knowre.android.myscript.iink.MyScriptApi -import com.knowre.android.myscript.iink.MyScriptAssetResource import com.knowre.android.myscript.iink.MyScriptInitializer import com.knowre.android.myscript.iink.MyScriptInterpretListener import com.knowre.android.myscript.iink.ToolFunction import com.knowre.android.myscript.iink.ToolType -import com.knowre.android.myscript.iink.certificate.MyCertificate import com.myscript.iink.Editor import com.myscript.iink.EditorError import kotlinx.coroutines.MainScope @@ -32,44 +37,61 @@ internal class MyScriptPadView constructor( private val mainScope = MainScope() - private lateinit var myscript: MyScriptApi + private lateinit var myScript: MyScriptApi + + private val candidateAdapter = CandidateAdapter( + onCandidateClicked = { candidate -> }, + onExitClicked = {} + ) init { - MyScriptInitializer( - certificate = MyCertificate.getBytes(), - editorView = binding.myScript.editorView, - context = context, - folders = FolderProvider(context), - assetResource = MyScriptAssetResource(context), - scope = mainScope - ) - .setGeneralConfiguration() - .setMathConfiguration() - .initialize { - myscript = it.apply { - listener = object : MyScriptInterpretListener { - override fun onInterpreted(interpreted: String) { - binding.latex.text = interpreted - mainScope.launch { - binding.redo.isEnabled = myscript.canRedo - binding.undo.isEnabled = myscript.canUndo - } - } - - override fun onError(editor: Editor, blockId: String, error: EditorError, message: String) { - Log.d("MY_SCRIPT_ERROR", "$error with message $message") - } - } - } + initializeMyScript() + initializeRecyclerView() + initializeToolsListener() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + mainScope.cancel() + } + + private fun initializeMyScript() { + mainScope.launch { + myScript = MyScriptInitializer( + myScriptView = binding.myScriptView, + context = context, + scope = mainScope + ) + .initialize() + .apply { addListener(interpretListener) } + .apply { isAutoConvertEnabled = false } + } + } + + private fun initializeRecyclerView() { + with(binding.candidate) { + adapter = candidateAdapter + layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + background = MaterialShapeDrawable( + ShapeAppearanceModel.Builder() + .setAllCornerSizes(8F.dp) + .build() + ).apply { + tintList = ColorStateList.valueOf(Color.parseColor("#FFFFFF")) + strokeWidth = 1F.dp + strokeColor = ColorStateList.valueOf(Color.parseColor("#CFD8DC")) + elevation = 4F.dp } + } + } + private fun initializeToolsListener() { binding.redo.isEnabled = false binding.undo.isEnabled = false - binding.convert.setOnClickListener { myscript.convert() } - binding.deleteAll.setOnClickListener { myscript.eraseAll() } + binding.deleteAll.setOnClickListener { myScript.eraseAll() } binding.digitOnlyGrammar.setOnClickListener { - myscript.loadMathGrammar("n_digit_exp", context.assets.toByteArray("n_digit_exp.res")) + myScript.loadMathGrammar("n_digit_exp", context.assets.toByteArray("n_digit_exp.res")) } binding.defaultGrammar.setOnClickListener { @@ -77,20 +99,22 @@ internal class MyScriptPadView constructor( } binding.red.setOnClickListener { - myscript.penColor = 0xFF0000 + myScript.penColor = 0xFF0000 } binding.blue.setOnClickListener { - myscript.penColor = 0x0000FF + myScript.penColor = 0x0000FF } binding.black.setOnClickListener { - myscript.penColor = 0x000000 + myScript.penColor = 0x000000 } + binding.convert.setOnClickListener { myScript.convert() } + binding.penSwitch.setOnCheckedChangeListener { _, isChecked -> binding.eraserSwitch.isChecked = false - myscript.tool = if (isChecked) { + myScript.tool = if (isChecked) { MyScriptApi.Tool( toolType = ToolType.PEN, toolFunction = ToolFunction.DRAWING @@ -104,32 +128,60 @@ internal class MyScriptPadView constructor( } binding.convertSwitch.setOnCheckedChangeListener { _, isChecked -> - myscript.isAutoConvertEnabled = isChecked + myScript.isAutoConvertEnabled = isChecked } binding.eraserSwitch.setOnCheckedChangeListener { _, isChecked -> val toolType = if (binding.penSwitch.isChecked) ToolType.PEN else ToolType.HAND if (isChecked) { - myscript.tool = MyScriptApi.Tool(toolType, ToolFunction.ERASING) + myScript.tool = MyScriptApi.Tool(toolType, ToolFunction.ERASING) } else { - myscript.tool = MyScriptApi.Tool(toolType, ToolFunction.DRAWING) + myScript.tool = MyScriptApi.Tool(toolType, ToolFunction.DRAWING) } } binding.redo.setOnClickListener { - myscript.redo() + myScript.redo() } binding.undo.setOnClickListener { - myscript.undo() + myScript.undo() } + + binding.candidateSwitch.setOnCheckedChangeListener { _, isChecked -> } } - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - mainScope.cancel() + private val interpretListener: MyScriptInterpretListener + get() = object : MyScriptInterpretListener { + override fun onInterpreted(interpreted: String) { + binding.latex.text = interpreted + binding.redo.isEnabled = myScript.canRedo + binding.undo.isEnabled = myScript.canUndo + } + + override fun onInterpretError(editor: Editor, blockId: String, error: EditorError, message: String) { + Log.d("MY_SCRIPT_ERROR", "$error with message $message") + } + + override fun onImportError() { + Toast + .makeText(context, "해당 문자로는 변경이 불가능합니다.", Toast.LENGTH_SHORT) + .show() + } + } + + private fun showNoCandidateAvailable() { + Toast + .makeText(context, "No candidates available.", Toast.LENGTH_SHORT) + .show() } private fun AssetManager.toByteArray(fileName: String) = open(fileName).use { it.readBytes() } + private val Number.dp: Float + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + toFloat(), + Resources.getSystem().displayMetrics + ) } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9fec30d..3c4722d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -20,15 +20,6 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_first.xml b/app/src/main/res/layout/fragment_first.xml index 5f25d3c..531b331 100644 --- a/app/src/main/res/layout/fragment_first.xml +++ b/app/src/main/res/layout/fragment_first.xml @@ -10,31 +10,17 @@ android:id="@+id/button_first" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="30dp" + android:layout_marginTop="50dp" android:text="@string/next" - app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> - - - + app:layout_constraintBottom_toBottomOf="parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/view_candidate_item.xml b/app/src/main/res/layout/view_candidate_item.xml new file mode 100644 index 0000000..a17adf8 --- /dev/null +++ b/app/src/main/res/layout/view_candidate_item.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_myscript_pad.xml b/app/src/main/res/layout/view_myscript_pad.xml index 9610942..d6ac65c 100644 --- a/app/src/main/res/layout/view_myscript_pad.xml +++ b/app/src/main/res/layout/view_myscript_pad.xml @@ -1,53 +1,66 @@ + android:id="@+id/my_script_view" + android:layout_width="0dp" + android:layout_height="0dp" + android:background="#11333345" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> -