Skip to content

Commit

Permalink
Added fragment starting voice transcription activity (googlesamples#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
idzkowski-google committed Jul 7, 2020
1 parent a596d36 commit 33a5bcb
Show file tree
Hide file tree
Showing 17 changed files with 610 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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<String>? =
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)
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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<BaseViewPagerFragment>,
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]
}
}
Original file line number Diff line number Diff line change
@@ -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<BaseViewPagerFragment>()
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()
}
}
4 changes: 2 additions & 2 deletions NotesSample/app/src/main/res/drawable/ic_add.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:width="64dp"
android:height="64dp"
android:tint="#FFFFFF"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
Expand Down
26 changes: 26 additions & 0 deletions NotesSample/app/src/main/res/drawable/ic_arrow_left.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:tint="#FFFFFF"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.41,16.09l-4.58,-4.59 4.58,-4.59L14,5.5l-6,6 6,6z" />
</vector>
Loading

0 comments on commit 33a5bcb

Please sign in to comment.