diff --git a/app/build.gradle b/app/build.gradle index 07590c3..4c56948 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: "androidx.navigation.safeargs.kotlin" android { compileSdkVersion 29 @@ -42,6 +43,10 @@ dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" + // navigation component + implementation "androidx.navigation:navigation-fragment-ktx:2.3.0" + implementation "androidx.navigation:navigation-ui-ktx:2.3.0" + testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9fd06fa..0dec640 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + diff --git a/app/src/main/java/tw/andyang/kotlinandroidworkshop/AddTodoFragment.kt b/app/src/main/java/tw/andyang/kotlinandroidworkshop/AddTodoFragment.kt new file mode 100644 index 0000000..0be5ef1 --- /dev/null +++ b/app/src/main/java/tw/andyang/kotlinandroidworkshop/AddTodoFragment.kt @@ -0,0 +1,61 @@ +package tw.andyang.kotlinandroidworkshop + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import kotlinx.android.synthetic.main.fragment_add_todo.* + +class AddTodoFragment : Fragment() { + + private val args by navArgs() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_add_todo, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // auto open soft keyboard + editTodo.requestFocus() + val inputMethodManager = + requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.toggleSoftInput( + InputMethodManager.SHOW_FORCED, + InputMethodManager.HIDE_IMPLICIT_ONLY + ) + + // setup argument + editTodo.setText(args.memo) + editTodo.setSelection(args.memo.length) + + val todoViewModel = ViewModelProvider(requireActivity()).get(TodoViewModel::class.java) + + buttonAdd.setOnClickListener { + if (editTodo.text.isNullOrEmpty()) { + editTodo.error = "請輸入你的代辦事項" + } else { + // clear error + editTodo.error = null + // post data to view model + todoViewModel.onNewTodo.postValue(editTodo.text.toString()) + // hide soft keyboard when item added + view.clearFocus() + inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) + // back to list page + findNavController().popBackStack() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/tw/andyang/kotlinandroidworkshop/MainActivity.kt b/app/src/main/java/tw/andyang/kotlinandroidworkshop/MainActivity.kt index 8c4f46f..b857996 100644 --- a/app/src/main/java/tw/andyang/kotlinandroidworkshop/MainActivity.kt +++ b/app/src/main/java/tw/andyang/kotlinandroidworkshop/MainActivity.kt @@ -2,30 +2,11 @@ package tw.andyang.kotlinandroidworkshop import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.* -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - - val adapter = TodoAdapter() - recyclerView.adapter = adapter - recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) - recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL)) - - val todoViewModel = ViewModelProvider(this).get() - - todoViewModel.todoLiveData.observe(this, Observer { todos: List -> - adapter.submitList(todos) - }) - - buttonAdd.setOnClickListener { - todoViewModel.onNewTodo.postValue(Unit) - } } } \ No newline at end of file diff --git a/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoListFragment.kt b/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoListFragment.kt new file mode 100644 index 0000000..0a6c152 --- /dev/null +++ b/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoListFragment.kt @@ -0,0 +1,49 @@ +package tw.andyang.kotlinandroidworkshop + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.fragment_todo_list.* + +class TodoListFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_todo_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val adapter = TodoAdapter() + recyclerView.adapter = adapter + recyclerView.layoutManager = + LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) + recyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), + LinearLayoutManager.VERTICAL + ) + ) + + val todoViewModel = ViewModelProvider(requireActivity()).get(TodoViewModel::class.java) + + todoViewModel.todoLiveData.observe(viewLifecycleOwner, Observer { todos: List -> + adapter.submitList(todos) + }) + + buttonAdd.setOnClickListener { + findNavController().navigate(TodoListFragmentDirections.actionMainFragmentToAddTodoFragment()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoViewModel.kt b/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoViewModel.kt index fdfab8b..4386393 100644 --- a/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoViewModel.kt +++ b/app/src/main/java/tw/andyang/kotlinandroidworkshop/TodoViewModel.kt @@ -7,16 +7,13 @@ import androidx.lifecycle.ViewModel class TodoViewModel : ViewModel() { - val onNewTodo = MutableLiveData() + val onNewTodo = MutableLiveData() val todoLiveData: LiveData> = MediatorLiveData>().apply { - addSource(onNewTodo) { - val todo = Todo.Item("note $count", false) + addSource(onNewTodo) { text -> + val todo = Todo.Item(text, false) this.value = this.value!! + listOf(todo) - count++ } value = mutableListOf(Todo.Title("This is a title")) } - - private var count = 0 } \ 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 c348834..5dca6d4 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,24 +1,15 @@ + android:layout_height="match_parent"> - - - + app:defaultNavHost="true" + app:navGraph="@navigation/nav_graph" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_add_todo.xml b/app/src/main/res/layout/fragment_add_todo.xml new file mode 100644 index 0000000..a00d6ae --- /dev/null +++ b/app/src/main/res/layout/fragment_add_todo.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_todo_list.xml b/app/src/main/res/layout/fragment_todo_list.xml new file mode 100644 index 0000000..4649395 --- /dev/null +++ b/app/src/main/res/layout/fragment_todo_list.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 0000000..3cb54aa --- /dev/null +++ b/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 960ef27..08becb5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,4 +2,5 @@ KotlinAndroidWorkshop 備忘錄 新增 + 你的待辦事項 \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1241d12..cf8c48b 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { dependencies { classpath "com.android.tools.build:gradle:4.0.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }