diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/NotesFragment.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/NotesFragment.kt index 7553158..6474378 100644 --- a/NotesSample/app/src/main/java/com/example/glass/notessample/NotesFragment.kt +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/NotesFragment.kt @@ -21,30 +21,40 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import com.example.glass.notessample.viewpager.BaseViewPagerFragment +import com.example.glass.notessample.viewpager.NotesViewPagerViewHelper import com.example.glass.ui.GlassGestureDetector +/** + * Main fragment for displaying notes + */ class NotesFragment : Fragment(), GlassGestureDetector.OnGestureListener { + private lateinit var notesViewHelper: NotesViewPagerViewHelper + private val currentFragment: BaseViewPagerFragment by lazy { + notesViewHelper.viewPagerAdapter + .getCurrentFragment(notesViewHelper.getCurrentElementIndex()) as BaseViewPagerFragment + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.notes_fragment, container, false) + return inflater.inflate(R.layout.notes_view_pager, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + notesViewHelper = NotesViewPagerViewHelper(view, childFragmentManager) + } + + override fun onGesture(glassGesture: GlassGestureDetector.Gesture): Boolean { + return currentFragment.onGesture(glassGesture) } override fun onResume() { super.onResume() (requireActivity() as BaseActivity).setOnGestureListener(this) } - - override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean { - return when (gesture) { - GlassGestureDetector.Gesture.SWIPE_DOWN -> { - requireActivity().finish() - true - } - else -> false - } - } } \ No newline at end of file diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/NotesViewHelper.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/NotesViewHelper.kt new file mode 100644 index 0000000..b85bb53 --- /dev/null +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/NotesViewHelper.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.glass.notessample + +/** + * View helper interface + */ +interface NotesViewHelper { + fun getCurrentElementIndex(): Int + fun notifyDataSetChanged(position: Int) +} \ No newline at end of file diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/AddNoteFragment.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/AddNoteFragment.kt new file mode 100644 index 0000000..569fdeb --- /dev/null +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/AddNoteFragment.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.glass.notessample.viewpager + +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.os.Bundle +import android.speech.RecognizerIntent +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.glass.notessample.R +import com.example.glass.ui.GlassGestureDetector +import kotlinx.android.synthetic.main.notes_option_layout.* + +/** + * Fragment for adding new notes + */ +class AddNoteFragment : BaseViewPagerFragment() { + + companion object { + private val TAG = AddNoteFragment::class.java.simpleName + private const val VOICE_REQUEST_CODE = 205 + + fun newInstance( + listener: (text: String) -> Unit + ): AddNoteFragment { + val addNoteFragment = AddNoteFragment() + addNoteFragment.listener = listener + return addNoteFragment + } + } + + lateinit var listener: (String) -> Unit + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.notes_option_layout, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + optionIcon.setImageResource(R.drawable.ic_add) + optionTextView.text = resources.getString(R.string.add_note) + } + + override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean = + when (gesture) { + GlassGestureDetector.Gesture.TAP -> { + startVoiceRecognition() + true + } + else -> super.onGesture(gesture) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == VOICE_REQUEST_CODE && resultCode == RESULT_OK) { + val results: List? = + data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) + if (results != null && results.isNotEmpty() && results[0].isNotEmpty()) { + listener(results[0]) + } else { + Log.d(TAG, "Voice recognition result is empty") + } + } else { + Log.d(TAG, "Voice recognition activity results with bad request or result code") + } + } + + private fun startVoiceRecognition() { + val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) + intent.putExtra( + RecognizerIntent.EXTRA_LANGUAGE_MODEL, + RecognizerIntent.LANGUAGE_MODEL_FREE_FORM + ) + startActivityForResult(intent, VOICE_REQUEST_CODE) + } +} \ No newline at end of file diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/BaseViewPagerFragment.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/BaseViewPagerFragment.kt new file mode 100644 index 0000000..04a0f01 --- /dev/null +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/BaseViewPagerFragment.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.glass.notessample.viewpager + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.glass.notessample.R +import com.example.glass.ui.GlassGestureDetector + +/** + * Base class for the view pager fragments + */ +open class BaseViewPagerFragment : Fragment(), GlassGestureDetector.OnGestureListener { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.notes_fragment_layout, container, false) + } + + override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean = + when (gesture) { + GlassGestureDetector.Gesture.SWIPE_DOWN -> { + requireActivity().finish() + true + } + else -> false + } +} \ No newline at end of file diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesPagerAdapter.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesPagerAdapter.kt new file mode 100644 index 0000000..fcb9e30 --- /dev/null +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesPagerAdapter.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.glass.notessample.viewpager + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import androidx.viewpager.widget.PagerAdapter + +/** + * Adapter for the view pager + */ +class NotesPagerAdapter( + private val fragments: MutableList, + fm: FragmentManager, + behavior: Int +) : FragmentStatePagerAdapter(fm, behavior) { + + override fun getItem(position: Int): Fragment { + return fragments[position] + } + + override fun getCount(): Int { + return fragments.size + } + + override fun getItemPosition(item: Any): Int { + val position = fragments.indexOf(item) + return if (position == -1) { + PagerAdapter.POSITION_NONE + } else { + position + } + } + + fun getCurrentFragment(position: Int): Fragment? { + return fragments[position] + } +} \ No newline at end of file diff --git a/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesViewPagerViewHelper.kt b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesViewPagerViewHelper.kt new file mode 100644 index 0000000..f0d1496 --- /dev/null +++ b/NotesSample/app/src/main/java/com/example/glass/notessample/viewpager/NotesViewPagerViewHelper.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.glass.notessample.viewpager + +import android.view.View +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import com.example.glass.notessample.NotesViewHelper +import kotlinx.android.synthetic.main.notes_view_pager.view.* + +/** + * View helper implementation for the view pager + */ +class NotesViewPagerViewHelper( + view: View, + fragmentManager: FragmentManager, + voiceListener: (String) -> Unit = {} +) : NotesViewHelper { + + companion object { + private const val FIRST_NOTE_POSITION = 2 + } + + val viewPagerAdapter: NotesPagerAdapter + private val fragmentList = mutableListOf() + private val viewPager = view.notesViewPager + + init { + fragmentList.add(AddNoteFragment.newInstance(voiceListener)) + viewPagerAdapter = NotesPagerAdapter( + fragmentList, + fragmentManager, + FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT + ) + viewPager.adapter = viewPagerAdapter + viewPager.currentItem = FIRST_NOTE_POSITION + + val tabLayout = view.page_indicator + tabLayout.setupWithViewPager(viewPager) + } + + override fun getCurrentElementIndex(): Int { + return viewPager.currentItem + } + + override fun notifyDataSetChanged(position: Int) { + fragmentList.removeAt(position) + viewPagerAdapter.notifyDataSetChanged() + } +} \ No newline at end of file diff --git a/NotesSample/app/src/main/res/drawable/ic_add.xml b/NotesSample/app/src/main/res/drawable/ic_add.xml index 88562d4..e18d02c 100644 --- a/NotesSample/app/src/main/res/drawable/ic_add.xml +++ b/NotesSample/app/src/main/res/drawable/ic_add.xml @@ -15,8 +15,8 @@ limitations under the License. --> diff --git a/NotesSample/app/src/main/res/drawable/ic_arrow_left.xml b/NotesSample/app/src/main/res/drawable/ic_arrow_left.xml new file mode 100644 index 0000000..5b09256 --- /dev/null +++ b/NotesSample/app/src/main/res/drawable/ic_arrow_left.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/NotesSample/app/src/main/res/drawable/indicator_not_selected.xml b/NotesSample/app/src/main/res/drawable/indicator_not_selected.xml new file mode 100644 index 0000000..be8478c --- /dev/null +++ b/NotesSample/app/src/main/res/drawable/indicator_not_selected.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/NotesSample/app/src/main/res/drawable/indicator_selected.xml b/NotesSample/app/src/main/res/drawable/indicator_selected.xml new file mode 100644 index 0000000..81ad21a --- /dev/null +++ b/NotesSample/app/src/main/res/drawable/indicator_selected.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/drawable/page_indicator_selector.xml b/NotesSample/app/src/main/res/drawable/page_indicator_selector.xml new file mode 100644 index 0000000..5541135 --- /dev/null +++ b/NotesSample/app/src/main/res/drawable/page_indicator_selector.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/layout/notes_fragment_layout.xml b/NotesSample/app/src/main/res/layout/notes_fragment_layout.xml new file mode 100644 index 0000000..63387a1 --- /dev/null +++ b/NotesSample/app/src/main/res/layout/notes_fragment_layout.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/layout/notes_option_layout.xml b/NotesSample/app/src/main/res/layout/notes_option_layout.xml new file mode 100644 index 0000000..3add112 --- /dev/null +++ b/NotesSample/app/src/main/res/layout/notes_option_layout.xml @@ -0,0 +1,41 @@ + + + + + + + + + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/layout/notes_view_pager.xml b/NotesSample/app/src/main/res/layout/notes_view_pager.xml new file mode 100644 index 0000000..003c706 --- /dev/null +++ b/NotesSample/app/src/main/res/layout/notes_view_pager.xml @@ -0,0 +1,45 @@ + + + + + + + + + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/values/dimens.xml b/NotesSample/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..9ee9d01 --- /dev/null +++ b/NotesSample/app/src/main/res/values/dimens.xml @@ -0,0 +1,23 @@ + + + + 45sp + 40dp + 32dp + 2dp + 0dp + \ No newline at end of file diff --git a/NotesSample/app/src/main/res/values/strings.xml b/NotesSample/app/src/main/res/values/strings.xml index c76ae85..3abcb1b 100644 --- a/NotesSample/app/src/main/res/values/strings.xml +++ b/NotesSample/app/src/main/res/values/strings.xml @@ -16,6 +16,7 @@ --> Notes Sample + sans-serif-thin Delete Edit Add note diff --git a/NotesSample/app/src/main/res/values/styles.xml b/NotesSample/app/src/main/res/values/styles.xml index e41f776..3fd08a2 100644 --- a/NotesSample/app/src/main/res/values/styles.xml +++ b/NotesSample/app/src/main/res/values/styles.xml @@ -22,4 +22,12 @@ @android:color/white + +