Im adapting a project created by the agora.io community. the base project is here: https://github.com/AgoraIO-Community/Agora-RN-Quickstart. A quick look at the App.tsx file there will give you the file im adapting. also easy to download and run

now initially, the project works fine, both start and end call buttons work out of the box. it needs some UI and functional updates though for my endgame. in the process of updating dynamic call start/end buttons, and adding a call time ui piece.

problem: all of sudden the end call button doesn't want to execute its onPress once the view returned by _renderVideos() is loaded. the start call function is async, so it takes a second or two for the new view to render. in this couple second window, the end call button can be pressed, and its function executed.

here's some of my adaptations:

import React from 'react';
import { View, Text, NativeModules, ScrollView, ActivityIndicator, TouchableOpacity, Dimensions, Platform, StyleSheet } from 'react-native';
import RtcEngine, { RtcLocalView, RtcRemoteView, VideoRenderMode } from 'react-native-agora';
import requestCameraAndAudioPermission from '../androidChatPermissions.js'
import * as Colors from '../assets/colors'

const AGORA_APP_ID = '<...>';
const { height, width } = Dimensions.get('window');

interface Props {
    userId: string
}

interface State {
    appId: string,
    channelName: string,
    joinSucceed: boolean,
    peerIds: number[],
    callStarted: boolean,
    continuityModal: boolean,
    endCallModal: boolean,
    microphoneMuted: boolean,
    roomNotification: string,
    clockRunning: boolean,
    clockTime: string,
    chatSec: number,
    chatMin: number
}

export default class Chatroom extends React.Component<Props, State> {
    _engine?: RtcEngine
    clock: Timestamp

    static navigationOptions = {
        headerShown: false
    }

    constructor(props) {
        super(props)
        this.state = {
            appId: AGORA_APP_ID,
            joinSucceed: false,
            peerIds: [],
            channelName: 'channel-x',
            callStarted: false,
            continuityModal: false,
            endCallModal: false,
            microphoneMuted: false,
            roomNotification: null,
            clockRunning: false,
            clockTime: null,
            chatSec: null,
            chatMin: null
        }
        if (Platform.OS === 'android') [
            requestCameraAndAudioPermission().then(_ => {
                console.log('permissions requested')
            })
        ]
    }

    componentDidMount() {
        this.init()
    }

    init = async () => {
       // no changes from base project's App.tsx
    }

    startCall = async () => {
        await this._engine?.joinChannel(null, this.state.channelName, null, 0)
        this.setState({ callStarted: true }, () => this.runClock())
    }

    endCall = async () => {
        console.log("end call pressed")
        await this._engine?.leaveChannel()
        this.setState({ peerIds: [], joinSucceed: false, callStarted: false })
    }

    runClock() {
        console.log("clock running")
    }

    render() {
        return (
            <View style={styles.max}>
                <View style={[styles.max, { backgroundColor: 'blue' }]}>
                    <View style={styles.detailsWrapper}>
                        {!this.state.callStarted ? (
                            <TouchableOpacity
                                onPress={this.startCall}
                                style={[styles.button, { backgroundColor: Colors.PRIMARY_GREEN }]}>
                                <Text style={styles.buttonText}> Start Call </Text>
                            </TouchableOpacity>
                        ) : (
                                <View style={{ marginTop: 20 }}>
                                    <Text>{this.state.chatTime}</Text>
                                    <TouchableOpacity
                                        onPress={this.endCall}
                                        style={[styles.button, { backgroundColor: Colors.PRIMARY_ACTION }]}>
                                        <Text style={styles.buttonText}> End Call </Text>
                                    </TouchableOpacity>
                                </View>
                            )}
                    </View>
                    {this._renderVideos()}
                </View>
            </View>
        )
    }

    _renderVideos = () => {
        const { joinSucceed } = this.state
        return joinSucceed ? (
            <View style={styles.fullView}>
                <RtcLocalView.SurfaceView
                    style={styles.max}
                    channelId={this.state.channelName}
                    renderMode={VideoRenderMode.Hidden} />
                {this._renderRemoteVideos()}
            </View>
        ) : null
    }

    _renderRemoteVideos = () => {
        const { peerIds } = this.state
        return (
            <ScrollView
                style={styles.remoteContainer}
                contentContainerStyle={{ paddingHorizontal: 2.5 }}
                horizontal={true}>
                {peerIds.map((value, index, array) => {
                    return (
                        <RtcRemoteView.SurfaceView
                            style={styles.remote}
                            uid={value}
                            channelId={this.state.channelName}
                            renderMode={VideoRenderMode.Hidden}
                            zOrderMediaOverlay={true} />
                    )
                })}
            </ScrollView>
        )
    }
}

const styles = StyleSheet.create({
    max: {
        flex: 1,
    },
    detailsWrapper: {
        position: 'absolute',
        top: 50,
        alignSelf: 'center',
        height: 100,
        width: width,
        alignItems: 'center',
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'space-evenly',
        borderWidth: 1,
        borderColor: 'red'
    },
    button: {
        paddingHorizontal: 20,
        paddingVertical: 10,
        borderRadius: 10,
    },
    buttonText: {
        color: '#fff',
        fontWeight: 'bold'
    },
    fullView: {
        width: width,
        height: 50,
        backgroundColor: '#333'
    },
    remoteContainer: {
        width: '100%',
        height: 150,
        position: 'absolute',
        top: 5
    },
    remote: {
        width: 150,
        height: 150,
        marginHorizontal: 2.5
    },
    noUserText: {
        paddingHorizontal: 10,
        paddingVertical: 5,
        color: '#0093E9',
    },
})

As you can see the only changes ive made so far were a couple logs, additional function call from after setState, dynamic button rendering, and some style adjustments. It's weird, everything seems frozen or blocked, Command+R and Command+I don't work either

Why is the onPress of the endCall button only executing before the new view renders?

1

There are 1 best solutions below

0
On

The issue here, relates to the absolute positioning I had updated the detailsWrapper with. the way in which the details wrappers, and _renderVideos was ordered in the render function affected the end call button by overlaying an invisible portion of the lower end of the renderVideos container. wasn't able to see it because the inspector was not working.

ultimately there are two fixes:

  1. what I did was to add a zIndex on the details wrapper style

  2. but I suppose you could also mess with the order of the views in the render. as an absolutely positioned view will be absolutely positioned relevant to the encasing parent view