Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2916: Add tts on android #2950

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft

2916: Add tts on android #2950

wants to merge 22 commits into from

Conversation

bahaaTuffaha
Copy link
Contributor

Short description

Adding text-to-speech functionality.

Proposed changes

  • TtsPlayer.tsx : deals with html content and it passes it to react-native-tts as sentences. used debounce function from lodash to handle rapid volume change. I added an expandPlayer state just to keep player expanded when changes from sentence to sentence. This component located at app level where it wraps around the NavigationContainer to be able to be floating at the bottom of the screen while scrolling.

  • useTtsPlayer.ts: Is a hook used to pass data (content, title, visibility, volume) from across the app to TtsPlayer.tsx using useContext.

  • Categories.tsx, News.tsx, Events.tsx each one is using the useTtsPlayer.ts hook to pass content and title.

  • Created a component Slider.tsx instead of adding more libraires and used the ones we have: react-native-reanimated & react-native-gesture-handler to create slider that can be used anywhere other than the volume.

  • Added ReadAloud HeaderButtonTitle to be selected from the kebab menu to show the player. This button will show up only in Integreat/IntegreatTestCms and at third level pages.

  • The TtsPlayer will stop when the app is in the background also if you back out from a 3rd level page.

  • Notes:

    • Not Tested on iOS !
    • Why I passed sentences to tts.speak()? due to react-native-tts doesn't have a functional pause also passing word by word will sound more robotic.
    • Persian is not supported at react-native-tts.

Side effects

  • Categories.tsx, News.tsx, Events.tsx, Header.tsx

Testing

  • At integreat : Go to any 3rd level content in categories or news.
  • Open the kebab menu on the right and select Read aloud.
  • The player will show up press play to make it start reading content.

Resolved issues

Fixes: #2916


Copy link
Contributor

@LeandraH LeandraH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works pretty well so far! A couple of points about the functionality:

  • If I change the volume while it's playing, it starts re-reading the current fragment. If possible, I think it should keep reading at the same spot.
  • In using, I thought the volume bar was for updating the speed of reading. Maybe that's just me but maybe not, we should see if other people have that problem.
  • For Persian (and any other languages where it doesn't work), I think we should hide the button to read the text aloud, and close the overlay if it's open when someone switches languages.
  • In emulated iOS, no sound comes out and I get this warning: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code: {"1000":{},"1001":{},"1002":{},"1003":{},"1004":{},"1005":{},"1006":{},"1007":{},"1008":{},"1009":{},"1010":{},"1011":{},"1012":{},"1013":{},"1014":{},"1015":{},"1016":{},"1017":{},"1018":{},"1019":{},"1020":{},"1021":{},"1022":{},"1023":{},"1024":{},"1025":{},"1026":{},"1027":{},"1028":{},"1029":{},"1030":{},"1031":{},"1032":{},"1033":{},"1034":{},"1035":{},"1036":{},"1037":{},"1038":{},"1039":{},"1040":{},"1041":{},"1042":{},"1043":{},"1044":{},"1045":{},"1046":{},"1047":{},"1048":{},"1049":{},"...(truncated keys)...":451} But I guess you did say that it's not yet tested for iOS :D

As discussed, I only half-checked the PR, let me know when it's ready for review again :)

assets/icons/no-sound.svg Outdated Show resolved Hide resolved
native/src/utils/TtsPlayerUtils.ts Outdated Show resolved Hide resolved
native/src/utils/TtsPlayerUtils.ts Outdated Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

native/src/components/TtsPlayer.tsx Show resolved Hide resolved
})
}
const startReading = () => {
if (!isPersian && sentences.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Maybe we shouldn't show the player at all for Farsi? Are there other languages that are specifically not supported? Or is there a function to check if a language is supported? Or is there a different package we could use that offers more languages?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I Added a condition in the header to check language and hide the button from the menu

native/src/components/TtsPlayer.tsx Outdated Show resolved Hide resolved
native/src/components/TtsPlayer.tsx Outdated Show resolved Hide resolved
native/src/components/TtsPlayer.tsx Outdated Show resolved Hide resolved
native/src/components/TtsPlayer.tsx Outdated Show resolved Hide resolved
assets/icons/no-sound.svg Outdated Show resolved Hide resolved
Copy link
Contributor

@f1sh1918 f1sh1918 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i couldn't test it since its crashing for me on emulator when i click play on Android 13

native/src/components/Header.tsx Outdated Show resolved Hide resolved
native/src/components/Header.tsx Outdated Show resolved Hide resolved
@@ -63,6 +64,16 @@ const News = ({
const selectedNewsItem = news.find(_newsItem => _newsItem.id === newsId)
const { t } = useTranslation('news')

const { setTitle, setContent } = useTtsPlayer()

useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't you just pass these values to the hook instead of using a separate useEffect here. I think the lifecycle depending things should be handled in the hook

Copy link
Contributor Author

@bahaaTuffaha bahaaTuffaha Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get what exactly you want me to do here... just pass them to the hook without useeffect?
I think in this case it will keep setting these states each time the News re-render right?

Copy link
Contributor

@f1sh1918 f1sh1918 Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i mean you can move this useEffect to your hook and just pass title and content.
sth like that.
You probably have to skip that if no content or title is delivered as its used in RemoteContent

const useTtsPlayer = (content: string, title: string): ttsContextType => {
  const tts = useContext(ttsContext)

  useEffect(() => {
    tts.setContent(content)
    tts.setTitle(title)
  }, [content, title, tts])
...

I didn't test that i just think to add to every usage of your useTtsPlayer hook an useEffect results in lots of code duplication

native/src/components/RemoteContent.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@f1sh1918 f1sh1918 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me on android. good work.
Since its a draft some improvements are missing i guess

image
Shouldn't here stand the title of what will be read?
Even add shadows/elevation for the container and the play button
image
The icons should switch i guess since the direction arrows are wrong

image

I think it would be better to create a fixed area for this player instead of overlapping content, but this may be also done in an additional tasks, since it will need some effort.

native/src/components/Slider.tsx Outdated Show resolved Hide resolved
const [isPlaying, setIsPlaying] = useState(false)
const [expandPlayer, setExpandPlayer] = useState(false)
const defaultVolume = 50
const [volume, setVolume] = useState(defaultVolume)
Copy link
Contributor

@f1sh1918 f1sh1918 Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you can initialize this with the value from your context, no?
{volume: defaultVolume} = useTtsPlayer()

Copy link

codeclimate bot commented Oct 17, 2024

Code Climate has analyzed commit 042e2ac and detected 3 issues on this pull request.

Here's the issue category breakdown:

Category Count
Complexity 3

The test coverage on the diff in this pull request is 75.9% (50% is the threshold).

This pull request will bring the total coverage in the repository to 74.2%.

View more on Code Climate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add TTS on android
3 participants