Sfoglia il codice sorgente

feat(conference) added React Navigation

Introduce navigation for all in-conference screens.
factor2
Calinteodor 4 anni fa
parent
commit
9df59b4a6f
Nessun account collegato all'indirizzo email del committer
54 ha cambiato i file con 1708 aggiunte e 601 eliminazioni
  1. 1
    1
      android/app/src/main/java/org/jitsi/meet/MainActivity.java
  2. 2
    2
      android/build.gradle
  3. 5
    0
      android/sdk/build.gradle
  4. 2
    2
      android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java
  5. 12
    7
      android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java
  6. 10
    0
      android/settings.gradle
  7. 5
    0
      ios/Podfile
  8. 33
    3
      ios/Podfile.lock
  9. 482
    128
      package-lock.json
  10. 9
    0
      package.json
  11. 52
    0
      react/features/app/getRouteToRender.native.js
  12. 10
    52
      react/features/app/getRouteToRender.web.js
  13. 83
    0
      react/features/base/modal/components/JitsiKeyboardAvoidingView.js
  14. 69
    0
      react/features/base/modal/components/JitsiScreen.js
  15. 60
    0
      react/features/base/modal/components/functions.native.js
  16. 5
    0
      react/features/base/modal/components/styles.js
  17. 6
    1
      react/features/base/ui/Tokens.js
  18. 19
    4
      react/features/chat/components/PrivateMessageButton.js
  19. 62
    82
      react/features/chat/components/native/Chat.js
  20. 43
    0
      react/features/chat/components/native/ChatAndPolls.js
  21. 14
    5
      react/features/chat/components/native/ChatButton.js
  22. 0
    14
      react/features/chat/components/native/ChatInputBar.js
  23. 51
    11
      react/features/chat/components/native/MessageRecipient.js
  24. 1
    0
      react/features/chat/components/native/index.js
  25. 7
    2
      react/features/chat/components/native/styles.js
  26. 0
    2
      react/features/chat/constants.js
  27. 0
    17
      react/features/chat/middleware.js
  28. 21
    29
      react/features/conference/components/native/Conference.js
  29. 100
    0
      react/features/conference/components/native/ConferenceNavigationContainer.js
  30. 40
    0
      react/features/conference/components/native/ConferenceNavigationContainerRef.js
  31. 111
    0
      react/features/conference/components/native/ConferenceNavigatorScreenOptions.js
  32. 39
    0
      react/features/conference/components/native/HeaderNavigationButton.js
  33. 1
    0
      react/features/conference/components/native/index.js
  34. 17
    0
      react/features/conference/components/native/routes.js
  35. 4
    0
      react/features/conference/components/native/styles.js
  36. 20
    0
      react/features/conference/functions.native.js
  37. 6
    11
      react/features/etherpad/components/SharedDocumentButton.js
  38. 33
    58
      react/features/etherpad/components/native/SharedDocument.js
  39. 8
    0
      react/features/etherpad/components/native/styles.js
  40. 3
    3
      react/features/invite/actions.native.js
  41. 67
    31
      react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js
  42. 22
    8
      react/features/invite/components/add-people-dialog/native/styles.js
  43. 0
    5
      react/features/invite/constants.js
  44. 15
    6
      react/features/lobby/components/native/LobbyScreen.js
  45. 24
    5
      react/features/lobby/components/native/styles.js
  46. 10
    11
      react/features/participants-pane/components/native/LobbyParticipantList.js
  47. 4
    1
      react/features/participants-pane/components/native/MeetingParticipantList.js
  48. 9
    12
      react/features/participants-pane/components/native/ParticipantsPane.js
  49. 4
    4
      react/features/participants-pane/components/native/ParticipantsPaneButton.js
  50. 16
    18
      react/features/participants-pane/components/native/styles.js
  51. 32
    33
      react/features/polls/components/native/PollCreate.js
  52. 42
    19
      react/features/polls/components/native/PollsPane.js
  53. 12
    6
      react/features/polls/components/native/styles.js
  54. 5
    8
      react/features/toolbox/components/native/Toolbox.js

+ 1
- 1
android/app/src/main/java/org/jitsi/meet/MainActivity.java Vedi File

82
     @Override
82
     @Override
83
     protected void onCreate(Bundle savedInstanceState) {
83
     protected void onCreate(Bundle savedInstanceState) {
84
         JitsiMeet.showSplashScreen(this);
84
         JitsiMeet.showSplashScreen(this);
85
-        super.onCreate(savedInstanceState);
85
+        super.onCreate(null);
86
     }
86
     }
87
 
87
 
88
     @Override
88
     @Override

+ 2
- 2
android/build.gradle Vedi File

110
 
110
 
111
             project.version = "${json.version}-jitsi-${versionQualifierNumber}"
111
             project.version = "${json.version}-jitsi-${versionQualifierNumber}"
112
 
112
 
113
-            task androidSourcesJar(type: Jar) {
113
+            task jitsiAndroidSourcesJar(type: Jar) {
114
                 classifier = 'sources'
114
                 classifier = 'sources'
115
                 from android.sourceSets.main.java.source
115
                 from android.sourceSets.main.java.source
116
             }
116
             }
124
                     artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
124
                     artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
125
                         extension "aar"
125
                         extension "aar"
126
                     }
126
                     }
127
-                    artifact(androidSourcesJar)
127
+                    artifact(jitsiAndroidSourcesJar)
128
                     pom.withXml {
128
                     pom.withXml {
129
                         def pomXml = asNode()
129
                         def pomXml = asNode()
130
                         pomXml.appendNode('name', project.name)
130
                         pomXml.appendNode('name', project.name)

+ 5
- 0
android/sdk/build.gradle Vedi File

70
     implementation project(':react-native-calendar-events')
70
     implementation project(':react-native-calendar-events')
71
     implementation project(':react-native-community_netinfo')
71
     implementation project(':react-native-community_netinfo')
72
     implementation project(':react-native-default-preference')
72
     implementation project(':react-native-default-preference')
73
+    implementation project(':react-native-gesture-handler')
73
     implementation project(':react-native-immersive')
74
     implementation project(':react-native-immersive')
74
     implementation project(':react-native-keep-awake')
75
     implementation project(':react-native-keep-awake')
76
+    implementation project(':react-native-masked-view_masked-view')
75
     implementation project(':react-native-performance')
77
     implementation project(':react-native-performance')
78
+    implementation project(':react-native-reanimated')
79
+    implementation project(':react-native-safe-area-context')
80
+    implementation project(':react-native-screens')
76
     implementation project(':react-native-slider')
81
     implementation project(':react-native-slider')
77
     implementation project(':react-native-sound')
82
     implementation project(':react-native-sound')
78
     implementation project(':react-native-splash-screen')
83
     implementation project(':react-native-splash-screen')

+ 2
- 2
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java Vedi File

24
 import android.os.Bundle;
24
 import android.os.Bundle;
25
 
25
 
26
 import androidx.annotation.Nullable;
26
 import androidx.annotation.Nullable;
27
-import androidx.fragment.app.FragmentActivity;
27
+import androidx.appcompat.app.AppCompatActivity;
28
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
28
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
29
 
29
 
30
 import com.facebook.react.modules.core.PermissionListener;
30
 import com.facebook.react.modules.core.PermissionListener;
38
  * A base activity for SDK users to embed. It uses {@link JitsiMeetFragment} to do the heavy
38
  * A base activity for SDK users to embed. It uses {@link JitsiMeetFragment} to do the heavy
39
  * lifting and wires the remaining Activity lifecycle methods so it works out of the box.
39
  * lifting and wires the remaining Activity lifecycle methods so it works out of the box.
40
  */
40
  */
41
-public class JitsiMeetActivity extends FragmentActivity
41
+public class JitsiMeetActivity extends AppCompatActivity
42
     implements JitsiMeetActivityInterface {
42
     implements JitsiMeetActivityInterface {
43
 
43
 
44
     protected static final String TAG = JitsiMeetActivity.class.getSimpleName();
44
     protected static final String TAG = JitsiMeetActivity.class.getSimpleName();

+ 12
- 7
android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java Vedi File

175
 
175
 
176
         List<ReactPackage> packages
176
         List<ReactPackage> packages
177
             = new ArrayList<>(Arrays.asList(
177
             = new ArrayList<>(Arrays.asList(
178
+                new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
179
+                new com.ocetnik.timer.BackgroundTimerPackage(),
178
                 new com.calendarevents.CalendarEventsPackage(),
180
                 new com.calendarevents.CalendarEventsPackage(),
179
                 new com.corbt.keepawake.KCKeepAwakePackage(),
181
                 new com.corbt.keepawake.KCKeepAwakePackage(),
180
                 new com.facebook.react.shell.MainReactPackage(),
182
                 new com.facebook.react.shell.MainReactPackage(),
181
-                new com.horcrux.svg.SvgPackage(),
182
-                new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
183
-                new com.learnium.RNDeviceInfo.RNDeviceInfo(),
184
-                new com.oblador.performance.PerformancePackage(),
185
-                new com.ocetnik.timer.BackgroundTimerPackage(),
186
-                new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
187
                 new com.reactnativecommunity.netinfo.NetInfoPackage(),
183
                 new com.reactnativecommunity.netinfo.NetInfoPackage(),
184
+                new com.oblador.performance.PerformancePackage(),
188
                 new com.reactnativecommunity.slider.ReactSliderPackage(),
185
                 new com.reactnativecommunity.slider.ReactSliderPackage(),
186
+                new com.brentvatne.react.ReactVideoPackage(),
187
+                new com.swmansion.reanimated.ReanimatedPackage(),
188
+                new org.reactnative.maskedview.RNCMaskedViewPackage(),
189
                 new com.reactnativecommunity.webview.RNCWebViewPackage(),
189
                 new com.reactnativecommunity.webview.RNCWebViewPackage(),
190
+                new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
191
+                new com.learnium.RNDeviceInfo.RNDeviceInfo(),
192
+                new com.swmansion.gesturehandler.react.RNGestureHandlerPackage(),
190
                 new com.rnimmersive.RNImmersivePackage(),
193
                 new com.rnimmersive.RNImmersivePackage(),
194
+                new com.swmansion.rnscreens.RNScreensPackage(),
191
                 new com.zmxv.RNSound.RNSoundPackage(),
195
                 new com.zmxv.RNSound.RNSoundPackage(),
192
-                new com.brentvatne.react.ReactVideoPackage(),
196
+                new com.th3rdwave.safeareacontext.SafeAreaContextPackage(),
197
+                new com.horcrux.svg.SvgPackage(),
193
                 new ReactPackageAdapter() {
198
                 new ReactPackageAdapter() {
194
                     @Override
199
                     @Override
195
                     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
200
                     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

+ 10
- 0
android/settings.gradle Vedi File

15
 project(':react-native-default-preference').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-default-preference/android')
15
 project(':react-native-default-preference').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-default-preference/android')
16
 include ':react-native-device-info'
16
 include ':react-native-device-info'
17
 project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
17
 project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
18
+include ':react-native-gesture-handler'
19
+project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
18
 include ':react-native-google-signin'
20
 include ':react-native-google-signin'
19
 project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android')
21
 project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android')
20
 include ':react-native-immersive'
22
 include ':react-native-immersive'
21
 project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
23
 project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
22
 include ':react-native-keep-awake'
24
 include ':react-native-keep-awake'
23
 project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
25
 project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
26
+include ':react-native-masked-view_masked-view'
27
+project(':react-native-masked-view_masked-view').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-masked-view/masked-view/android')
24
 include ':react-native-performance'
28
 include ':react-native-performance'
25
 project(':react-native-performance').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-performance/android')
29
 project(':react-native-performance').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-performance/android')
30
+include ':react-native-reanimated'
31
+project(':react-native-reanimated').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-reanimated/android')
32
+include ':react-native-safe-area-context'
33
+project(':react-native-safe-area-context').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-safe-area-context/android')
34
+include ':react-native-screens'
35
+project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-screens/android')
26
 include ':react-native-slider'
36
 include ':react-native-slider'
27
 project(':react-native-slider').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/slider/android')
37
 project(':react-native-slider').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/slider/android')
28
 include ':react-native-sound'
38
 include ':react-native-sound'

+ 5
- 0
ios/Podfile Vedi File

72
   pod 'RNSVG', :path => '../node_modules/react-native-svg'
72
   pod 'RNSVG', :path => '../node_modules/react-native-svg'
73
   pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
73
   pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
74
   pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
74
   pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
75
+  pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler'
76
+  pod 'RNReanimated', :path => '../node_modules/react-native-reanimated'
77
+  pod 'RNScreens', :path => '../node_modules/react-native-screens'
78
+  pod 'react-native-safe-area-context', :path => '../node_modules/react-native-safe-area-context'
79
+  pod 'RNCMaskedView', :path => '../node_modules/@react-native-masked-view/masked-view'
75
 
80
 
76
   # Native pod dependencies
81
   # Native pod dependencies
77
   #
82
   #

+ 33
- 3
ios/Podfile.lock Vedi File

109
   - GTMAppAuth (1.2.2):
109
   - GTMAppAuth (1.2.2):
110
     - AppAuth/Core (~> 1.4)
110
     - AppAuth/Core (~> 1.4)
111
     - GTMSessionFetcher/Core (~> 1.5)
111
     - GTMSessionFetcher/Core (~> 1.5)
112
-  - GTMSessionFetcher/Core (1.6.1)
112
+  - GTMSessionFetcher/Core (1.7.0)
113
   - nanopb (1.30906.0):
113
   - nanopb (1.30906.0):
114
     - nanopb/decode (= 1.30906.0)
114
     - nanopb/decode (= 1.30906.0)
115
     - nanopb/encode (= 1.30906.0)
115
     - nanopb/encode (= 1.30906.0)
290
     - React
290
     - React
291
   - react-native-performance (2.0.0):
291
   - react-native-performance (2.0.0):
292
     - React-Core
292
     - React-Core
293
+  - react-native-safe-area-context (3.3.2):
294
+    - React-Core
293
   - react-native-slider (3.0.3):
295
   - react-native-slider (3.0.3):
294
     - React
296
     - React
295
   - react-native-splash-screen (3.2.0):
297
   - react-native-splash-screen (3.2.0):
359
     - ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
361
     - ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
360
   - RNCAsyncStorage (1.15.5):
362
   - RNCAsyncStorage (1.15.5):
361
     - React-Core
363
     - React-Core
364
+  - RNCMaskedView (0.2.6):
365
+    - React-Core
362
   - RNDefaultPreference (1.4.2):
366
   - RNDefaultPreference (1.4.2):
363
     - React
367
     - React
364
   - RNDeviceInfo (8.0.0):
368
   - RNDeviceInfo (8.0.0):
365
     - React-Core
369
     - React-Core
370
+  - RNGestureHandler (1.10.3):
371
+    - React-Core
366
   - RNGoogleSignin (3.0.1):
372
   - RNGoogleSignin (3.0.1):
367
     - GoogleSignIn (~> 5.0.0)
373
     - GoogleSignIn (~> 5.0.0)
368
     - React
374
     - React
375
+  - RNReanimated (1.13.3):
376
+    - React-Core
377
+  - RNScreens (2.18.1):
378
+    - React-Core
369
   - RNSound (0.11.0):
379
   - RNSound (0.11.0):
370
     - React
380
     - React
371
     - RNSound/Core (= 0.11.0)
381
     - RNSound/Core (= 0.11.0)
405
   - react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
415
   - react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
406
   - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
416
   - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
407
   - react-native-performance (from `../node_modules/react-native-performance/ios`)
417
   - react-native-performance (from `../node_modules/react-native-performance/ios`)
418
+  - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
408
   - "react-native-slider (from `../node_modules/@react-native-community/slider`)"
419
   - "react-native-slider (from `../node_modules/@react-native-community/slider`)"
409
   - react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
420
   - react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
410
   - react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
421
   - react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
421
   - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
432
   - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
422
   - ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
433
   - ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
423
   - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
434
   - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
435
+  - "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
424
   - RNDefaultPreference (from `../node_modules/react-native-default-preference`)
436
   - RNDefaultPreference (from `../node_modules/react-native-default-preference`)
425
   - RNDeviceInfo (from `../node_modules/react-native-device-info`)
437
   - RNDeviceInfo (from `../node_modules/react-native-device-info`)
438
+  - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
426
   - "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)"
439
   - "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)"
440
+  - RNReanimated (from `../node_modules/react-native-reanimated`)
441
+  - RNScreens (from `../node_modules/react-native-screens`)
427
   - RNSound (from `../node_modules/react-native-sound`)
442
   - RNSound (from `../node_modules/react-native-sound`)
428
   - RNSVG (from `../node_modules/react-native-svg`)
443
   - RNSVG (from `../node_modules/react-native-svg`)
429
   - RNWatch (from `../node_modules/react-native-watch-connectivity`)
444
   - RNWatch (from `../node_modules/react-native-watch-connectivity`)
493
     :path: "../node_modules/@react-native-community/netinfo"
508
     :path: "../node_modules/@react-native-community/netinfo"
494
   react-native-performance:
509
   react-native-performance:
495
     :path: "../node_modules/react-native-performance/ios"
510
     :path: "../node_modules/react-native-performance/ios"
511
+  react-native-safe-area-context:
512
+    :path: "../node_modules/react-native-safe-area-context"
496
   react-native-slider:
513
   react-native-slider:
497
     :path: "../node_modules/@react-native-community/slider"
514
     :path: "../node_modules/@react-native-community/slider"
498
   react-native-splash-screen:
515
   react-native-splash-screen:
525
     :path: "../node_modules/react-native/ReactCommon"
542
     :path: "../node_modules/react-native/ReactCommon"
526
   RNCAsyncStorage:
543
   RNCAsyncStorage:
527
     :path: "../node_modules/@react-native-async-storage/async-storage"
544
     :path: "../node_modules/@react-native-async-storage/async-storage"
545
+  RNCMaskedView:
546
+    :path: "../node_modules/@react-native-masked-view/masked-view"
528
   RNDefaultPreference:
547
   RNDefaultPreference:
529
     :path: "../node_modules/react-native-default-preference"
548
     :path: "../node_modules/react-native-default-preference"
530
   RNDeviceInfo:
549
   RNDeviceInfo:
531
     :path: "../node_modules/react-native-device-info"
550
     :path: "../node_modules/react-native-device-info"
551
+  RNGestureHandler:
552
+    :path: "../node_modules/react-native-gesture-handler"
532
   RNGoogleSignin:
553
   RNGoogleSignin:
533
     :path: "../node_modules/@react-native-community/google-signin"
554
     :path: "../node_modules/@react-native-community/google-signin"
555
+  RNReanimated:
556
+    :path: "../node_modules/react-native-reanimated"
557
+  RNScreens:
558
+    :path: "../node_modules/react-native-screens"
534
   RNSound:
559
   RNSound:
535
     :path: "../node_modules/react-native-sound"
560
     :path: "../node_modules/react-native-sound"
536
   RNSVG:
561
   RNSVG:
563
   GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
588
   GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
564
   GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
589
   GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
565
   GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
590
   GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
566
-  GTMSessionFetcher: 36689134877faeb055b27dfa4ccc9ceaa42e029e
591
+  GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91
567
   nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
592
   nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
568
   ObjectiveDropboxOfficial: b4765572e334d6fc6214b43a7595510324bbbbaa
593
   ObjectiveDropboxOfficial: b4765572e334d6fc6214b43a7595510324bbbbaa
569
   PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
594
   PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
581
   react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
606
   react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
582
   react-native-netinfo: 0e563248a4b9a99c33ec29bd03c2d50767db22a6
607
   react-native-netinfo: 0e563248a4b9a99c33ec29bd03c2d50767db22a6
583
   react-native-performance: 6bd6cfac80594775fb782405fceaaf206becf53b
608
   react-native-performance: 6bd6cfac80594775fb782405fceaaf206becf53b
609
+  react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
584
   react-native-slider: e99fc201cefe81270fc9d81714a7a0f5e566b168
610
   react-native-slider: e99fc201cefe81270fc9d81714a7a0f5e566b168
585
   react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
611
   react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
586
   react-native-video: 0bb76b6d6b77da3009611586c7dbf817b947f30e
612
   react-native-video: 0bb76b6d6b77da3009611586c7dbf817b947f30e
597
   React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
623
   React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
598
   ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
624
   ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
599
   RNCAsyncStorage: 56a3355a10b5d660c48c6e37325ac85ebfd09885
625
   RNCAsyncStorage: 56a3355a10b5d660c48c6e37325ac85ebfd09885
626
+  RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd
600
   RNDefaultPreference: 1f8133ec0bc0f9453cdada578564ba1ef551fb44
627
   RNDefaultPreference: 1f8133ec0bc0f9453cdada578564ba1ef551fb44
601
   RNDeviceInfo: 87d2d175c760f6bcf58acd036f887e8b2392802c
628
   RNDeviceInfo: 87d2d175c760f6bcf58acd036f887e8b2392802c
629
+  RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
602
   RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
630
   RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
631
+  RNReanimated: 514a11da3a2bcc6c3dfd9de32b38e2b9bf101926
632
+  RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
603
   RNSound: da030221e6ac7e8290c6b43f2b5f2133a8e225b0
633
   RNSound: da030221e6ac7e8290c6b43f2b5f2133a8e225b0
604
   RNSVG: ce9d996113475209013317e48b05c21ee988d42e
634
   RNSVG: ce9d996113475209013317e48b05c21ee988d42e
605
   RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
635
   RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
606
   Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
636
   Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
607
 
637
 
608
-PODFILE CHECKSUM: 3cc305fd6ee83fff506c10c4805471fa72b61c9a
638
+PODFILE CHECKSUM: 42be6796ba6ac039dae5c02125677728ecd0df0d
609
 
639
 
610
 COCOAPODS: 1.10.1
640
 COCOAPODS: 1.10.1

+ 482
- 128
package-lock.json Vedi File

37
         "@react-native-community/google-signin": "3.0.1",
37
         "@react-native-community/google-signin": "3.0.1",
38
         "@react-native-community/netinfo": "4.1.5",
38
         "@react-native-community/netinfo": "4.1.5",
39
         "@react-native-community/slider": "3.0.3",
39
         "@react-native-community/slider": "3.0.3",
40
+        "@react-native-masked-view/masked-view": "0.2.6",
41
+        "@react-navigation/material-top-tabs": "5.3.19",
42
+        "@react-navigation/native": "5.9.8",
43
+        "@react-navigation/stack": "5.14.9",
40
         "@svgr/webpack": "4.3.2",
44
         "@svgr/webpack": "4.3.2",
41
         "amplitude-js": "8.2.1",
45
         "amplitude-js": "8.2.1",
42
         "base64-js": "1.3.1",
46
         "base64-js": "1.3.1",
76
         "react-native-collapsible": "1.5.1",
80
         "react-native-collapsible": "1.5.1",
77
         "react-native-default-preference": "1.4.2",
81
         "react-native-default-preference": "1.4.2",
78
         "react-native-device-info": "8.0.0",
82
         "react-native-device-info": "8.0.0",
83
+        "react-native-gesture-handler": "1.10.3",
79
         "react-native-immersive": "2.0.0",
84
         "react-native-immersive": "2.0.0",
80
         "react-native-keep-awake": "4.0.0",
85
         "react-native-keep-awake": "4.0.0",
81
         "react-native-paper": "4.8.1",
86
         "react-native-paper": "4.8.1",
82
         "react-native-performance": "2.0.0",
87
         "react-native-performance": "2.0.0",
88
+        "react-native-reanimated": "1.13.3",
89
+        "react-native-safe-area-context": "3.3.2",
90
+        "react-native-screens": "2.18.1",
83
         "react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
91
         "react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
84
         "react-native-splash-screen": "3.2.0",
92
         "react-native-splash-screen": "3.2.0",
85
         "react-native-svg": "12.1.0",
93
         "react-native-svg": "12.1.0",
86
         "react-native-svg-transformer": "0.14.3",
94
         "react-native-svg-transformer": "0.14.3",
95
+        "react-native-tab-view": "2.16.0",
87
         "react-native-url-polyfill": "1.2.0",
96
         "react-native-url-polyfill": "1.2.0",
88
         "react-native-video": "5.1.1",
97
         "react-native-video": "5.1.1",
89
         "react-native-watch-connectivity": "0.4.3",
98
         "react-native-watch-connectivity": "0.4.3",
2929
         "node": ">=10.0.0"
2938
         "node": ">=10.0.0"
2930
       }
2939
       }
2931
     },
2940
     },
2941
+    "node_modules/@egjs/hammerjs": {
2942
+      "version": "2.0.17",
2943
+      "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
2944
+      "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
2945
+      "dependencies": {
2946
+        "@types/hammerjs": "^2.0.36"
2947
+      },
2948
+      "engines": {
2949
+        "node": ">=0.8.0"
2950
+      }
2951
+    },
2932
     "node_modules/@emotion/cache": {
2952
     "node_modules/@emotion/cache": {
2933
       "version": "10.0.29",
2953
       "version": "10.0.29",
2934
       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
2954
       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
4036
         "react-native": "*"
4056
         "react-native": "*"
4037
       }
4057
       }
4038
     },
4058
     },
4059
+    "node_modules/@react-native-masked-view/masked-view": {
4060
+      "version": "0.2.6",
4061
+      "resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz",
4062
+      "integrity": "sha512-303CxmetUmgiX9NSUxatZkNh9qTYYdiM8xkGf9I3Uj20U3eGY3M78ljeNQ4UVCJA+FNGS5nC1dtS9GjIqvB4dg==",
4063
+      "peerDependencies": {
4064
+        "react": "16 || 17",
4065
+        "react-native": ">=0.57"
4066
+      }
4067
+    },
4068
+    "node_modules/@react-navigation/core": {
4069
+      "version": "5.16.1",
4070
+      "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.16.1.tgz",
4071
+      "integrity": "sha512-3AToC7vPNeSNcHFLd1h71L6u34hfXoRAS1CxF9Fc4uC8uOrVqcNvphpeFbE0O9Bw6Zpl0BnMFl7E5gaL3KGzNA==",
4072
+      "dependencies": {
4073
+        "@react-navigation/routers": "^5.7.4",
4074
+        "escape-string-regexp": "^4.0.0",
4075
+        "nanoid": "^3.1.15",
4076
+        "query-string": "^6.13.6",
4077
+        "react-is": "^16.13.0"
4078
+      },
4079
+      "peerDependencies": {
4080
+        "react": "*"
4081
+      }
4082
+    },
4083
+    "node_modules/@react-navigation/core/node_modules/escape-string-regexp": {
4084
+      "version": "4.0.0",
4085
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
4086
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
4087
+      "engines": {
4088
+        "node": ">=10"
4089
+      },
4090
+      "funding": {
4091
+        "url": "https://github.com/sponsors/sindresorhus"
4092
+      }
4093
+    },
4094
+    "node_modules/@react-navigation/core/node_modules/query-string": {
4095
+      "version": "6.14.1",
4096
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
4097
+      "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==",
4098
+      "dependencies": {
4099
+        "decode-uri-component": "^0.2.0",
4100
+        "filter-obj": "^1.1.0",
4101
+        "split-on-first": "^1.0.0",
4102
+        "strict-uri-encode": "^2.0.0"
4103
+      },
4104
+      "engines": {
4105
+        "node": ">=6"
4106
+      },
4107
+      "funding": {
4108
+        "url": "https://github.com/sponsors/sindresorhus"
4109
+      }
4110
+    },
4111
+    "node_modules/@react-navigation/core/node_modules/strict-uri-encode": {
4112
+      "version": "2.0.0",
4113
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
4114
+      "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
4115
+      "engines": {
4116
+        "node": ">=4"
4117
+      }
4118
+    },
4119
+    "node_modules/@react-navigation/material-top-tabs": {
4120
+      "version": "5.3.19",
4121
+      "resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
4122
+      "integrity": "sha512-I7bEF99THxxcY7kCUZ5pPmwXr6kgo6L2sg3P1YJo+CcBWSGvGiHyNbZXNs15HuKRuFvEuueChNV9n8QuKBWbDA==",
4123
+      "dependencies": {
4124
+        "color": "^3.1.3"
4125
+      },
4126
+      "peerDependencies": {
4127
+        "@react-navigation/native": "^5.0.5",
4128
+        "react": "*",
4129
+        "react-native": "*",
4130
+        "react-native-gesture-handler": ">= 1.0.0",
4131
+        "react-native-reanimated": ">= 1.0.0",
4132
+        "react-native-tab-view": ">= 2.0.0"
4133
+      }
4134
+    },
4135
+    "node_modules/@react-navigation/native": {
4136
+      "version": "5.9.8",
4137
+      "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-5.9.8.tgz",
4138
+      "integrity": "sha512-DNbcDHXQPSFDLn51kkVVJjT3V7jJy2GztNYZe/2bEg29mi5QEcHHcpifjMCtyFKntAOWzKlG88UicIQ17UEghg==",
4139
+      "dependencies": {
4140
+        "@react-navigation/core": "^5.16.1",
4141
+        "escape-string-regexp": "^4.0.0",
4142
+        "nanoid": "^3.1.15"
4143
+      },
4144
+      "peerDependencies": {
4145
+        "react": "*",
4146
+        "react-native": "*"
4147
+      }
4148
+    },
4149
+    "node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
4150
+      "version": "4.0.0",
4151
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
4152
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
4153
+      "engines": {
4154
+        "node": ">=10"
4155
+      },
4156
+      "funding": {
4157
+        "url": "https://github.com/sponsors/sindresorhus"
4158
+      }
4159
+    },
4160
+    "node_modules/@react-navigation/routers": {
4161
+      "version": "5.7.4",
4162
+      "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-5.7.4.tgz",
4163
+      "integrity": "sha512-0N202XAqsU/FlE53Nmh6GHyMtGm7g6TeC93mrFAFJOqGRKznT0/ail+cYlU6tNcPA9AHzZu1Modw1eoDINSliQ==",
4164
+      "dependencies": {
4165
+        "nanoid": "^3.1.15"
4166
+      }
4167
+    },
4168
+    "node_modules/@react-navigation/stack": {
4169
+      "version": "5.14.9",
4170
+      "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-5.14.9.tgz",
4171
+      "integrity": "sha512-DuvrT9P+Tz8ezZLQYxORZqOGqO+vEufaxlW1hSLw1knLD4jNxkz8TJDXtfKwaz//9gb43UhTNccNM02vm7iPqQ==",
4172
+      "dependencies": {
4173
+        "color": "^3.1.3",
4174
+        "react-native-iphone-x-helper": "^1.3.0"
4175
+      },
4176
+      "peerDependencies": {
4177
+        "@react-native-community/masked-view": ">= 0.1.0",
4178
+        "@react-navigation/native": "^5.0.5",
4179
+        "react": "*",
4180
+        "react-native": "*",
4181
+        "react-native-gesture-handler": ">= 1.0.0",
4182
+        "react-native-safe-area-context": ">= 0.6.0",
4183
+        "react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
4184
+      }
4185
+    },
4039
     "node_modules/@svgr/babel-plugin-add-jsx-attribute": {
4186
     "node_modules/@svgr/babel-plugin-add-jsx-attribute": {
4040
       "version": "4.2.0",
4187
       "version": "4.2.0",
4041
       "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
4188
       "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
5045
       "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
5192
       "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
5046
       "dev": true
5193
       "dev": true
5047
     },
5194
     },
5195
+    "node_modules/@types/hammerjs": {
5196
+      "version": "2.0.40",
5197
+      "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.40.tgz",
5198
+      "integrity": "sha512-VbjwR1fhsn2h2KXAY4oy1fm7dCxaKy0D+deTb8Ilc3Eo3rc5+5eA4rfYmZaHgNJKxVyI0f6WIXzO2zLkVmQPHA=="
5199
+    },
5048
     "node_modules/@types/http-proxy": {
5200
     "node_modules/@types/http-proxy": {
5049
       "version": "1.17.7",
5201
       "version": "1.17.7",
5050
       "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
5202
       "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
7651
         "object-assign": "^4.1.1"
7803
         "object-assign": "^4.1.1"
7652
       }
7804
       }
7653
     },
7805
     },
7806
+    "node_modules/cross-fetch": {
7807
+      "version": "3.1.4",
7808
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",
7809
+      "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==",
7810
+      "dependencies": {
7811
+        "node-fetch": "2.6.1"
7812
+      }
7813
+    },
7814
+    "node_modules/cross-fetch/node_modules/node-fetch": {
7815
+      "version": "2.6.1",
7816
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
7817
+      "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
7818
+      "engines": {
7819
+        "node": "4.x || >=6.0.0"
7820
+      }
7821
+    },
7654
     "node_modules/cross-os": {
7822
     "node_modules/cross-os": {
7655
       "version": "1.4.0",
7823
       "version": "1.4.0",
7656
       "resolved": "https://registry.npmjs.org/cross-os/-/cross-os-1.4.0.tgz",
7824
       "resolved": "https://registry.npmjs.org/cross-os/-/cross-os-1.4.0.tgz",
10014
         "node": ">=0.10.0"
10182
         "node": ">=0.10.0"
10015
       }
10183
       }
10016
     },
10184
     },
10185
+    "node_modules/filter-obj": {
10186
+      "version": "1.1.0",
10187
+      "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
10188
+      "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
10189
+      "engines": {
10190
+        "node": ">=0.10.0"
10191
+      }
10192
+    },
10017
     "node_modules/finalhandler": {
10193
     "node_modules/finalhandler": {
10018
       "version": "1.1.2",
10194
       "version": "1.1.2",
10019
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
10195
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
10582
       }
10758
       }
10583
     },
10759
     },
10584
     "node_modules/fsevents/node_modules/mkdirp": {
10760
     "node_modules/fsevents/node_modules/mkdirp": {
10585
-      "version": "0.5.5",
10761
+      "version": "0.5.1",
10586
       "inBundle": true,
10762
       "inBundle": true,
10587
       "license": "MIT",
10763
       "license": "MIT",
10588
       "optional": true,
10764
       "optional": true,
10589
       "dependencies": {
10765
       "dependencies": {
10590
-        "minimist": "^1.2.5"
10766
+        "minimist": "0.0.8"
10591
       },
10767
       },
10592
       "bin": {
10768
       "bin": {
10593
         "mkdirp": "bin/cmd.js"
10769
         "mkdirp": "bin/cmd.js"
10764
       }
10940
       }
10765
     },
10941
     },
10766
     "node_modules/fsevents/node_modules/rc/node_modules/minimist": {
10942
     "node_modules/fsevents/node_modules/rc/node_modules/minimist": {
10767
-      "version": "1.2.5",
10943
+      "version": "1.2.0",
10768
       "inBundle": true,
10944
       "inBundle": true,
10769
       "license": "MIT",
10945
       "license": "MIT",
10770
       "optional": true
10946
       "optional": true
11812
       }
11988
       }
11813
     },
11989
     },
11814
     "node_modules/invariant": {
11990
     "node_modules/invariant": {
11815
-      "version": "2.2.3",
11816
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz",
11817
-      "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==",
11991
+      "version": "2.2.4",
11992
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
11993
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
11818
       "dependencies": {
11994
       "dependencies": {
11819
         "loose-envify": "^1.0.0"
11995
         "loose-envify": "^1.0.0"
11820
       }
11996
       }
12382
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
12558
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
12383
       "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
12559
       "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
12384
     },
12560
     },
12385
-    "node_modules/jest-haste-map/node_modules/invariant": {
12386
-      "version": "2.2.4",
12387
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
12388
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
12389
-      "dependencies": {
12390
-        "loose-envify": "^1.0.0"
12391
-      }
12392
-    },
12393
     "node_modules/jest-message-util": {
12561
     "node_modules/jest-message-util": {
12394
       "version": "24.9.0",
12562
       "version": "24.9.0",
12395
       "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
12563
       "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
13641
         "vlq": "^1.0.0"
13809
         "vlq": "^1.0.0"
13642
       }
13810
       }
13643
     },
13811
     },
13644
-    "node_modules/metro-source-map/node_modules/invariant": {
13645
-      "version": "2.2.4",
13646
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
13647
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
13648
-      "dependencies": {
13649
-        "loose-envify": "^1.0.0"
13650
-      }
13651
-    },
13652
     "node_modules/metro-symbolicate": {
13812
     "node_modules/metro-symbolicate": {
13653
       "version": "0.56.4",
13813
       "version": "0.56.4",
13654
       "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.56.4.tgz",
13814
       "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.56.4.tgz",
13667
         "node": ">=8.3"
13827
         "node": ">=8.3"
13668
       }
13828
       }
13669
     },
13829
     },
13670
-    "node_modules/metro-symbolicate/node_modules/invariant": {
13671
-      "version": "2.2.4",
13672
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
13673
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
13674
-      "dependencies": {
13675
-        "loose-envify": "^1.0.0"
13676
-      }
13677
-    },
13678
     "node_modules/metro/node_modules/@babel/helper-plugin-utils": {
13830
     "node_modules/metro/node_modules/@babel/helper-plugin-utils": {
13679
       "version": "7.8.3",
13831
       "version": "7.8.3",
13680
       "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
13832
       "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
13759
         "klaw": "^1.0.0"
13911
         "klaw": "^1.0.0"
13760
       }
13912
       }
13761
     },
13913
     },
13762
-    "node_modules/metro/node_modules/invariant": {
13763
-      "version": "2.2.4",
13764
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
13765
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
13766
-      "dependencies": {
13767
-        "loose-envify": "^1.0.0"
13768
-      }
13769
-    },
13770
     "node_modules/metro/node_modules/jsonfile": {
13914
     "node_modules/metro/node_modules/jsonfile": {
13771
       "version": "2.4.0",
13915
       "version": "2.4.0",
13772
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
13916
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
14124
       "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
14268
       "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
14125
       "optional": true
14269
       "optional": true
14126
     },
14270
     },
14271
+    "node_modules/nanoid": {
14272
+      "version": "3.1.30",
14273
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
14274
+      "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
14275
+      "bin": {
14276
+        "nanoid": "bin/nanoid.cjs"
14277
+      },
14278
+      "engines": {
14279
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
14280
+      }
14281
+    },
14127
     "node_modules/nanomatch": {
14282
     "node_modules/nanomatch": {
14128
       "version": "1.2.13",
14283
       "version": "1.2.13",
14129
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
14284
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
16558
         "react-native": "*"
16713
         "react-native": "*"
16559
       }
16714
       }
16560
     },
16715
     },
16716
+    "node_modules/react-native-gesture-handler": {
16717
+      "version": "1.10.3",
16718
+      "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz",
16719
+      "integrity": "sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw==",
16720
+      "dependencies": {
16721
+        "@egjs/hammerjs": "^2.0.17",
16722
+        "fbjs": "^3.0.0",
16723
+        "hoist-non-react-statics": "^3.3.0",
16724
+        "invariant": "^2.2.4",
16725
+        "prop-types": "^15.7.2"
16726
+      }
16727
+    },
16728
+    "node_modules/react-native-gesture-handler/node_modules/fbjs": {
16729
+      "version": "3.0.0",
16730
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz",
16731
+      "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==",
16732
+      "dependencies": {
16733
+        "cross-fetch": "^3.0.4",
16734
+        "fbjs-css-vars": "^1.0.0",
16735
+        "loose-envify": "^1.0.0",
16736
+        "object-assign": "^4.1.0",
16737
+        "promise": "^7.1.1",
16738
+        "setimmediate": "^1.0.5",
16739
+        "ua-parser-js": "^0.7.18"
16740
+      }
16741
+    },
16561
     "node_modules/react-native-immersive": {
16742
     "node_modules/react-native-immersive": {
16562
       "version": "2.0.0",
16743
       "version": "2.0.0",
16563
       "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
16744
       "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
16602
         "react-native": "*"
16783
         "react-native": "*"
16603
       }
16784
       }
16604
     },
16785
     },
16786
+    "node_modules/react-native-reanimated": {
16787
+      "version": "1.13.3",
16788
+      "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.13.3.tgz",
16789
+      "integrity": "sha512-i714H24dv6ncpFO7/SZ0PfAMbvjgVbF8Ow2NPtowoZAz8osS54DmTMrkgJ9Za+uEku/s0AEaxqiXG2Xgntvv2g==",
16790
+      "dependencies": {
16791
+        "fbjs": "^1.0.0"
16792
+      },
16793
+      "peerDependencies": {
16794
+        "react": "*",
16795
+        "react-native": "*"
16796
+      }
16797
+    },
16798
+    "node_modules/react-native-reanimated/node_modules/fbjs": {
16799
+      "version": "1.0.0",
16800
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-1.0.0.tgz",
16801
+      "integrity": "sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA==",
16802
+      "dependencies": {
16803
+        "core-js": "^2.4.1",
16804
+        "fbjs-css-vars": "^1.0.0",
16805
+        "isomorphic-fetch": "^2.1.1",
16806
+        "loose-envify": "^1.0.0",
16807
+        "object-assign": "^4.1.0",
16808
+        "promise": "^7.1.1",
16809
+        "setimmediate": "^1.0.5",
16810
+        "ua-parser-js": "^0.7.18"
16811
+      }
16812
+    },
16813
+    "node_modules/react-native-safe-area-context": {
16814
+      "version": "3.3.2",
16815
+      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
16816
+      "integrity": "sha512-yOwiiPJ1rk+/nfK13eafbpW6sKW0jOnsRem2C1LPJjM3tfTof6hlvV5eWHATye3XOpu2cJ7N+HdkUvUDGwFD2Q==",
16817
+      "peerDependencies": {
16818
+        "react": "*",
16819
+        "react-native": "*"
16820
+      }
16821
+    },
16822
+    "node_modules/react-native-screens": {
16823
+      "version": "2.18.1",
16824
+      "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.18.1.tgz",
16825
+      "integrity": "sha512-r5WZLpmx2hHjC1RgMdPq5YpSU9tEhBpUaZ5M1SUtNIONyiLqQVxabhRCINdebIk4depJiIl7yw2Q85zJyeX6fw==",
16826
+      "peerDependencies": {
16827
+        "react": "*",
16828
+        "react-native": "*"
16829
+      }
16830
+    },
16605
     "node_modules/react-native-sound": {
16831
     "node_modules/react-native-sound": {
16606
       "version": "0.11.0",
16832
       "version": "0.11.0",
16607
       "resolved": "git+ssh://git@github.com/jitsi/react-native-sound.git#3fe5480fce935e888d5089d94a191c7c7e3aa190",
16833
       "resolved": "git+ssh://git@github.com/jitsi/react-native-sound.git#3fe5480fce935e888d5089d94a191c7c7e3aa190",
16734
         "semver": "bin/semver"
16960
         "semver": "bin/semver"
16735
       }
16961
       }
16736
     },
16962
     },
16963
+    "node_modules/react-native-tab-view": {
16964
+      "version": "2.16.0",
16965
+      "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.16.0.tgz",
16966
+      "integrity": "sha512-ac2DmT7+l13wzIFqtbfXn4wwfgtPoKzWjjZyrK1t+T8sdemuUvD4zIt+UImg03fu3s3VD8Wh/fBrIdcqQyZJWg==",
16967
+      "peerDependencies": {
16968
+        "react": "*",
16969
+        "react-native": "*",
16970
+        "react-native-gesture-handler": "*",
16971
+        "react-native-reanimated": "*"
16972
+      }
16973
+    },
16737
     "node_modules/react-native-url-polyfill": {
16974
     "node_modules/react-native-url-polyfill": {
16738
       "version": "1.2.0",
16975
       "version": "1.2.0",
16739
       "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
16976
       "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
16809
         "node": ">=8"
17046
         "node": ">=8"
16810
       }
17047
       }
16811
     },
17048
     },
16812
-    "node_modules/react-native-webview/node_modules/invariant": {
16813
-      "version": "2.2.4",
16814
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
16815
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
16816
-      "dependencies": {
16817
-        "loose-envify": "^1.0.0"
16818
-      }
16819
-    },
16820
     "node_modules/react-native-youtube-iframe": {
17049
     "node_modules/react-native-youtube-iframe": {
16821
       "version": "2.1.1",
17050
       "version": "2.1.1",
16822
       "resolved": "https://registry.npmjs.org/react-native-youtube-iframe/-/react-native-youtube-iframe-2.1.1.tgz",
17051
       "resolved": "https://registry.npmjs.org/react-native-youtube-iframe/-/react-native-youtube-iframe-2.1.1.tgz",
16854
         "ua-parser-js": "^0.7.18"
17083
         "ua-parser-js": "^0.7.18"
16855
       }
17084
       }
16856
     },
17085
     },
16857
-    "node_modules/react-native/node_modules/invariant": {
16858
-      "version": "2.2.4",
16859
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
16860
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
16861
-      "dependencies": {
16862
-        "loose-envify": "^1.0.0"
16863
-      }
16864
-    },
16865
     "node_modules/react-native/node_modules/whatwg-fetch": {
17086
     "node_modules/react-native/node_modules/whatwg-fetch": {
16866
       "version": "3.0.0",
17087
       "version": "3.0.0",
16867
       "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
17088
       "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
16902
         "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0"
17123
         "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0"
16903
       }
17124
       }
16904
     },
17125
     },
16905
-    "node_modules/react-redux/node_modules/invariant": {
16906
-      "version": "2.2.4",
16907
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
16908
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
16909
-      "dependencies": {
16910
-        "loose-envify": "^1.0.0"
16911
-      }
16912
-    },
16913
     "node_modules/react-redux/node_modules/loose-envify": {
17126
     "node_modules/react-redux/node_modules/loose-envify": {
16914
       "version": "1.4.0",
17127
       "version": "1.4.0",
16915
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
17128
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
18275
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
18488
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
18276
       "dev": true
18489
       "dev": true
18277
     },
18490
     },
18491
+    "node_modules/split-on-first": {
18492
+      "version": "1.1.0",
18493
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
18494
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
18495
+      "engines": {
18496
+        "node": ">=6"
18497
+      }
18498
+    },
18278
     "node_modules/split-string": {
18499
     "node_modules/split-string": {
18279
       "version": "3.1.0",
18500
       "version": "3.1.0",
18280
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
18501
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
24126
       "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
24347
       "integrity": "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==",
24127
       "dev": true
24348
       "dev": true
24128
     },
24349
     },
24350
+    "@egjs/hammerjs": {
24351
+      "version": "2.0.17",
24352
+      "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
24353
+      "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
24354
+      "requires": {
24355
+        "@types/hammerjs": "^2.0.36"
24356
+      }
24357
+    },
24129
     "@emotion/cache": {
24358
     "@emotion/cache": {
24130
       "version": "10.0.29",
24359
       "version": "10.0.29",
24131
       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
24360
       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
24988
       "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-3.0.3.tgz",
25217
       "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-3.0.3.tgz",
24989
       "integrity": "sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw=="
25218
       "integrity": "sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw=="
24990
     },
25219
     },
25220
+    "@react-native-masked-view/masked-view": {
25221
+      "version": "0.2.6",
25222
+      "resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz",
25223
+      "integrity": "sha512-303CxmetUmgiX9NSUxatZkNh9qTYYdiM8xkGf9I3Uj20U3eGY3M78ljeNQ4UVCJA+FNGS5nC1dtS9GjIqvB4dg=="
25224
+    },
25225
+    "@react-navigation/core": {
25226
+      "version": "5.16.1",
25227
+      "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.16.1.tgz",
25228
+      "integrity": "sha512-3AToC7vPNeSNcHFLd1h71L6u34hfXoRAS1CxF9Fc4uC8uOrVqcNvphpeFbE0O9Bw6Zpl0BnMFl7E5gaL3KGzNA==",
25229
+      "requires": {
25230
+        "@react-navigation/routers": "^5.7.4",
25231
+        "escape-string-regexp": "^4.0.0",
25232
+        "nanoid": "^3.1.15",
25233
+        "query-string": "^6.13.6",
25234
+        "react-is": "^16.13.0"
25235
+      },
25236
+      "dependencies": {
25237
+        "escape-string-regexp": {
25238
+          "version": "4.0.0",
25239
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
25240
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
25241
+        },
25242
+        "query-string": {
25243
+          "version": "6.14.1",
25244
+          "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
25245
+          "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==",
25246
+          "requires": {
25247
+            "decode-uri-component": "^0.2.0",
25248
+            "filter-obj": "^1.1.0",
25249
+            "split-on-first": "^1.0.0",
25250
+            "strict-uri-encode": "^2.0.0"
25251
+          }
25252
+        },
25253
+        "strict-uri-encode": {
25254
+          "version": "2.0.0",
25255
+          "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
25256
+          "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
25257
+        }
25258
+      }
25259
+    },
25260
+    "@react-navigation/material-top-tabs": {
25261
+      "version": "5.3.19",
25262
+      "resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
25263
+      "integrity": "sha512-I7bEF99THxxcY7kCUZ5pPmwXr6kgo6L2sg3P1YJo+CcBWSGvGiHyNbZXNs15HuKRuFvEuueChNV9n8QuKBWbDA==",
25264
+      "requires": {
25265
+        "color": "^3.1.3"
25266
+      }
25267
+    },
25268
+    "@react-navigation/native": {
25269
+      "version": "5.9.8",
25270
+      "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-5.9.8.tgz",
25271
+      "integrity": "sha512-DNbcDHXQPSFDLn51kkVVJjT3V7jJy2GztNYZe/2bEg29mi5QEcHHcpifjMCtyFKntAOWzKlG88UicIQ17UEghg==",
25272
+      "requires": {
25273
+        "@react-navigation/core": "^5.16.1",
25274
+        "escape-string-regexp": "^4.0.0",
25275
+        "nanoid": "^3.1.15"
25276
+      },
25277
+      "dependencies": {
25278
+        "escape-string-regexp": {
25279
+          "version": "4.0.0",
25280
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
25281
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
25282
+        }
25283
+      }
25284
+    },
25285
+    "@react-navigation/routers": {
25286
+      "version": "5.7.4",
25287
+      "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-5.7.4.tgz",
25288
+      "integrity": "sha512-0N202XAqsU/FlE53Nmh6GHyMtGm7g6TeC93mrFAFJOqGRKznT0/ail+cYlU6tNcPA9AHzZu1Modw1eoDINSliQ==",
25289
+      "requires": {
25290
+        "nanoid": "^3.1.15"
25291
+      }
25292
+    },
25293
+    "@react-navigation/stack": {
25294
+      "version": "5.14.9",
25295
+      "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-5.14.9.tgz",
25296
+      "integrity": "sha512-DuvrT9P+Tz8ezZLQYxORZqOGqO+vEufaxlW1hSLw1knLD4jNxkz8TJDXtfKwaz//9gb43UhTNccNM02vm7iPqQ==",
25297
+      "requires": {
25298
+        "color": "^3.1.3",
25299
+        "react-native-iphone-x-helper": "^1.3.0"
25300
+      }
25301
+    },
24991
     "@svgr/babel-plugin-add-jsx-attribute": {
25302
     "@svgr/babel-plugin-add-jsx-attribute": {
24992
       "version": "4.2.0",
25303
       "version": "4.2.0",
24993
       "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
25304
       "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
25801
       "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
26112
       "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
25802
       "dev": true
26113
       "dev": true
25803
     },
26114
     },
26115
+    "@types/hammerjs": {
26116
+      "version": "2.0.40",
26117
+      "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.40.tgz",
26118
+      "integrity": "sha512-VbjwR1fhsn2h2KXAY4oy1fm7dCxaKy0D+deTb8Ilc3Eo3rc5+5eA4rfYmZaHgNJKxVyI0f6WIXzO2zLkVmQPHA=="
26119
+    },
25804
     "@types/http-proxy": {
26120
     "@types/http-proxy": {
25805
       "version": "1.17.7",
26121
       "version": "1.17.7",
25806
       "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
26122
       "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
27871
         "object-assign": "^4.1.1"
28187
         "object-assign": "^4.1.1"
27872
       }
28188
       }
27873
     },
28189
     },
28190
+    "cross-fetch": {
28191
+      "version": "3.1.4",
28192
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",
28193
+      "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==",
28194
+      "requires": {
28195
+        "node-fetch": "2.6.1"
28196
+      },
28197
+      "dependencies": {
28198
+        "node-fetch": {
28199
+          "version": "2.6.1",
28200
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
28201
+          "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
28202
+        }
28203
+      }
28204
+    },
27874
     "cross-os": {
28205
     "cross-os": {
27875
       "version": "1.4.0",
28206
       "version": "1.4.0",
27876
       "resolved": "https://registry.npmjs.org/cross-os/-/cross-os-1.4.0.tgz",
28207
       "resolved": "https://registry.npmjs.org/cross-os/-/cross-os-1.4.0.tgz",
29761
         }
30092
         }
29762
       }
30093
       }
29763
     },
30094
     },
30095
+    "filter-obj": {
30096
+      "version": "1.1.0",
30097
+      "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
30098
+      "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
30099
+    },
29764
     "finalhandler": {
30100
     "finalhandler": {
29765
       "version": "1.1.2",
30101
       "version": "1.1.2",
29766
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
30102
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
30184
           }
30520
           }
30185
         },
30521
         },
30186
         "mkdirp": {
30522
         "mkdirp": {
30187
-          "version": "0.5.5",
30523
+          "version": "0.5.1",
30188
           "bundled": true,
30524
           "bundled": true,
30189
           "optional": true,
30525
           "optional": true,
30190
           "requires": {
30526
           "requires": {
30191
-            "minimist": "^1.2.5"
30527
+            "minimist": "0.0.8"
30192
           }
30528
           }
30193
         },
30529
         },
30194
         "ms": {
30530
         "ms": {
30316
           },
30652
           },
30317
           "dependencies": {
30653
           "dependencies": {
30318
             "minimist": {
30654
             "minimist": {
30319
-              "version": "1.2.5",
30655
+              "version": "1.2.0",
30320
               "bundled": true,
30656
               "bundled": true,
30321
               "optional": true
30657
               "optional": true
30322
             }
30658
             }
31156
       "dev": true
31492
       "dev": true
31157
     },
31493
     },
31158
     "invariant": {
31494
     "invariant": {
31159
-      "version": "2.2.3",
31160
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz",
31161
-      "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==",
31495
+      "version": "2.2.4",
31496
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
31497
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
31162
       "requires": {
31498
       "requires": {
31163
         "loose-envify": "^1.0.0"
31499
         "loose-envify": "^1.0.0"
31164
       }
31500
       }
31559
           "version": "4.2.3",
31895
           "version": "4.2.3",
31560
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
31896
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
31561
           "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
31897
           "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
31562
-        },
31563
-        "invariant": {
31564
-          "version": "2.2.4",
31565
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
31566
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
31567
-          "requires": {
31568
-            "loose-envify": "^1.0.0"
31569
-          }
31570
         }
31898
         }
31571
       }
31899
       }
31572
     },
31900
     },
32390
             "klaw": "^1.0.0"
32718
             "klaw": "^1.0.0"
32391
           }
32719
           }
32392
         },
32720
         },
32393
-        "invariant": {
32394
-          "version": "2.2.4",
32395
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
32396
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
32397
-          "requires": {
32398
-            "loose-envify": "^1.0.0"
32399
-          }
32400
-        },
32401
         "jsonfile": {
32721
         "jsonfile": {
32402
           "version": "2.4.0",
32722
           "version": "2.4.0",
32403
           "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
32723
           "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
32840
         "ob1": "^0.56.4",
33160
         "ob1": "^0.56.4",
32841
         "source-map": "^0.5.6",
33161
         "source-map": "^0.5.6",
32842
         "vlq": "^1.0.0"
33162
         "vlq": "^1.0.0"
32843
-      },
32844
-      "dependencies": {
32845
-        "invariant": {
32846
-          "version": "2.2.4",
32847
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
32848
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
32849
-          "requires": {
32850
-            "loose-envify": "^1.0.0"
32851
-          }
32852
-        }
32853
       }
33163
       }
32854
     },
33164
     },
32855
     "metro-symbolicate": {
33165
     "metro-symbolicate": {
32862
         "source-map": "^0.5.6",
33172
         "source-map": "^0.5.6",
32863
         "through2": "^2.0.1",
33173
         "through2": "^2.0.1",
32864
         "vlq": "^1.0.0"
33174
         "vlq": "^1.0.0"
32865
-      },
32866
-      "dependencies": {
32867
-        "invariant": {
32868
-          "version": "2.2.4",
32869
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
32870
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
32871
-          "requires": {
32872
-            "loose-envify": "^1.0.0"
32873
-          }
32874
-        }
32875
       }
33175
       }
32876
     },
33176
     },
32877
     "micromatch": {
33177
     "micromatch": {
33046
       "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
33346
       "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
33047
       "optional": true
33347
       "optional": true
33048
     },
33348
     },
33349
+    "nanoid": {
33350
+      "version": "3.1.30",
33351
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
33352
+      "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
33353
+    },
33049
     "nanomatch": {
33354
     "nanomatch": {
33050
       "version": "1.2.13",
33355
       "version": "1.2.13",
33051
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
33356
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
34896
             "ua-parser-js": "^0.7.18"
35201
             "ua-parser-js": "^0.7.18"
34897
           }
35202
           }
34898
         },
35203
         },
34899
-        "invariant": {
34900
-          "version": "2.2.4",
34901
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
34902
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
34903
-          "requires": {
34904
-            "loose-envify": "^1.0.0"
34905
-          }
34906
-        },
34907
         "whatwg-fetch": {
35204
         "whatwg-fetch": {
34908
           "version": "3.0.0",
35205
           "version": "3.0.0",
34909
           "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
35206
           "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
34948
       "resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-8.0.0.tgz",
35245
       "resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-8.0.0.tgz",
34949
       "integrity": "sha512-7/DOEhg8GtyW1hpVtWf8F6RvGLaFaOGmex+IkmiBWQC2uW4NFDcfXm+lMMZnduFavTyUTX7AF6lAM3y286cEfA=="
35246
       "integrity": "sha512-7/DOEhg8GtyW1hpVtWf8F6RvGLaFaOGmex+IkmiBWQC2uW4NFDcfXm+lMMZnduFavTyUTX7AF6lAM3y286cEfA=="
34950
     },
35247
     },
35248
+    "react-native-gesture-handler": {
35249
+      "version": "1.10.3",
35250
+      "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz",
35251
+      "integrity": "sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw==",
35252
+      "requires": {
35253
+        "@egjs/hammerjs": "^2.0.17",
35254
+        "fbjs": "^3.0.0",
35255
+        "hoist-non-react-statics": "^3.3.0",
35256
+        "invariant": "^2.2.4",
35257
+        "prop-types": "^15.7.2"
35258
+      },
35259
+      "dependencies": {
35260
+        "fbjs": {
35261
+          "version": "3.0.0",
35262
+          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz",
35263
+          "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==",
35264
+          "requires": {
35265
+            "cross-fetch": "^3.0.4",
35266
+            "fbjs-css-vars": "^1.0.0",
35267
+            "loose-envify": "^1.0.0",
35268
+            "object-assign": "^4.1.0",
35269
+            "promise": "^7.1.1",
35270
+            "setimmediate": "^1.0.5",
35271
+            "ua-parser-js": "^0.7.18"
35272
+          }
35273
+        }
35274
+      }
35275
+    },
34951
     "react-native-immersive": {
35276
     "react-native-immersive": {
34952
       "version": "2.0.0",
35277
       "version": "2.0.0",
34953
       "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
35278
       "resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
34978
       "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-2.0.0.tgz",
35303
       "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-2.0.0.tgz",
34979
       "integrity": "sha512-jKM9Qg0SkL9D9ad377nxb1VV+OXJSyYyIrBHKmM6CABNxfrLVA5xkQMEibjmZQde7b0ndJOZoQAiObgJjjc4VQ=="
35304
       "integrity": "sha512-jKM9Qg0SkL9D9ad377nxb1VV+OXJSyYyIrBHKmM6CABNxfrLVA5xkQMEibjmZQde7b0ndJOZoQAiObgJjjc4VQ=="
34980
     },
35305
     },
35306
+    "react-native-reanimated": {
35307
+      "version": "1.13.3",
35308
+      "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.13.3.tgz",
35309
+      "integrity": "sha512-i714H24dv6ncpFO7/SZ0PfAMbvjgVbF8Ow2NPtowoZAz8osS54DmTMrkgJ9Za+uEku/s0AEaxqiXG2Xgntvv2g==",
35310
+      "requires": {
35311
+        "fbjs": "^1.0.0"
35312
+      },
35313
+      "dependencies": {
35314
+        "fbjs": {
35315
+          "version": "1.0.0",
35316
+          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-1.0.0.tgz",
35317
+          "integrity": "sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA==",
35318
+          "requires": {
35319
+            "core-js": "^2.4.1",
35320
+            "fbjs-css-vars": "^1.0.0",
35321
+            "isomorphic-fetch": "^2.1.1",
35322
+            "loose-envify": "^1.0.0",
35323
+            "object-assign": "^4.1.0",
35324
+            "promise": "^7.1.1",
35325
+            "setimmediate": "^1.0.5",
35326
+            "ua-parser-js": "^0.7.18"
35327
+          }
35328
+        }
35329
+      }
35330
+    },
35331
+    "react-native-safe-area-context": {
35332
+      "version": "3.3.2",
35333
+      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
35334
+      "integrity": "sha512-yOwiiPJ1rk+/nfK13eafbpW6sKW0jOnsRem2C1LPJjM3tfTof6hlvV5eWHATye3XOpu2cJ7N+HdkUvUDGwFD2Q=="
35335
+    },
35336
+    "react-native-screens": {
35337
+      "version": "2.18.1",
35338
+      "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.18.1.tgz",
35339
+      "integrity": "sha512-r5WZLpmx2hHjC1RgMdPq5YpSU9tEhBpUaZ5M1SUtNIONyiLqQVxabhRCINdebIk4depJiIl7yw2Q85zJyeX6fw=="
35340
+    },
34981
     "react-native-sound": {
35341
     "react-native-sound": {
34982
       "version": "git+ssh://git@github.com/jitsi/react-native-sound.git#3fe5480fce935e888d5089d94a191c7c7e3aa190",
35342
       "version": "git+ssh://git@github.com/jitsi/react-native-sound.git#3fe5480fce935e888d5089d94a191c7c7e3aa190",
34983
       "integrity": "sha512-364A1CvMgh5MnzI4iJgg+AqpePO63Jmf1ESvkTlW+VK3S513fM3092+5mupmGO8KIP77PuYpuNjTYpjZukbgkw==",
35343
       "integrity": "sha512-364A1CvMgh5MnzI4iJgg+AqpePO63Jmf1ESvkTlW+VK3S513fM3092+5mupmGO8KIP77PuYpuNjTYpjZukbgkw==",
35076
         }
35436
         }
35077
       }
35437
       }
35078
     },
35438
     },
35439
+    "react-native-tab-view": {
35440
+      "version": "2.16.0",
35441
+      "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.16.0.tgz",
35442
+      "integrity": "sha512-ac2DmT7+l13wzIFqtbfXn4wwfgtPoKzWjjZyrK1t+T8sdemuUvD4zIt+UImg03fu3s3VD8Wh/fBrIdcqQyZJWg=="
35443
+    },
35079
     "react-native-url-polyfill": {
35444
     "react-native-url-polyfill": {
35080
       "version": "1.2.0",
35445
       "version": "1.2.0",
35081
       "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
35446
       "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
35131
           "version": "2.0.0",
35496
           "version": "2.0.0",
35132
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
35497
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
35133
           "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
35498
           "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
35134
-        },
35135
-        "invariant": {
35136
-          "version": "2.2.4",
35137
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
35138
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
35139
-          "requires": {
35140
-            "loose-envify": "^1.0.0"
35141
-          }
35142
         }
35499
         }
35143
       }
35500
       }
35144
     },
35501
     },
35177
         "react-is": "^16.8.6"
35534
         "react-is": "^16.8.6"
35178
       },
35535
       },
35179
       "dependencies": {
35536
       "dependencies": {
35180
-        "invariant": {
35181
-          "version": "2.2.4",
35182
-          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
35183
-          "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
35184
-          "requires": {
35185
-            "loose-envify": "^1.0.0"
35186
-          }
35187
-        },
35188
         "loose-envify": {
35537
         "loose-envify": {
35189
           "version": "1.4.0",
35538
           "version": "1.4.0",
35190
           "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
35539
           "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
36283
         }
36632
         }
36284
       }
36633
       }
36285
     },
36634
     },
36635
+    "split-on-first": {
36636
+      "version": "1.1.0",
36637
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
36638
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
36639
+    },
36286
     "split-string": {
36640
     "split-string": {
36287
       "version": "3.1.0",
36641
       "version": "3.1.0",
36288
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
36642
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",

+ 9
- 0
package.json Vedi File

42
     "@react-native-community/google-signin": "3.0.1",
42
     "@react-native-community/google-signin": "3.0.1",
43
     "@react-native-community/netinfo": "4.1.5",
43
     "@react-native-community/netinfo": "4.1.5",
44
     "@react-native-community/slider": "3.0.3",
44
     "@react-native-community/slider": "3.0.3",
45
+    "@react-native-masked-view/masked-view": "0.2.6",
46
+    "@react-navigation/material-top-tabs": "5.3.19",
47
+    "@react-navigation/native": "5.9.8",
48
+    "@react-navigation/stack": "5.14.9",
45
     "@svgr/webpack": "4.3.2",
49
     "@svgr/webpack": "4.3.2",
46
     "amplitude-js": "8.2.1",
50
     "amplitude-js": "8.2.1",
47
     "base64-js": "1.3.1",
51
     "base64-js": "1.3.1",
81
     "react-native-collapsible": "1.5.1",
85
     "react-native-collapsible": "1.5.1",
82
     "react-native-default-preference": "1.4.2",
86
     "react-native-default-preference": "1.4.2",
83
     "react-native-device-info": "8.0.0",
87
     "react-native-device-info": "8.0.0",
88
+    "react-native-gesture-handler": "1.10.3",
84
     "react-native-immersive": "2.0.0",
89
     "react-native-immersive": "2.0.0",
85
     "react-native-keep-awake": "4.0.0",
90
     "react-native-keep-awake": "4.0.0",
86
     "react-native-paper": "4.8.1",
91
     "react-native-paper": "4.8.1",
87
     "react-native-performance": "2.0.0",
92
     "react-native-performance": "2.0.0",
93
+    "react-native-reanimated": "1.13.3",
94
+    "react-native-safe-area-context": "3.3.2",
95
+    "react-native-screens": "2.18.1",
88
     "react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
96
     "react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
89
     "react-native-splash-screen": "3.2.0",
97
     "react-native-splash-screen": "3.2.0",
90
     "react-native-svg": "12.1.0",
98
     "react-native-svg": "12.1.0",
91
     "react-native-svg-transformer": "0.14.3",
99
     "react-native-svg-transformer": "0.14.3",
100
+    "react-native-tab-view": "2.16.0",
92
     "react-native-url-polyfill": "1.2.0",
101
     "react-native-url-polyfill": "1.2.0",
93
     "react-native-video": "5.1.1",
102
     "react-native-video": "5.1.1",
94
     "react-native-watch-connectivity": "0.4.3",
103
     "react-native-watch-connectivity": "0.4.3",

+ 52
- 0
react/features/app/getRouteToRender.native.js Vedi File

1
+
2
+import { isRoomValid } from '../base/conference';
3
+import { toState } from '../base/redux';
4
+import { ConferenceNavigationContainer } from '../conference';
5
+import { isWelcomePageAppEnabled } from '../welcome';
6
+import { BlankPage, WelcomePage } from '../welcome/components';
7
+
8
+/**
9
+ * Determines which route is to be rendered in order to depict a specific Redux
10
+ * store.
11
+ *
12
+ * @param {(Function|Object)} stateful - THe redux store, state, or
13
+ * {@code getState} function.
14
+ * @returns {Promise<Object>}
15
+ */
16
+export function _getRouteToRender(stateful) {
17
+    const state = toState(stateful);
18
+
19
+    return _getMobileRoute(state);
20
+}
21
+
22
+/**
23
+ * Returns the {@code Route} to display on the React Native app.
24
+ *
25
+ * @param {Object} state - The redux state.
26
+ * @returns {Promise}
27
+ */
28
+function _getMobileRoute(state) {
29
+    const route = _getEmptyRoute();
30
+
31
+    if (isRoomValid(state['features/base/conference'].room)) {
32
+        route.component = ConferenceNavigationContainer;
33
+    } else if (isWelcomePageAppEnabled(state)) {
34
+        route.component = WelcomePage;
35
+    } else {
36
+        route.component = BlankPage;
37
+    }
38
+
39
+    return Promise.resolve(route);
40
+}
41
+
42
+/**
43
+ * Returns the default {@code Route}.
44
+ *
45
+ * @returns {Object}
46
+ */
47
+function _getEmptyRoute() {
48
+    return {
49
+        component: BlankPage,
50
+        href: undefined
51
+    };
52
+}

react/features/app/getRouteToRender.js → react/features/app/getRouteToRender.web.js Vedi File

1
-// @flow
2
 
1
 
3
 import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
2
 import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
4
-import type { Component } from 'react';
5
 
3
 
6
 import { isRoomValid } from '../base/conference';
4
 import { isRoomValid } from '../base/conference';
7
 import { isSupportedBrowser } from '../base/environment';
5
 import { isSupportedBrowser } from '../base/environment';
9
 import { Conference } from '../conference';
7
 import { Conference } from '../conference';
10
 import { getDeepLinkingPage } from '../deep-linking';
8
 import { getDeepLinkingPage } from '../deep-linking';
11
 import { UnsupportedDesktopBrowser } from '../unsupported-browser';
9
 import { UnsupportedDesktopBrowser } from '../unsupported-browser';
12
-import {
13
-    BlankPage,
14
-    WelcomePage,
15
-    isWelcomePageAppEnabled,
16
-    isWelcomePageUserEnabled
17
-} from '../welcome';
10
+import { isWelcomePageUserEnabled } from '../welcome';
11
+import { BlankPage, WelcomePage } from '../welcome/components';
18
 
12
 
19
-/**
20
- * Object describing application route.
21
- *
22
- * @typedef {Object} Route
23
- * @property {Component} component - React Component constructor.
24
- * @property {string|undefined} href - New location, in case navigation involves
25
- * a location change.
26
- */
27
-export type Route = {
28
-    component: Class<Component<*>>,
29
-    href: ?string
30
-};
31
 
13
 
32
 /**
14
 /**
33
  * Determines which route is to be rendered in order to depict a specific Redux
15
  * Determines which route is to be rendered in order to depict a specific Redux
35
  *
17
  *
36
  * @param {(Function|Object)} stateful - THe redux store, state, or
18
  * @param {(Function|Object)} stateful - THe redux store, state, or
37
  * {@code getState} function.
19
  * {@code getState} function.
38
- * @returns {Promise<Route>}
20
+ * @returns {Promise<Object>}
39
  */
21
  */
40
-export function _getRouteToRender(stateful: Function | Object): Promise<Route> {
22
+export function _getRouteToRender(stateful) {
41
     const state = toState(stateful);
23
     const state = toState(stateful);
42
 
24
 
43
-    if (navigator.product === 'ReactNative') {
44
-        return _getMobileRoute(state);
45
-    }
46
-
47
     return _getWebConferenceRoute(state) || _getWebWelcomePageRoute(state);
25
     return _getWebConferenceRoute(state) || _getWebWelcomePageRoute(state);
48
 }
26
 }
49
 
27
 
50
-/**
51
- * Returns the {@code Route} to display on the React Native app.
52
- *
53
- * @param {Object} state - The redux state.
54
- * @returns {Promise<Route>}
55
- */
56
-function _getMobileRoute(state): Promise<Route> {
57
-    const route = _getEmptyRoute();
58
-
59
-    if (isRoomValid(state['features/base/conference'].room)) {
60
-        route.component = Conference;
61
-    } else if (isWelcomePageAppEnabled(state)) {
62
-        route.component = WelcomePage;
63
-    } else {
64
-        route.component = BlankPage;
65
-    }
66
-
67
-    return Promise.resolve(route);
68
-}
69
-
70
 /**
28
 /**
71
  * Returns the {@code Route} to display when trying to access a conference if
29
  * Returns the {@code Route} to display when trying to access a conference if
72
  * a valid conference is being joined.
30
  * a valid conference is being joined.
73
  *
31
  *
74
  * @param {Object} state - The redux state.
32
  * @param {Object} state - The redux state.
75
- * @returns {Promise<Route>|undefined}
33
+ * @returns {Promise|undefined}
76
  */
34
  */
77
-function _getWebConferenceRoute(state): ?Promise<Route> {
35
+function _getWebConferenceRoute(state) {
78
     if (!isRoomValid(state['features/base/conference'].room)) {
36
     if (!isRoomValid(state['features/base/conference'].room)) {
79
         return;
37
         return;
80
     }
38
     }
111
  * Returns the {@code Route} to display when trying to access the welcome page.
69
  * Returns the {@code Route} to display when trying to access the welcome page.
112
  *
70
  *
113
  * @param {Object} state - The redux state.
71
  * @param {Object} state - The redux state.
114
- * @returns {Promise<Route>}
72
+ * @returns {Promise<Object>}
115
  */
73
  */
116
-function _getWebWelcomePageRoute(state): Promise<Route> {
74
+function _getWebWelcomePageRoute(state) {
117
     const route = _getEmptyRoute();
75
     const route = _getEmptyRoute();
118
 
76
 
119
     if (isWelcomePageUserEnabled(state)) {
77
     if (isWelcomePageUserEnabled(state)) {
137
 /**
95
 /**
138
  * Returns the default {@code Route}.
96
  * Returns the default {@code Route}.
139
  *
97
  *
140
- * @returns {Route}
98
+ * @returns {Object}
141
  */
99
  */
142
-function _getEmptyRoute(): Route {
100
+function _getEmptyRoute() {
143
     return {
101
     return {
144
         component: BlankPage,
102
         component: BlankPage,
145
         href: undefined
103
         href: undefined

+ 83
- 0
react/features/base/modal/components/JitsiKeyboardAvoidingView.js Vedi File

1
+// @flow
2
+
3
+import { useHeaderHeight } from '@react-navigation/stack';
4
+import React, { useEffect, useState } from 'react';
5
+import {
6
+    Keyboard,
7
+    KeyboardAvoidingView,
8
+    Platform,
9
+    TouchableWithoutFeedback
10
+} from 'react-native';
11
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
12
+
13
+import { StyleType } from '../../styles';
14
+
15
+type Props = {
16
+
17
+    /**
18
+     * The children component(s) of the Modal, to be rendered.
19
+     */
20
+    children: React$Node,
21
+
22
+    /**
23
+     * Additional style to be appended to the KeyboardAvoidingView content container.
24
+     */
25
+    contentContainerStyle?: StyleType,
26
+
27
+    /**
28
+     * Is the screen rendering a tab navigator?
29
+     */
30
+    hasTabNavigator: boolean,
31
+
32
+    /**
33
+     * Additional style to be appended to the KeyboardAvoidingView.
34
+     */
35
+    style?: StyleType
36
+}
37
+
38
+const JitsiKeyboardAvoidingView = (
39
+        {
40
+            children,
41
+            contentContainerStyle,
42
+            hasTabNavigator,
43
+            style
44
+        }: Props) => {
45
+    const headerHeight = useHeaderHeight();
46
+    const insets = useSafeAreaInsets();
47
+    const [ bottomPadding, setBottomPadding ] = useState(insets.bottom);
48
+
49
+    useEffect(() => {
50
+        // This useEffect is needed because insets are undefined at first for some reason
51
+        // https://github.com/th3rdwave/react-native-safe-area-context/issues/54
52
+        setBottomPadding(insets.bottom);
53
+
54
+    }, [ insets.bottom ]);
55
+
56
+    const tabNavigatorPadding
57
+        = hasTabNavigator ? headerHeight : 0;
58
+    const noNotchDevicePadding = bottomPadding || 10;
59
+    const iosVerticalOffset = headerHeight + noNotchDevicePadding + tabNavigatorPadding;
60
+    const androidVerticalOffset = headerHeight;
61
+
62
+    return (
63
+        <TouchableWithoutFeedback
64
+            /* eslint-disable-next-line react/jsx-handler-names */
65
+            onPress = { Keyboard.dismiss }>
66
+            <KeyboardAvoidingView
67
+                behavior = { Platform.OS === 'ios' ? 'padding' : 'height' }
68
+                contentContainerStyle = { contentContainerStyle }
69
+                enabled = { true }
70
+                keyboardVerticalOffset = {
71
+                    Platform.OS === 'ios'
72
+                        ? iosVerticalOffset
73
+                        : androidVerticalOffset
74
+                }
75
+                style = { style }>
76
+                { children }
77
+            </KeyboardAvoidingView>
78
+        </TouchableWithoutFeedback>
79
+    );
80
+};
81
+
82
+
83
+export default JitsiKeyboardAvoidingView;

+ 69
- 0
react/features/base/modal/components/JitsiScreen.js Vedi File

1
+// @flow
2
+
3
+import React from 'react';
4
+import { View } from 'react-native';
5
+import { SafeAreaView } from 'react-native-safe-area-context';
6
+
7
+import { StyleType } from '../../styles';
8
+
9
+import JitsiKeyboardAvoidingView from './JitsiKeyboardAvoidingView';
10
+import styles from './styles';
11
+
12
+
13
+type Props = {
14
+
15
+    /**
16
+     * Additional style to be appended to the KeyboardAvoidingView content container.
17
+     */
18
+    contentContainerStyle?: StyleType,
19
+
20
+    /**
21
+     * The children component(s) of the Modal, to be rendered.
22
+     */
23
+    children: React$Node,
24
+
25
+    /**
26
+     * Optional function that renders a footer component, if needed.
27
+     */
28
+    footerComponent?: Function,
29
+
30
+    /**
31
+     * Is the screen rendering a tab navigator?
32
+     */
33
+    hasTabNavigator: boolean,
34
+
35
+    /**
36
+     * Additional style to be appended to the KeyboardAvoidingView containing the content of the modal.
37
+     */
38
+    style?: StyleType
39
+}
40
+
41
+const JitsiScreen = ({
42
+    contentContainerStyle,
43
+    children,
44
+    footerComponent,
45
+    hasTabNavigator,
46
+    style
47
+}: Props) => (
48
+    <View
49
+        style = { styles.jitsiScreenContainer }>
50
+        <JitsiKeyboardAvoidingView
51
+            contentContainerStyle = { contentContainerStyle }
52
+            hasTabNavigator = { hasTabNavigator }
53
+            style = { style }>
54
+            <SafeAreaView
55
+                edges = { [
56
+                    'bottom',
57
+                    'left',
58
+                    'right'
59
+                ] }
60
+                style = { styles.safeArea }>
61
+                { children }
62
+            </SafeAreaView>
63
+            { footerComponent && footerComponent() }
64
+        </JitsiKeyboardAvoidingView>
65
+    </View>
66
+);
67
+
68
+
69
+export default JitsiScreen;

+ 60
- 0
react/features/base/modal/components/functions.native.js Vedi File

1
+// @flow
2
+
3
+import { useEffect, useState } from 'react';
4
+import { Keyboard } from 'react-native';
5
+
6
+import { toState } from '../../redux';
7
+
8
+export const useKeyboardHeight = () => {
9
+    const [ keyboardHeight, setKeyboardHeight ] = useState(0);
10
+
11
+    const onKeyboardDidShow = e => {
12
+        setKeyboardHeight(e.endCoordinates.height);
13
+    };
14
+
15
+    const onKeyboardDidHide = () => {
16
+        setKeyboardHeight(0);
17
+    };
18
+
19
+    useEffect(() => {
20
+        const keyboardShow = Keyboard.addListener('keyboardDidShow', onKeyboardDidShow);
21
+        const keyboardHide = Keyboard.addListener('keyboardDidHide', onKeyboardDidHide);
22
+
23
+        return () => {
24
+            keyboardShow.remove();
25
+            keyboardHide.remove();
26
+        };
27
+    }, []);
28
+
29
+    return keyboardHeight;
30
+};
31
+
32
+/**
33
+ *
34
+ * Returns the client width.
35
+ *
36
+ * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
37
+ * {@code getState} function to be used to retrieve the state
38
+ * features/base/config.
39
+ * @returns {number}.
40
+ */
41
+export function getClientWidth(stateful: Object) {
42
+    const state = toState(stateful['features/base/responsive-ui']);
43
+
44
+    return state.clientWidth;
45
+}
46
+
47
+/**
48
+ *
49
+ * Returns the client height.
50
+ *
51
+ * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
52
+ * {@code getState} function to be used to retrieve the state
53
+ * features/base/config.
54
+ * @returns {number}.
55
+ */
56
+export function getClientHeight(stateful: Object) {
57
+    const state = toState(stateful['features/base/responsive-ui']);
58
+
59
+    return state.clientHeight;
60
+}

+ 5
- 0
react/features/base/modal/components/styles.js Vedi File

3
 import { ColorSchemeRegistry, schemeColor } from '../../color-scheme';
3
 import { ColorSchemeRegistry, schemeColor } from '../../color-scheme';
4
 
4
 
5
 export default {
5
 export default {
6
+
7
+    jitsiScreenContainer: {
8
+        flex: 1
9
+    },
10
+
6
     safeArea: {
11
     safeArea: {
7
         flex: 1
12
         flex: 1
8
     }
13
     }

+ 6
- 1
react/features/base/ui/Tokens.js Vedi File

17
     primary07: '#669AEC',
17
     primary07: '#669AEC',
18
     primary08: '#99BBF3',
18
     primary08: '#99BBF3',
19
     primary09: '#CCDDF9',
19
     primary09: '#CCDDF9',
20
+    primary10: '#17A0DB',
20
 
21
 
21
     surface00: '#111111',
22
     surface00: '#111111',
22
     surface01: '#040404',
23
     surface01: '#040404',
54
     // Primary buttons
55
     // Primary buttons
55
     action01: 'primary05',
56
     action01: 'primary05',
56
 
57
 
58
+    // Screen header
59
+    screen01Header: 'primary10',
60
+
57
     // Hover state for primary buttons
61
     // Hover state for primary buttons
58
     action01Hover: 'primary06',
62
     action01Hover: 'primary06',
59
 
63
 
226
     boxShadow: 'inset 0px -1px 0px rgba(255, 255, 255, 0.15)'
230
     boxShadow: 'inset 0px -1px 0px rgba(255, 255, 255, 0.15)'
227
 };
231
 };
228
 
232
 
229
-export const spacing = [ 0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80 ];
233
+export const spacing
234
+    = [ 0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 ];
230
 
235
 
231
 export const typography = {
236
 export const typography = {
232
     labelRegular: {
237
     labelRegular: {

+ 19
- 4
react/features/chat/components/PrivateMessageButton.js Vedi File

6
 import { getParticipantById } from '../../base/participants';
6
 import { getParticipantById } from '../../base/participants';
7
 import { connect } from '../../base/redux';
7
 import { connect } from '../../base/redux';
8
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
8
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
9
-import { openChat } from '../actions';
9
+import { navigate } from '../../conference/components/native/ConferenceNavigationContainerRef';
10
+import { screen } from '../../conference/components/native/routes';
10
 
11
 
11
 export type Props = AbstractButtonProps & {
12
 export type Props = AbstractButtonProps & {
12
 
13
 
30
      */
31
      */
31
     dispatch: Function,
32
     dispatch: Function,
32
 
33
 
34
+    /**
35
+     * True if the polls feature is disabled.
36
+     */
37
+    _isPollsDisabled: boolean,
38
+
33
     /**
39
     /**
34
      * The participant object retrieved from Redux.
40
      * The participant object retrieved from Redux.
35
      */
41
      */
52
      * @returns {void}
58
      * @returns {void}
53
      */
59
      */
54
     _handleClick() {
60
     _handleClick() {
55
-        const { dispatch, _participant } = this.props;
56
-
57
-        dispatch(openChat(_participant));
61
+        this.props._isPollsDisabled
62
+            ? navigate(screen.conference.chat, {
63
+                privateMessageRecipient: this.props._participant
64
+            })
65
+            : navigate(screen.conference.chatandpolls.main, {
66
+                screen: screen.conference.chatandpolls.tab.chat,
67
+                params: {
68
+                    privateMessageRecipient: this.props._participant
69
+                }
70
+            });
58
     }
71
     }
59
 
72
 
60
     /**
73
     /**
79
  */
92
  */
80
 export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
93
 export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
81
     const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
94
     const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
95
+    const { disablePolls } = state['features/base/config'];
82
     const { visible = enabled } = ownProps;
96
     const { visible = enabled } = ownProps;
83
 
97
 
84
     return {
98
     return {
99
+        _isPollsDisabled: disablePolls,
85
         _participant: getParticipantById(state, ownProps.participantID),
100
         _participant: getParticipantById(state, ownProps.participantID),
86
         visible
101
         visible
87
     };
102
     };

+ 62
- 82
react/features/chat/components/native/Chat.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
-import React from 'react';
4
-import { View } from 'react-native';
5
-import { Button } from 'react-native-paper';
3
+import { useIsFocused } from '@react-navigation/native';
4
+import React, { useEffect } from 'react';
6
 
5
 
7
 import { translate } from '../../../base/i18n';
6
 import { translate } from '../../../base/i18n';
8
-import { JitsiModal } from '../../../base/modal';
7
+import JitsiScreen from '../../../base/modal/components/JitsiScreen';
9
 import { connect } from '../../../base/redux';
8
 import { connect } from '../../../base/redux';
10
-import { PollsPane } from '../../../polls/components';
11
-import { closeChat } from '../../actions.any';
12
-import { BUTTON_MODES, CHAT_VIEW_MODAL_ID } from '../../constants';
9
+import { screen } from '../../../conference/components/native/routes';
10
+import { closeChat, openChat } from '../../actions.native';
13
 import AbstractChat, {
11
 import AbstractChat, {
14
     _mapStateToProps,
12
     _mapStateToProps,
15
-    type Props
13
+    type Props as AbstractProps
16
 } from '../AbstractChat';
14
 } from '../AbstractChat';
17
 
15
 
18
 import ChatInputBar from './ChatInputBar';
16
 import ChatInputBar from './ChatInputBar';
20
 import MessageRecipient from './MessageRecipient';
18
 import MessageRecipient from './MessageRecipient';
21
 import styles from './styles';
19
 import styles from './styles';
22
 
20
 
21
+
22
+type Props = AbstractProps & {
23
+
24
+    /**
25
+     * Is this screen focused or not(React Navigation)
26
+     */
27
+    isChatScreenFocused: boolean,
28
+
29
+    /**
30
+     * Default prop for navigating between screen components(React Navigation)
31
+     */
32
+    navigation: Object,
33
+
34
+    /**
35
+     * Default prop for navigating between screen components(React Navigation)
36
+     */
37
+    route: Object
38
+};
39
+
23
 /**
40
 /**
24
  * Implements a React native component that renders the chat window (modal) of
41
  * Implements a React native component that renders the chat window (modal) of
25
  * the mobile client.
42
  * the mobile client.
26
  */
43
  */
27
 class Chat extends AbstractChat<Props> {
44
 class Chat extends AbstractChat<Props> {
28
-    /**
29
-     * Creates a new instance.
30
-     *
31
-     * @inheritdoc
32
-     */
33
-    constructor(props: Props) {
34
-        super(props);
35
-
36
-        this._onClose = this._onClose.bind(this);
37
-    }
38
 
45
 
39
     /**
46
     /**
40
      * Implements React's {@link Component#render()}.
47
      * Implements React's {@link Component#render()}.
42
      * @inheritdoc
49
      * @inheritdoc
43
      */
50
      */
44
     render() {
51
     render() {
52
+        const { _messages, route } = this.props;
53
+        const privateMessageRecipient = route.params?.privateMessageRecipient;
54
+
45
         return (
55
         return (
46
-            <JitsiModal
47
-                headerProps = {{
48
-                    headerLabelKey: this.props._isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title'
49
-                }}
50
-                modalId = { CHAT_VIEW_MODAL_ID }
51
-                onClose = { this._onClose }>
52
-                {this.props._isPollsEnabled && <View style = { styles.tabContainer }>
53
-                    <Button
54
-                        color = '#17a0db'
55
-                        mode = {
56
-                            this.props._isPollsTabFocused
57
-                                ? BUTTON_MODES.CONTAINED
58
-                                : BUTTON_MODES.TEXT
59
-                        }
60
-                        onPress = { this._onToggleChatTab }
61
-                        style = { styles.tabLeftButton }
62
-                        uppercase = { false }>
63
-                        {`${this.props.t('chat.tabs.chat')}${this.props._isPollsTabFocused
64
-                                && this.props._nbUnreadMessages > 0
65
-                            ? `(${this.props._nbUnreadMessages})`
66
-                            : ''
67
-                        }`}
68
-                    </Button>
69
-                    <Button
70
-                        color = '#17a0db'
71
-                        mode = {
72
-                            this.props._isPollsTabFocused
73
-                                ? BUTTON_MODES.TEXT
74
-                                : BUTTON_MODES.CONTAINED
75
-                        }
76
-                        onPress = { this._onTogglePollsTab }
77
-                        style = { styles.tabRightButton }
78
-                        uppercase = { false }>
79
-                        {`${this.props.t('chat.tabs.polls')}${!this.props._isPollsTabFocused
80
-                                && this.props._nbUnreadPolls > 0
81
-                            ? `(${this.props._nbUnreadPolls})`
82
-                            : ''
83
-                        }`}
84
-                    </Button>
85
-                </View>}
86
-                {this.props._isPollsTabFocused
87
-                    ? <PollsPane />
88
-                    : (
89
-                    <>
90
-                        <MessageContainer messages = { this.props._messages } />
91
-                        <MessageRecipient />
92
-                        <ChatInputBar onSend = { this._onSendMessage } />
93
-                    </>
94
-                    )}
95
-            </JitsiModal>
56
+            <JitsiScreen
57
+                hasTabNavigator = { true }
58
+                style = { styles.chatContainer }>
59
+                <MessageContainer messages = { _messages } />
60
+                <MessageRecipient privateMessageRecipient = { privateMessageRecipient } />
61
+                <ChatInputBar onSend = { this._onSendMessage } />
62
+            </JitsiScreen>
96
         );
63
         );
97
     }
64
     }
98
 
65
 
99
     _onSendMessage: (string) => void;
66
     _onSendMessage: (string) => void;
67
+}
100
 
68
 
101
-    _onClose: () => boolean
69
+export default translate(connect(_mapStateToProps)(props => {
70
+    const {
71
+        _nbUnreadMessages,
72
+        dispatch,
73
+        navigation,
74
+        route
75
+    } = props;
76
+    const isChatScreenFocused = useIsFocused();
77
+    const privateMessageRecipient = route.params?.privateMessageRecipient;
102
 
78
 
103
-    _onTogglePollsTab: () => void;
104
-    _onToggleChatTab: () => void;
79
+    const nrUnreadMessages
80
+        = !isChatScreenFocused && _nbUnreadMessages > 0
81
+            ? `(${_nbUnreadMessages})` : '';
105
 
82
 
106
-    /**
107
-     * Closes the modal.
108
-     *
109
-     * @returns {boolean}
110
-     */
111
-    _onClose() {
112
-        this.props.dispatch(closeChat());
83
+    useEffect(() => {
84
+        dispatch(openChat(privateMessageRecipient));
113
 
85
 
114
-        return true;
115
-    }
116
-}
86
+        navigation.setOptions({
87
+            tabBarLabel: `${screen.conference.chatandpolls.tab.chat} ${nrUnreadMessages}`
88
+        });
89
+
90
+        return () => dispatch(closeChat());
91
+    }, [ nrUnreadMessages ]);
117
 
92
 
118
-export default translate(connect(_mapStateToProps)(Chat));
93
+    return (
94
+        <Chat
95
+            { ...props }
96
+            isChatScreenFocused = { isChatScreenFocused } />
97
+    );
98
+}));

+ 43
- 0
react/features/chat/components/native/ChatAndPolls.js Vedi File

1
+// @flow
2
+
3
+import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
4
+import React from 'react';
5
+import { useSelector } from 'react-redux';
6
+
7
+import {
8
+    getClientHeight,
9
+    getClientWidth
10
+} from '../../../base/modal/components/functions.native';
11
+import { Chat } from '../../../chat';
12
+import { chatTabBarOptions } from '../../../conference/components/native/ConferenceNavigatorScreenOptions';
13
+import { screen } from '../../../conference/components/native/routes';
14
+import { PollsPane } from '../../../polls/components';
15
+
16
+const ChatTab = createMaterialTopTabNavigator();
17
+
18
+
19
+const ChatAndPolls = () => {
20
+    const clientHeight = useSelector(getClientHeight);
21
+    const clientWidth = useSelector(getClientWidth);
22
+
23
+    return (
24
+        <ChatTab.Navigator
25
+            backBehavior = 'none'
26
+            initialLayout = {{
27
+                height: clientHeight,
28
+                width: clientWidth
29
+            }}
30
+            tabBarOptions = {{
31
+                ...chatTabBarOptions
32
+            }}>
33
+            <ChatTab.Screen
34
+                component = { Chat }
35
+                name = { screen.conference.chatandpolls.tab.chat } />
36
+            <ChatTab.Screen
37
+                component = { PollsPane }
38
+                name = { screen.conference.chatandpolls.tab.polls } />
39
+        </ChatTab.Navigator>
40
+    );
41
+};
42
+
43
+export default ChatAndPolls;

+ 14
- 5
react/features/chat/components/native/ChatButton.js Vedi File

7
     AbstractButton,
7
     AbstractButton,
8
     type AbstractButtonProps
8
     type AbstractButtonProps
9
 } from '../../../base/toolbox/components';
9
 } from '../../../base/toolbox/components';
10
-import { openChat } from '../../actions.native';
10
+import { navigate } from '../../../conference/components/native/ConferenceNavigationContainerRef';
11
+import { screen } from '../../../conference/components/native/routes';
11
 import { getUnreadCount } from '../../functions';
12
 import { getUnreadCount } from '../../functions';
12
 
13
 
14
+
13
 type Props = AbstractButtonProps & {
15
 type Props = AbstractButtonProps & {
14
 
16
 
15
     /**
17
     /**
16
-     * The unread message count.
18
+     * True if the polls feature is disabled.
17
      */
19
      */
18
-    _unreadMessageCount: number,
20
+    _isPollsDisabled: boolean,
19
 
21
 
20
-    dispatch: Function
22
+    /**
23
+     * The unread message count.
24
+     */
25
+    _unreadMessageCount: number
21
 };
26
 };
22
 
27
 
23
 /**
28
 /**
36
      * @returns {void}
41
      * @returns {void}
37
      */
42
      */
38
     _handleClick() {
43
     _handleClick() {
39
-        this.props.dispatch(openChat());
44
+        this.props._isPollsDisabled
45
+            ? navigate(screen.conference.chat)
46
+            : navigate(screen.conference.chatandpolls.main);
40
     }
47
     }
41
 
48
 
42
     /**
49
     /**
59
  */
66
  */
60
 function _mapStateToProps(state, ownProps) {
67
 function _mapStateToProps(state, ownProps) {
61
     const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
68
     const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
69
+    const { disablePolls } = state['features/base/config'];
62
     const { visible = enabled } = ownProps;
70
     const { visible = enabled } = ownProps;
63
 
71
 
64
     return {
72
     return {
73
+        _isPollsDisabled: disablePolls,
65
         _unreadMessageCount: getUnreadCount(state),
74
         _unreadMessageCount: getUnreadCount(state),
66
         visible
75
         visible
67
     };
76
     };

+ 0
- 14
react/features/chat/components/native/ChatInputBar.js Vedi File

58
         };
58
         };
59
 
59
 
60
         this._onChangeText = this._onChangeText.bind(this);
60
         this._onChangeText = this._onChangeText.bind(this);
61
-        this._onFieldReferenceAvailable = this._onFieldReferenceAvailable.bind(this);
62
         this._onFocused = this._onFocused.bind(this);
61
         this._onFocused = this._onFocused.bind(this);
63
         this._onSubmit = this._onSubmit.bind(this);
62
         this._onSubmit = this._onSubmit.bind(this);
64
     }
63
     }
83
                     onFocus = { this._onFocused(true) }
82
                     onFocus = { this._onFocused(true) }
84
                     onSubmitEditing = { this._onSubmit }
83
                     onSubmitEditing = { this._onSubmit }
85
                     placeholder = { this.props.t('chat.fieldPlaceHolder') }
84
                     placeholder = { this.props.t('chat.fieldPlaceHolder') }
86
-                    ref = { this._onFieldReferenceAvailable }
87
                     returnKeyType = 'send'
85
                     returnKeyType = 'send'
88
                     style = { styles.inputField }
86
                     style = { styles.inputField }
89
                     value = { this.state.message } />
87
                     value = { this.state.message } />
113
         });
111
         });
114
     }
112
     }
115
 
113
 
116
-    _onFieldReferenceAvailable: Object => void;
117
-
118
-    /**
119
-     * Callback to be invoked when the field reference is available.
120
-     *
121
-     * @param {Object} field - The reference to the field.
122
-     * @returns {void}
123
-     */
124
-    _onFieldReferenceAvailable(field) {
125
-        field && field.focus();
126
-    }
127
-
128
     _onFocused: boolean => Function;
114
     _onFocused: boolean => Function;
129
 
115
 
130
     /**
116
     /**

+ 51
- 11
react/features/chat/components/native/MessageRecipient.js Vedi File

8
 import { Icon, IconCancelSelection } from '../../../base/icons';
8
 import { Icon, IconCancelSelection } from '../../../base/icons';
9
 import { connect } from '../../../base/redux';
9
 import { connect } from '../../../base/redux';
10
 import { type StyleType } from '../../../base/styles';
10
 import { type StyleType } from '../../../base/styles';
11
+import {
12
+    setParams
13
+} from '../../../conference/components/native/ConferenceNavigationContainerRef';
14
+import { setPrivateMessageRecipient } from '../../actions.any';
11
 import AbstractMessageRecipient, {
15
 import AbstractMessageRecipient, {
12
-    _mapDispatchToProps,
13
-    _mapStateToProps as _abstractMapStateToProps,
14
     type Props as AbstractProps
16
     type Props as AbstractProps
15
 } from '../AbstractMessageRecipient';
17
 } from '../AbstractMessageRecipient';
16
 
18
 
19
     /**
21
     /**
20
      * The color-schemed stylesheet of the feature.
22
      * The color-schemed stylesheet of the feature.
21
      */
23
      */
22
-    _styles: StyleType
24
+    _styles: StyleType,
25
+
26
+    /**
27
+     * The Redux dispatch function.
28
+     */
29
+    dispatch: Function,
30
+
31
+    /**
32
+     * The participant object set for private messaging.
33
+     */
34
+    privateMessageRecipient: Object,
23
 };
35
 };
24
 
36
 
25
 /**
37
 /**
26
  * Class to implement the displaying of the recipient of the next message.
38
  * Class to implement the displaying of the recipient of the next message.
27
  */
39
  */
28
 class MessageRecipient extends AbstractMessageRecipient<Props> {
40
 class MessageRecipient extends AbstractMessageRecipient<Props> {
41
+
42
+    /**
43
+     * Constructor of the component.
44
+     *
45
+     * @param {Props} props - The props of the component.
46
+     */
47
+    constructor(props: Props) {
48
+        super(props);
49
+
50
+        this._onResetPrivateMessageRecipient = this._onResetPrivateMessageRecipient.bind(this);
51
+    }
52
+
53
+    _onResetPrivateMessageRecipient: () => void;
54
+
55
+    /**
56
+     * Resets private message recipient from state.
57
+     *
58
+     * @returns {void}
59
+     */
60
+    _onResetPrivateMessageRecipient() {
61
+        const { dispatch } = this.props;
62
+
63
+        dispatch(setPrivateMessageRecipient());
64
+
65
+        setParams({
66
+            privateMessageRecipient: undefined
67
+        });
68
+    }
69
+
29
     /**
70
     /**
30
      * Implements {@code PureComponent#render}.
71
      * Implements {@code PureComponent#render}.
31
      *
72
      *
32
      * @inheritdoc
73
      * @inheritdoc
74
+     * @returns {ReactElement}
33
      */
75
      */
34
     render() {
76
     render() {
35
-        const { _privateMessageRecipient, _styles } = this.props;
77
+        const { _styles, privateMessageRecipient, t } = this.props;
36
 
78
 
37
-        if (!_privateMessageRecipient) {
79
+        if (!privateMessageRecipient) {
38
             return null;
80
             return null;
39
         }
81
         }
40
 
82
 
41
-        const { t } = this.props;
42
-
43
         return (
83
         return (
44
             <View style = { _styles.messageRecipientContainer }>
84
             <View style = { _styles.messageRecipientContainer }>
45
                 <Text style = { _styles.messageRecipientText }>
85
                 <Text style = { _styles.messageRecipientText }>
46
                     { t('chat.messageTo', {
86
                     { t('chat.messageTo', {
47
-                        recipient: _privateMessageRecipient
87
+                        recipient: privateMessageRecipient.name
48
                     }) }
88
                     }) }
49
                 </Text>
89
                 </Text>
50
-                <TouchableHighlight onPress = { this.props._onRemovePrivateMessageRecipient }>
90
+                <TouchableHighlight
91
+                    onPress = { this._onResetPrivateMessageRecipient }>
51
                     <Icon
92
                     <Icon
52
                         src = { IconCancelSelection }
93
                         src = { IconCancelSelection }
53
                         style = { _styles.messageRecipientCancelIcon } />
94
                         style = { _styles.messageRecipientCancelIcon } />
65
  */
106
  */
66
 function _mapStateToProps(state) {
107
 function _mapStateToProps(state) {
67
     return {
108
     return {
68
-        ..._abstractMapStateToProps(state),
69
         _styles: ColorSchemeRegistry.get(state, 'Chat')
109
         _styles: ColorSchemeRegistry.get(state, 'Chat')
70
     };
110
     };
71
 }
111
 }
72
 
112
 
73
-export default translate(connect(_mapStateToProps, _mapDispatchToProps)(MessageRecipient));
113
+export default translate(connect(_mapStateToProps)(MessageRecipient));

+ 1
- 0
react/features/chat/components/native/index.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
 export { default as Chat } from './Chat';
3
 export { default as Chat } from './Chat';
4
+export { default as ChatAndPolls } from './ChatAndPolls';
4
 export { default as ChatButton } from './ChatButton';
5
 export { default as ChatButton } from './ChatButton';
5
 export { default as ChatPrivacyDialog } from './ChatPrivacyDialog';
6
 export { default as ChatPrivacyDialog } from './ChatPrivacyDialog';

+ 7
- 2
react/features/chat/components/native/styles.js Vedi File

2
 
2
 
3
 import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
3
 import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
4
 import { BoxModel, ColorPalette } from '../../../base/styles';
4
 import { BoxModel, ColorPalette } from '../../../base/styles';
5
+import BaseTheme from '../../../base/ui/components/BaseTheme.native';
5
 
6
 
6
 const BUBBLE_RADIUS = 8;
7
 const BUBBLE_RADIUS = 8;
7
 
8
 
40
         alignSelf: 'center',
41
         alignSelf: 'center',
41
         flex: 1,
42
         flex: 1,
42
         padding: BoxModel.padding,
43
         padding: BoxModel.padding,
43
-        paddingTop: '10%'
44
+        paddingTop: '8%'
44
     },
45
     },
45
 
46
 
46
     /**
47
     /**
126
         fontSize: 13
127
         fontSize: 13
127
     },
128
     },
128
 
129
 
130
+    chatContainer: {
131
+        flex: 1
132
+    },
133
+
129
     tabContainer: {
134
     tabContainer: {
130
         flexDirection: 'row',
135
         flexDirection: 'row',
131
         justifyContent: 'center'
136
         justifyContent: 'center'
164
     },
169
     },
165
 
170
 
166
     emptyComponentText: {
171
     emptyComponentText: {
167
-        color: schemeColor('displayName'),
172
+        color: BaseTheme.palette.ui05,
168
         textAlign: 'center'
173
         textAlign: 'center'
169
     },
174
     },
170
 
175
 

+ 0
- 2
react/features/chat/constants.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
-export const CHAT_VIEW_MODAL_ID = 'chatView';
4
-
5
 /**
3
 /**
6
  * The size of the chat.
4
  * The size of the chat.
7
  */
5
  */

+ 0
- 17
react/features/chat/middleware.js Vedi File

10
     JitsiConferenceErrors,
10
     JitsiConferenceErrors,
11
     JitsiConferenceEvents
11
     JitsiConferenceEvents
12
 } from '../base/lib-jitsi-meet';
12
 } from '../base/lib-jitsi-meet';
13
-import { setActiveModalId } from '../base/modal';
14
 import {
13
 import {
15
     getLocalParticipant,
14
     getLocalParticipant,
16
     getParticipantById,
15
     getParticipantById,
18
 } from '../base/participants';
17
 } from '../base/participants';
19
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
18
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
20
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
19
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
21
-import { openDisplayNamePrompt } from '../display-name';
22
 import { resetNbUnreadPollsMessages } from '../polls/actions';
20
 import { resetNbUnreadPollsMessages } from '../polls/actions';
23
 import { ADD_REACTION_MESSAGE } from '../reactions/actionTypes';
21
 import { ADD_REACTION_MESSAGE } from '../reactions/actionTypes';
24
 import { pushReactions } from '../reactions/actions.any';
22
 import { pushReactions } from '../reactions/actions.any';
35
 import { closeChat } from './actions.any';
33
 import { closeChat } from './actions.any';
36
 import { ChatPrivacyDialog } from './components';
34
 import { ChatPrivacyDialog } from './components';
37
 import {
35
 import {
38
-    CHAT_VIEW_MODAL_ID,
39
     INCOMING_MSG_SOUND_ID,
36
     INCOMING_MSG_SOUND_ID,
40
     MESSAGE_TYPE_ERROR,
37
     MESSAGE_TYPE_ERROR,
41
     MESSAGE_TYPE_LOCAL,
38
     MESSAGE_TYPE_LOCAL,
95
         break;
92
         break;
96
 
93
 
97
     case OPEN_CHAT:
94
     case OPEN_CHAT:
98
-        if (navigator.product === 'ReactNative') {
99
-            if (localParticipant.name) {
100
-                dispatch(setActiveModalId(CHAT_VIEW_MODAL_ID));
101
-            } else {
102
-                dispatch(openDisplayNamePrompt(() => {
103
-                    dispatch(setActiveModalId(CHAT_VIEW_MODAL_ID));
104
-                }));
105
-            }
106
-        } else {
107
-            dispatch(setActiveModalId(CHAT_VIEW_MODAL_ID));
108
-        }
109
-
110
         unreadCount = 0;
95
         unreadCount = 0;
111
 
96
 
112
         if (typeof APP !== 'undefined') {
97
         if (typeof APP !== 'undefined') {
126
         if (isPollTabOpen) {
111
         if (isPollTabOpen) {
127
             dispatch(resetNbUnreadPollsMessages());
112
             dispatch(resetNbUnreadPollsMessages());
128
         }
113
         }
129
-
130
-        dispatch(setActiveModalId());
131
         break;
114
         break;
132
     }
115
     }
133
 
116
 

+ 21
- 29
react/features/conference/components/native/Conference.js Vedi File

10
 import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
10
 import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
11
 import { TestConnectionInfo } from '../../../base/testing';
11
 import { TestConnectionInfo } from '../../../base/testing';
12
 import { ConferenceNotification, isCalendarEnabled } from '../../../calendar-sync';
12
 import { ConferenceNotification, isCalendarEnabled } from '../../../calendar-sync';
13
-import { Chat } from '../../../chat';
14
 import { DisplayNameLabel } from '../../../display-name';
13
 import { DisplayNameLabel } from '../../../display-name';
15
-import { SharedDocument } from '../../../etherpad';
16
 import {
14
 import {
17
     FILMSTRIP_SIZE,
15
     FILMSTRIP_SIZE,
18
     Filmstrip,
16
     Filmstrip,
19
     isFilmstripVisible,
17
     isFilmstripVisible,
20
     TileView
18
     TileView
21
 } from '../../../filmstrip';
19
 } from '../../../filmstrip';
22
-import { AddPeopleDialog, CalleeInfoContainer } from '../../../invite';
20
+import { CalleeInfoContainer } from '../../../invite';
23
 import { LargeVideo } from '../../../large-video';
21
 import { LargeVideo } from '../../../large-video';
24
 import { KnockingParticipantList } from '../../../lobby';
22
 import { KnockingParticipantList } from '../../../lobby';
25
-import { LobbyScreen } from '../../../lobby/components/native';
26
 import { getIsLobbyVisible } from '../../../lobby/functions';
23
 import { getIsLobbyVisible } from '../../../lobby/functions';
27
 import { BackButtonRegistry } from '../../../mobile/back-button';
24
 import { BackButtonRegistry } from '../../../mobile/back-button';
28
-import { ParticipantsPane } from '../../../participants-pane/components/native';
29
 import { Captions } from '../../../subtitles';
25
 import { Captions } from '../../../subtitles';
30
 import { setToolboxVisible } from '../../../toolbox/actions';
26
 import { setToolboxVisible } from '../../../toolbox/actions';
31
 import { Toolbox } from '../../../toolbox/components/native';
27
 import { Toolbox } from '../../../toolbox/components/native';
36
 } from '../AbstractConference';
32
 } from '../AbstractConference';
37
 import type { AbstractProps } from '../AbstractConference';
33
 import type { AbstractProps } from '../AbstractConference';
38
 
34
 
35
+import { navigate } from './ConferenceNavigationContainerRef';
39
 import LonelyMeetingExperience from './LonelyMeetingExperience';
36
 import LonelyMeetingExperience from './LonelyMeetingExperience';
40
 import NavigationBar from './NavigationBar';
37
 import NavigationBar from './NavigationBar';
38
+import { screen } from './routes';
41
 import styles from './styles';
39
 import styles from './styles';
42
 
40
 
43
 
41
 
141
         BackButtonRegistry.addListener(this._onHardwareBackPress);
139
         BackButtonRegistry.addListener(this._onHardwareBackPress);
142
     }
140
     }
143
 
141
 
142
+    /**
143
+     * Implements {@code Component#componentDidUpdate}.
144
+     *
145
+     * @inheritdoc
146
+     */
147
+    componentDidUpdate(prevProps) {
148
+        const { _showLobby } = this.props;
149
+
150
+        if (!prevProps._showLobby && _showLobby) {
151
+            navigate(screen.lobby);
152
+        }
153
+
154
+        if (prevProps._showLobby && !_showLobby) {
155
+            navigate(screen.conference.main);
156
+        }
157
+    }
158
+
144
     /**
159
     /**
145
      * Implements {@link Component#componentWillUnmount()}. Invoked immediately
160
      * Implements {@link Component#componentWillUnmount()}. Invoked immediately
146
      * before this component is unmounted and destroyed. Disconnects the
161
      * before this component is unmounted and destroyed. Disconnects the
161
      * @returns {ReactElement}
176
      * @returns {ReactElement}
162
      */
177
      */
163
     render() {
178
     render() {
164
-        const { _fullscreenEnabled, _showLobby } = this.props;
165
-
166
-        if (_showLobby) {
167
-            return <LobbyScreen />;
168
-        }
179
+        const { _fullscreenEnabled } = this.props;
169
 
180
 
170
         return (
181
         return (
171
             <Container style = { styles.conference }>
182
             <Container style = { styles.conference }>
217
         return true;
228
         return true;
218
     }
229
     }
219
 
230
 
220
-    /**
221
-     * Renders JitsiModals that are supposed to be on the conference screen.
222
-     *
223
-     * @returns {Array<ReactElement>}
224
-     */
225
-    _renderConferenceModals() {
226
-        return [
227
-            <AddPeopleDialog key = 'addPeopleDialog' />,
228
-            <Chat key = 'chat' />,
229
-            <SharedDocument key = 'sharedDocument' />
230
-        ];
231
-    }
232
-
233
     /**
231
     /**
234
      * Renders the conference notification badge if the feature is enabled.
232
      * Renders the conference notification badge if the feature is enabled.
235
      *
233
      *
254
     _renderContent() {
252
     _renderContent() {
255
         const {
253
         const {
256
             _connecting,
254
             _connecting,
257
-            _isParticipantsPaneOpen,
258
             _largeVideoParticipantId,
255
             _largeVideoParticipantId,
259
             _reducedUI,
256
             _reducedUI,
260
             _shouldDisplayTileView
257
             _shouldDisplayTileView
316
                 <TestConnectionInfo />
313
                 <TestConnectionInfo />
317
                 { this._renderConferenceNotification() }
314
                 { this._renderConferenceNotification() }
318
 
315
 
319
-                { this._renderConferenceModals() }
320
-
321
                 {_shouldDisplayTileView && <Toolbox />}
316
                 {_shouldDisplayTileView && <Toolbox />}
322
-
323
-                { _isParticipantsPaneOpen && <ParticipantsPane /> }
324
-
325
             </>
317
             </>
326
         );
318
         );
327
     }
319
     }

+ 100
- 0
react/features/conference/components/native/ConferenceNavigationContainer.js Vedi File

1
+// @flow
2
+
3
+import { NavigationContainer } from '@react-navigation/native';
4
+import { createStackNavigator } from '@react-navigation/stack';
5
+import React from 'react';
6
+import { SafeAreaProvider } from 'react-native-safe-area-context';
7
+import { useSelector } from 'react-redux';
8
+
9
+import { Chat, ChatAndPolls } from '../../../chat';
10
+import { SharedDocument } from '../../../etherpad';
11
+import AddPeopleDialog
12
+    from '../../../invite/components/add-people-dialog/native/AddPeopleDialog';
13
+import LobbyScreen from '../../../lobby/components/native/LobbyScreen';
14
+import { ParticipantsPane } from '../../../participants-pane/components/native';
15
+import { getDisablePolls } from '../../functions';
16
+
17
+import Conference from './Conference';
18
+import {
19
+    conferenceNavigationRef
20
+} from './ConferenceNavigationContainerRef';
21
+import {
22
+    chatScreenOptions,
23
+    conferenceScreenOptions,
24
+    inviteScreenOptions,
25
+    lobbyScreenOptions,
26
+    participantsScreenOptions,
27
+    sharedDocumentScreenOptions
28
+} from './ConferenceNavigatorScreenOptions';
29
+import { screen } from './routes';
30
+
31
+const ConferenceStack = createStackNavigator();
32
+
33
+const ConferenceNavigationContainer = () => {
34
+    const isPollsDisabled = useSelector(getDisablePolls);
35
+    const ChatScreen
36
+        = isPollsDisabled
37
+            ? Chat
38
+            : ChatAndPolls;
39
+    const chatScreenName
40
+        = isPollsDisabled
41
+            ? screen.conference.chat
42
+            : screen.conference.chatandpolls.main;
43
+
44
+    return (
45
+        <SafeAreaProvider>
46
+            <NavigationContainer
47
+                independent = { true }
48
+                ref = { conferenceNavigationRef }
49
+                theme = {{
50
+                    colors: {
51
+                        background: '#fff'
52
+                    }
53
+                }}>
54
+                <ConferenceStack.Navigator
55
+                    initialRouteName = { screen.conference.main }
56
+                    mode = 'modal'>
57
+                    <ConferenceStack.Screen
58
+                        component = { Conference }
59
+                        name = { screen.conference.main }
60
+                        options = {{
61
+                            ...conferenceScreenOptions
62
+                        }} />
63
+                    <ConferenceStack.Screen
64
+                        /* eslint-disable-next-line react/jsx-no-bind */
65
+                        component = { ChatScreen }
66
+                        name = { chatScreenName }
67
+                        options = {{
68
+                            ...chatScreenOptions
69
+                        }} />
70
+                    <ConferenceStack.Screen
71
+                        component = { ParticipantsPane }
72
+                        name = { screen.conference.participants }
73
+                        options = {{
74
+                            ...participantsScreenOptions
75
+                        }} />
76
+                    <ConferenceStack.Screen
77
+                        component = { LobbyScreen }
78
+                        name = { screen.lobby }
79
+                        options = {{
80
+                            ...lobbyScreenOptions
81
+                        }} />
82
+                    <ConferenceStack.Screen
83
+                        component = { AddPeopleDialog }
84
+                        name = { screen.conference.invite }
85
+                        options = {{
86
+                            ...inviteScreenOptions
87
+                        }} />
88
+                    <ConferenceStack.Screen
89
+                        component = { SharedDocument }
90
+                        name = { screen.conference.sharedDocument }
91
+                        options = {{
92
+                            ...sharedDocumentScreenOptions
93
+                        }} />
94
+                </ConferenceStack.Navigator>
95
+            </NavigationContainer>
96
+        </SafeAreaProvider>
97
+    );
98
+};
99
+
100
+export default ConferenceNavigationContainer;

+ 40
- 0
react/features/conference/components/native/ConferenceNavigationContainerRef.js Vedi File

1
+// @flow
2
+
3
+import React from 'react';
4
+
5
+// $FlowExpectedError
6
+export const conferenceNavigationRef = React.createRef();
7
+
8
+/**
9
+ * User defined navigation action included inside the reference to the container.
10
+ *
11
+ * @param {string} name - Destination name of the route that has been defined somewhere.
12
+ * @param {Object} params - Params to pass to the destination route.
13
+ * @returns {Function}
14
+ */
15
+export function navigate(name: string, params: Object) {
16
+    // $FlowExpectedError
17
+    return conferenceNavigationRef.current?.navigate(name, params);
18
+}
19
+
20
+/**
21
+ * User defined navigation action included inside the reference to the container.
22
+ *
23
+ * @returns {Function}
24
+ */
25
+export function goBack() {
26
+    // $FlowExpectedError
27
+    return conferenceNavigationRef.current?.goBack();
28
+}
29
+
30
+/**
31
+ * User defined navigation action included inside the reference to the container.
32
+ *
33
+ * @param {Object} params - Params to pass to the destination route.
34
+ * @returns {Function}
35
+ */
36
+export function setParams(params: Object) {
37
+    // $FlowExpectedError
38
+    return conferenceNavigationRef.current?.setParams(params);
39
+}
40
+

+ 111
- 0
react/features/conference/components/native/ConferenceNavigatorScreenOptions.js Vedi File

1
+import { TransitionPresets } from '@react-navigation/stack';
2
+import React from 'react';
3
+import { Platform } from 'react-native';
4
+
5
+import { IconClose } from '../../../base/icons';
6
+import BaseTheme from '../../../base/ui/components/BaseTheme';
7
+
8
+import { goBack } from './ConferenceNavigationContainerRef';
9
+import HeaderNavigationButton from './HeaderNavigationButton';
10
+
11
+
12
+/**
13
+ * Default modal transition for the current platform.
14
+ */
15
+export const conferenceModalPresentation = Platform.select({
16
+    ios: TransitionPresets.ModalPresentationIOS,
17
+    default: TransitionPresets.DefaultTransition
18
+});
19
+
20
+/**
21
+ * Screen options and transition types.
22
+ */
23
+export const screenOptions = {
24
+    ...TransitionPresets.ModalTransition,
25
+    gestureEnabled: false,
26
+    headerShown: false
27
+};
28
+
29
+/**
30
+ * Screen options for conference.
31
+ */
32
+export const conferenceScreenOptions = {
33
+    ...screenOptions
34
+};
35
+
36
+/**
37
+ * Screen options for lobby modal.
38
+ */
39
+export const lobbyScreenOptions = {
40
+    ...screenOptions
41
+};
42
+
43
+/**
44
+ * Tab bar options for chat screen.
45
+ */
46
+export const chatTabBarOptions = {
47
+    activeTintColor: BaseTheme.palette.screen01Header,
48
+    labelStyle: {
49
+        fontSize: BaseTheme.typography.labelRegular.fontSize
50
+    },
51
+    inactiveTintColor: BaseTheme.palette.field02Disabled,
52
+    indicatorStyle: {
53
+        backgroundColor: BaseTheme.palette.screen01Header
54
+    }
55
+};
56
+
57
+/**
58
+ * Screen options for presentation type modals.
59
+ */
60
+export const presentationScreenOptions = {
61
+    ...conferenceModalPresentation,
62
+    headerBackTitleVisible: false,
63
+    headerLeft: () => (
64
+        <HeaderNavigationButton
65
+            onPress = { goBack }
66
+            src = { IconClose } />
67
+    ),
68
+    headerStatusBarHeight: 0,
69
+    headerStyle: {
70
+        backgroundColor: BaseTheme.palette.screen01Header
71
+    },
72
+    headerTitleStyle: {
73
+        color: BaseTheme.palette.text01
74
+    }
75
+};
76
+
77
+/**
78
+ * Screen options for chat.
79
+ */
80
+export const chatScreenOptions = {
81
+    ...presentationScreenOptions
82
+};
83
+
84
+/**
85
+ * Screen options for invite modal.
86
+ */
87
+export const inviteScreenOptions = {
88
+    ...presentationScreenOptions
89
+};
90
+
91
+/**
92
+ * Screen options for participants modal.
93
+ */
94
+export const participantsScreenOptions = {
95
+    ...presentationScreenOptions
96
+};
97
+
98
+/**
99
+ * Screen options for shared document.
100
+ */
101
+export const sharedDocumentScreenOptions = {
102
+    ...TransitionPresets.DefaultTransition,
103
+    headerBackTitleVisible: false,
104
+    headerShown: true,
105
+    headerStyle: {
106
+        backgroundColor: BaseTheme.palette.screen01Header
107
+    },
108
+    headerTitleStyle: {
109
+        color: BaseTheme.palette.text01
110
+    }
111
+};

+ 39
- 0
react/features/conference/components/native/HeaderNavigationButton.js Vedi File

1
+// @flow
2
+
3
+import React from 'react';
4
+import { TouchableWithoutFeedback } from 'react-native';
5
+
6
+import { Icon } from '../../../base/icons';
7
+
8
+import styles from './styles';
9
+
10
+type Props = {
11
+
12
+    /**
13
+     * Callback to invoke when the {@code HeaderNavigationButton} is clicked/pressed.
14
+     */
15
+    onPress: Function,
16
+
17
+    /**
18
+     * The ImageSource to be rendered as image.
19
+     */
20
+    src: Object,
21
+
22
+    /**
23
+     * The component's external style
24
+     */
25
+    style: Object
26
+}
27
+
28
+const HeaderNavigationButton = ({ onPress, src, style }: Props) => (
29
+    <TouchableWithoutFeedback
30
+        onPress = { onPress } >
31
+        <Icon
32
+            size = { 20 }
33
+            src = { src }
34
+            style = { [ styles.headerNavigationButton, style ] } />
35
+    </TouchableWithoutFeedback>
36
+);
37
+
38
+
39
+export default HeaderNavigationButton;

+ 1
- 0
react/features/conference/components/native/index.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
 export { default as Conference } from './Conference';
3
 export { default as Conference } from './Conference';
4
+export { default as ConferenceNavigationContainer } from './ConferenceNavigationContainer';
4
 export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
5
 export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
5
 export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';
6
 export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';

+ 17
- 0
react/features/conference/components/native/routes.js Vedi File

1
+export const screen = {
2
+    conference: {
3
+        main: 'Conference',
4
+        chat: 'Chat',
5
+        chatandpolls: {
6
+            main: 'Chat and Polls',
7
+            tab: {
8
+                chat: 'Chat',
9
+                polls: 'Polls'
10
+            }
11
+        },
12
+        participants: 'Participants',
13
+        invite: 'Invite',
14
+        sharedDocument: 'Shared document'
15
+    },
16
+    lobby: 'Lobby'
17
+};

+ 4
- 0
react/features/conference/components/native/styles.js Vedi File

23
         margin: 10
23
         margin: 10
24
     },
24
     },
25
 
25
 
26
+    headerNavigationButton: {
27
+        marginLeft: 12
28
+    },
29
+
26
     /**
30
     /**
27
      * View that contains the indicators.
31
      * View that contains the indicators.
28
      */
32
      */

+ 20
- 0
react/features/conference/functions.native.js Vedi File

1
+// @flow
2
+
3
+import { toState } from '../base/redux';
4
+
1
 export * from './functions.any';
5
 export * from './functions.any';
6
+
7
+
8
+/**
9
+ *
10
+ * Returns true if polls feature is disabled.
11
+ *
12
+ * @param {(Function|Object)} stateful - The (whole) redux state, or redux's
13
+ * {@code getState} function to be used to retrieve the state
14
+ * features/base/config.
15
+ * @returns {boolean}.
16
+ */
17
+export function getDisablePolls(stateful: Object) {
18
+    const state = toState(stateful['features/base/config']);
19
+
20
+    return state.disablePolls;
21
+}

+ 6
- 11
react/features/etherpad/components/SharedDocumentButton.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
-import type { Dispatch } from 'redux';
4
-
5
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
3
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
6
 import { translate } from '../../base/i18n';
4
 import { translate } from '../../base/i18n';
7
 import { IconShareDoc } from '../../base/icons';
5
 import { IconShareDoc } from '../../base/icons';
8
 import { connect } from '../../base/redux';
6
 import { connect } from '../../base/redux';
9
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
7
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
10
-import { toggleDocument } from '../actions';
8
+import { navigate } from '../../conference/components/native/ConferenceNavigationContainerRef';
9
+import { screen } from '../../conference/components/native/routes';
11
 
10
 
12
 
11
 
13
 type Props = AbstractButtonProps & {
12
 type Props = AbstractButtonProps & {
15
     /**
14
     /**
16
      * Whether the shared document is being edited or not.
15
      * Whether the shared document is being edited or not.
17
      */
16
      */
18
-    _editing: boolean,
19
-
20
-    /**
21
-     * Redux dispatch function.
22
-     */
23
-    dispatch: Dispatch<any>,
17
+    _editing: boolean
24
 };
18
 };
25
 
19
 
26
 /**
20
 /**
59
      * @returns {void}
53
      * @returns {void}
60
      */
54
      */
61
     _handleClick() {
55
     _handleClick() {
62
-        const { _editing, dispatch, handleClick } = this.props;
56
+        const { _editing, handleClick } = this.props;
63
 
57
 
64
         if (handleClick) {
58
         if (handleClick) {
65
             handleClick();
59
             handleClick();
72
             {
66
             {
73
                 enable: !_editing
67
                 enable: !_editing
74
             }));
68
             }));
75
-        dispatch(toggleDocument());
69
+
70
+        navigate(screen.conference.sharedDocument);
76
     }
71
     }
77
 
72
 
78
     /**
73
     /**

+ 33
- 58
react/features/etherpad/components/native/SharedDocument.js Vedi File

3
 import React, { PureComponent } from 'react';
3
 import React, { PureComponent } from 'react';
4
 import { View } from 'react-native';
4
 import { View } from 'react-native';
5
 import { WebView } from 'react-native-webview';
5
 import { WebView } from 'react-native-webview';
6
-import type { Dispatch } from 'redux';
7
 
6
 
8
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
9
 import { translate } from '../../../base/i18n';
8
 import { translate } from '../../../base/i18n';
10
-import { JitsiModal } from '../../../base/modal';
9
+import { IconArrowBack } from '../../../base/icons';
10
+import JitsiScreen from '../../../base/modal/components/JitsiScreen';
11
 import { LoadingIndicator } from '../../../base/react';
11
 import { LoadingIndicator } from '../../../base/react';
12
 import { connect } from '../../../base/redux';
12
 import { connect } from '../../../base/redux';
13
-import { toggleDocument } from '../../actions';
14
-import { SHARE_DOCUMENT_VIEW_ID } from '../../constants';
13
+import { goBack } from '../../../conference/components/native/ConferenceNavigationContainerRef';
14
+import HeaderNavigationButton
15
+    from '../../../conference/components/native/HeaderNavigationButton';
15
 import { getSharedDocumentUrl } from '../../functions';
16
 import { getSharedDocumentUrl } from '../../functions';
16
 
17
 
17
 import styles, { INDICATOR_COLOR } from './styles';
18
 import styles, { INDICATOR_COLOR } from './styles';
32
     _headerStyles: Object,
33
     _headerStyles: Object,
33
 
34
 
34
     /**
35
     /**
35
-     * True if the chat window should be rendered.
36
+     * Default prop for navigation between screen components(React Navigation)
36
      */
37
      */
37
-    _isOpen: boolean,
38
-
39
-    /**
40
-     * The Redux dispatch function.
41
-     */
42
-    dispatch: Dispatch<any>,
38
+    navigation: Object,
43
 
39
 
44
     /**
40
     /**
45
      * Function to be used to translate i18n labels.
41
      * Function to be used to translate i18n labels.
59
     constructor(props: Props) {
55
     constructor(props: Props) {
60
         super(props);
56
         super(props);
61
 
57
 
62
-        this._onClose = this._onClose.bind(this);
63
-        this._onError = this._onError.bind(this);
64
         this._renderLoading = this._renderLoading.bind(this);
58
         this._renderLoading = this._renderLoading.bind(this);
65
     }
59
     }
66
 
60
 
61
+    /**
62
+     * Implements React's {@link Component#componentDidMount()}. Invoked
63
+     * immediately after this component is mounted.
64
+     *
65
+     * @inheritdoc
66
+     * @returns {void}
67
+     */
68
+    componentDidMount() {
69
+        const { navigation } = this.props;
70
+
71
+        navigation.setOptions({
72
+            headerLeft: () => (
73
+                <HeaderNavigationButton
74
+                    onPress = { goBack }
75
+                    src = { IconArrowBack }
76
+                    style = { styles.headerArrowBack } />
77
+            )
78
+        });
79
+    }
80
+
67
     /**
81
     /**
68
      * Implements React's {@link Component#render()}.
82
      * Implements React's {@link Component#render()}.
69
      *
83
      *
73
         const { _documentUrl } = this.props;
87
         const { _documentUrl } = this.props;
74
 
88
 
75
         return (
89
         return (
76
-            <JitsiModal
77
-                headerProps = {{
78
-                    headerLabelKey: 'documentSharing.title'
79
-                }}
80
-                modalId = { SHARE_DOCUMENT_VIEW_ID }
81
-                style = { styles.webView }>
90
+            <JitsiScreen
91
+                addHeaderHeightValue = { true }
92
+                hasTabNavigator = { false }
93
+                style = { styles.sharedDocContainer }>
82
                 <WebView
94
                 <WebView
83
-                    onError = { this._onError }
84
                     renderLoading = { this._renderLoading }
95
                     renderLoading = { this._renderLoading }
85
                     source = {{ uri: _documentUrl }}
96
                     source = {{ uri: _documentUrl }}
86
                     startInLoadingState = { true } />
97
                     startInLoadingState = { true } />
87
-            </JitsiModal>
98
+            </JitsiScreen>
88
         );
99
         );
89
     }
100
     }
90
 
101
 
91
-    _onClose: () => boolean
92
-
93
-    /**
94
-     * Closes the window.
95
-     *
96
-     * @returns {boolean}
97
-     */
98
-    _onClose() {
99
-        const { _isOpen, dispatch } = this.props;
100
-
101
-        if (_isOpen) {
102
-            dispatch(toggleDocument());
103
-
104
-            return true;
105
-        }
106
-
107
-        return false;
108
-    }
109
-
110
-    _onError: () => void;
111
-
112
-    /**
113
-     * Callback to handle the error if the page fails to load.
114
-     *
115
-     * @returns {void}
116
-     */
117
-    _onError() {
118
-        const { _isOpen, dispatch } = this.props;
119
-
120
-        if (_isOpen) {
121
-            dispatch(toggleDocument());
122
-        }
123
-    }
124
-
125
     _renderLoading: () => React$Component<any>;
102
     _renderLoading: () => React$Component<any>;
126
 
103
 
127
     /**
104
     /**
148
  * @returns {Object}
125
  * @returns {Object}
149
  */
126
  */
150
 export function _mapStateToProps(state: Object) {
127
 export function _mapStateToProps(state: Object) {
151
-    const { editing } = state['features/etherpad'];
152
     const documentUrl = getSharedDocumentUrl(state);
128
     const documentUrl = getSharedDocumentUrl(state);
153
 
129
 
154
     return {
130
     return {
155
         _documentUrl: documentUrl,
131
         _documentUrl: documentUrl,
156
-        _headerStyles: ColorSchemeRegistry.get(state, 'Header'),
157
-        _isOpen: editing
132
+        _headerStyles: ColorSchemeRegistry.get(state, 'Header')
158
     };
133
     };
159
 }
134
 }
160
 
135
 

+ 8
- 0
react/features/etherpad/components/native/styles.js Vedi File

6
 
6
 
7
 export default {
7
 export default {
8
 
8
 
9
+    headerArrowBack: {
10
+        marginLeft: 12
11
+    },
12
+
9
     indicatorWrapper: {
13
     indicatorWrapper: {
10
         alignItems: 'center',
14
         alignItems: 'center',
11
         backgroundColor: ColorPalette.white,
15
         backgroundColor: ColorPalette.white,
13
         justifyContent: 'center'
17
         justifyContent: 'center'
14
     },
18
     },
15
 
19
 
20
+    sharedDocContainer: {
21
+        flex: 1
22
+    },
23
+
16
     webView: {
24
     webView: {
17
         backgroundColor: 'rgb(242, 242, 242)'
25
         backgroundColor: 'rgb(242, 242, 242)'
18
     }
26
     }

+ 3
- 3
react/features/invite/actions.native.js Vedi File

3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
 import { getFeatureFlag, ADD_PEOPLE_ENABLED } from '../base/flags';
5
 import { getFeatureFlag, ADD_PEOPLE_ENABLED } from '../base/flags';
6
-import { setActiveModalId } from '../base/modal';
6
+import { navigate } from '../conference/components/native/ConferenceNavigationContainerRef';
7
+import { screen } from '../conference/components/native/routes';
7
 import { beginShareRoom } from '../share-room';
8
 import { beginShareRoom } from '../share-room';
8
 
9
 
9
-import { ADD_PEOPLE_DIALOG_VIEW_ID } from './constants';
10
 import { isAddPeopleEnabled, isDialOutEnabled } from './functions';
10
 import { isAddPeopleEnabled, isDialOutEnabled } from './functions';
11
 
11
 
12
 export * from './actions.any';
12
 export * from './actions.any';
24
             && (isAddPeopleEnabled(state) || isDialOutEnabled(state));
24
             && (isAddPeopleEnabled(state) || isDialOutEnabled(state));
25
 
25
 
26
         if (addPeopleEnabled) {
26
         if (addPeopleEnabled) {
27
-            return dispatch(setActiveModalId(ADD_PEOPLE_DIALOG_VIEW_ID));
27
+            return navigate(screen.conference.invite);
28
         }
28
         }
29
 
29
 
30
         return dispatch(beginShareRoom());
30
         return dispatch(beginShareRoom());

+ 67
- 31
react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js Vedi File

6
     ActivityIndicator,
6
     ActivityIndicator,
7
     FlatList,
7
     FlatList,
8
     Platform,
8
     Platform,
9
-    SafeAreaView,
10
     TextInput,
9
     TextInput,
11
     TouchableOpacity,
10
     TouchableOpacity,
12
     View
11
     View
13
 } from 'react-native';
12
 } from 'react-native';
13
+import { Text, TouchableRipple, withTheme } from 'react-native-paper';
14
 
14
 
15
-import { ColorSchemeRegistry } from '../../../../base/color-scheme';
16
 import { AlertDialog, openDialog } from '../../../../base/dialog';
15
 import { AlertDialog, openDialog } from '../../../../base/dialog';
17
 import { translate } from '../../../../base/i18n';
16
 import { translate } from '../../../../base/i18n';
18
 import {
17
 import {
24
     IconSearch,
23
     IconSearch,
25
     IconShare
24
     IconShare
26
 } from '../../../../base/icons';
25
 } from '../../../../base/icons';
27
-import { JitsiModal, setActiveModalId } from '../../../../base/modal';
26
+import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
28
 import {
27
 import {
29
     AvatarListItem,
28
     AvatarListItem,
30
     type Item
29
     type Item
31
 } from '../../../../base/react';
30
 } from '../../../../base/react';
32
 import { connect } from '../../../../base/redux';
31
 import { connect } from '../../../../base/redux';
33
-import { ColorPalette } from '../../../../base/styles';
34
 import { beginShareRoom } from '../../../../share-room';
32
 import { beginShareRoom } from '../../../../share-room';
35
-import { ADD_PEOPLE_DIALOG_VIEW_ID, INVITE_TYPES } from '../../../constants';
33
+import { INVITE_TYPES } from '../../../constants';
36
 import AbstractAddPeopleDialog, {
34
 import AbstractAddPeopleDialog, {
37
     type Props as AbstractProps,
35
     type Props as AbstractProps,
38
     type State as AbstractState,
36
     type State as AbstractState,
47
 type Props = AbstractProps & {
45
 type Props = AbstractProps & {
48
 
46
 
49
     /**
47
     /**
50
-     * The color schemed style of the Header.
48
+     * True if the invite dialog should be open, false otherwise.
51
      */
49
      */
52
-    _headerStyles: Object,
50
+    _isVisible: boolean,
53
 
51
 
54
     /**
52
     /**
55
-     * True if the invite dialog should be open, false otherwise.
53
+     * Default prop for navigation between screen components(React Navigation)
56
      */
54
      */
57
-    _isVisible: boolean,
55
+    navigation: Object,
58
 
56
 
59
     /**
57
     /**
60
      * Function used to translate i18n labels.
58
      * Function used to translate i18n labels.
61
      */
59
      */
62
-    t: Function
60
+    t: Function,
61
+
62
+    /**
63
+     * Theme used for styles.
64
+     */
65
+    theme: Object
63
 };
66
 };
64
 
67
 
65
 type State = AbstractState & {
68
 type State = AbstractState & {
136
         this._setFieldRef = this._setFieldRef.bind(this);
139
         this._setFieldRef = this._setFieldRef.bind(this);
137
     }
140
     }
138
 
141
 
142
+    /**
143
+     * Implements React's {@link Component#componentDidMount()}. Invoked
144
+     * immediately after this component is mounted.
145
+     *
146
+     * @inheritdoc
147
+     * @returns {void}
148
+     */
149
+    componentDidMount() {
150
+        const { navigation, t, theme } = this.props;
151
+        const { palette } = theme;
152
+
153
+        navigation.setOptions({
154
+            headerRight: () => (
155
+                <TouchableRipple
156
+                    disabled = { this._isAddDisabled() }
157
+                    rippleColor = { palette.screen01Header } >
158
+                    <Text
159
+                        style = { styles.headerSendInvite }>{ t('inviteDialog.send') }
160
+                    </Text>
161
+                </TouchableRipple>
162
+            )
163
+        });
164
+    }
165
+
139
     /**
166
     /**
140
      * Implements {@code Component#componentDidUpdate}.
167
      * Implements {@code Component#componentDidUpdate}.
141
      *
168
      *
142
      * @inheritdoc
169
      * @inheritdoc
143
      */
170
      */
144
     componentDidUpdate(prevProps) {
171
     componentDidUpdate(prevProps) {
172
+        const { navigation, t, theme } = this.props;
173
+        const { palette } = theme;
174
+
175
+        navigation.setOptions({
176
+            // eslint-disable-next-line react/no-multi-comp
177
+            headerRight: () => (
178
+                <TouchableRipple
179
+                    disabled = { this._isAddDisabled() }
180
+                    onPress = { this._onInvite }
181
+                    rippleColor = { palette.screen01Header } >
182
+                    <Text
183
+                        /* eslint-disable-next-line react-native/no-inline-styles */
184
+                        style = { styles.headerSendInvite }>{ t('inviteDialog.send') }
185
+                    </Text>
186
+                </TouchableRipple>
187
+            )
188
+        });
189
+
145
         if (prevProps._isVisible !== this.props._isVisible) {
190
         if (prevProps._isVisible !== this.props._isVisible) {
146
             // Clear state
191
             // Clear state
147
             this._clearState();
192
             this._clearState();
159
             _dialOutEnabled
204
             _dialOutEnabled
160
         } = this.props;
205
         } = this.props;
161
         const { inviteItems, selectableItems } = this.state;
206
         const { inviteItems, selectableItems } = this.state;
207
+        const { theme } = this.props;
208
+        const { palette } = theme;
162
 
209
 
163
         let placeholderKey = 'searchPlaceholder';
210
         let placeholderKey = 'searchPlaceholder';
164
 
211
 
169
         }
216
         }
170
 
217
 
171
         return (
218
         return (
172
-            <JitsiModal
219
+            <JitsiScreen
173
                 footerComponent = { this._renderShareMeetingButton }
220
                 footerComponent = { this._renderShareMeetingButton }
174
-                headerProps = {{
175
-                    forwardDisabled: this._isAddDisabled(),
176
-                    forwardLabelKey: 'inviteDialog.send',
177
-                    headerLabelKey: 'inviteDialog.header',
178
-                    onPressForward: this._onInvite
179
-                }}
180
-                modalId = { ADD_PEOPLE_DIALOG_VIEW_ID }>
221
+                hasTabNavigator = { false }
222
+                style = { styles.addPeopleContainer }>
181
                 <View
223
                 <View
182
                     style = { styles.searchFieldWrapper }>
224
                     style = { styles.searchFieldWrapper }>
183
                     <View style = { styles.searchIconWrapper }>
225
                     <View style = { styles.searchIconWrapper }>
198
                         placeholder = {
240
                         placeholder = {
199
                             this.props.t(`inviteDialog.${placeholderKey}`)
241
                             this.props.t(`inviteDialog.${placeholderKey}`)
200
                         }
242
                         }
201
-                        placeholderTextColor = { ColorPalette.lightGrey }
243
+                        placeholderTextColor = { palette.text04 }
202
                         ref = { this._setFieldRef }
244
                         ref = { this._setFieldRef }
203
                         spellCheck = { false }
245
                         spellCheck = { false }
204
                         style = { styles.searchField }
246
                         style = { styles.searchField }
222
                         keyboardShouldPersistTaps = 'always'
264
                         keyboardShouldPersistTaps = 'always'
223
                         renderItem = { this._renderItem } />
265
                         renderItem = { this._renderItem } />
224
                 </View>
266
                 </View>
225
-            </JitsiModal>
267
+            </JitsiScreen>
226
         );
268
         );
227
     }
269
     }
228
 
270
 
326
                         inviteItems: invitesLeftToSend
368
                         inviteItems: invitesLeftToSend
327
                     });
369
                     });
328
                     this._showFailedInviteAlert();
370
                     this._showFailedInviteAlert();
329
-                } else {
330
-                    this.props.dispatch(setActiveModalId());
331
                 }
371
                 }
332
             });
372
             });
333
     }
373
     }
562
      * @returns {React#Element<*>}
602
      * @returns {React#Element<*>}
563
      */
603
      */
564
     _renderShareMeetingButton() {
604
     _renderShareMeetingButton() {
565
-        const { _headerStyles } = this.props;
566
 
605
 
567
         return (
606
         return (
568
-            <SafeAreaView
607
+            <View
569
                 style = { [
608
                 style = { [
570
                     styles.bottomBar,
609
                     styles.bottomBar,
571
-                    _headerStyles.headerOverlay,
572
                     this.state.bottomPadding ? styles.extraBarPadding : null
610
                     this.state.bottomPadding ? styles.extraBarPadding : null
573
                 ] }>
611
                 ] }>
574
                 <TouchableOpacity
612
                 <TouchableOpacity
575
                     onPress = { this._onShareMeeting }>
613
                     onPress = { this._onShareMeeting }>
576
                     <Icon
614
                     <Icon
577
                         src = { IconShare }
615
                         src = { IconShare }
578
-                        style = { [ _headerStyles.headerButtonText, styles.shareIcon ] } />
616
+                        style = { styles.shareIcon } />
579
                 </TouchableOpacity>
617
                 </TouchableOpacity>
580
-            </SafeAreaView>
618
+            </View>
581
         );
619
         );
582
     }
620
     }
583
 
621
 
621
  */
659
  */
622
 function _mapStateToProps(state: Object) {
660
 function _mapStateToProps(state: Object) {
623
     return {
661
     return {
624
-        ..._abstractMapStateToProps(state),
625
-        _headerStyles: ColorSchemeRegistry.get(state, 'Header'),
626
-        _isVisible: state['features/base/modal'].activeModalId === ADD_PEOPLE_DIALOG_VIEW_ID
662
+        ..._abstractMapStateToProps(state)
627
     };
663
     };
628
 }
664
 }
629
 
665
 
630
-export default translate(connect(_mapStateToProps)(AddPeopleDialog));
666
+export default translate(connect(_mapStateToProps)(withTheme(AddPeopleDialog)));

+ 22
- 8
react/features/invite/components/add-people-dialog/native/styles.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import { BoxModel } from '../../../../base/styles';
3
 import { BoxModel } from '../../../../base/styles';
4
+import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
4
 
5
 
5
 export const AVATAR_SIZE = 40;
6
 export const AVATAR_SIZE = 40;
6
 export const DARK_GREY = 'rgb(28, 32, 37)';
7
 export const DARK_GREY = 'rgb(28, 32, 37)';
7
 export const LIGHT_GREY = 'rgb(209, 219, 232)';
8
 export const LIGHT_GREY = 'rgb(209, 219, 232)';
8
 export const ICON_SIZE = 15;
9
 export const ICON_SIZE = 15;
9
 
10
 
10
-const FIELD_COLOR = 'rgb(240, 243, 247)';
11
-
12
 export default {
11
 export default {
12
+
13
+    addPeopleContainer: {
14
+        flex: 1
15
+    },
16
+
13
     avatar: {
17
     avatar: {
14
         backgroundColor: LIGHT_GREY
18
         backgroundColor: LIGHT_GREY
15
     },
19
     },
21
 
25
 
22
     bottomBar: {
26
     bottomBar: {
23
         alignItems: 'center',
27
         alignItems: 'center',
24
-        flexDirection: 'row',
25
-        justifyContent: 'space-around'
28
+        justifyContent: 'center',
29
+        backgroundColor: BaseTheme.palette.screen01Header,
30
+        height: BaseTheme.spacing[10]
26
     },
31
     },
27
 
32
 
28
     clearButton: {
33
     clearButton: {
39
 
44
 
40
     clearIconContainer: {
45
     clearIconContainer: {
41
         alignItems: 'center',
46
         alignItems: 'center',
42
-        backgroundColor: FIELD_COLOR,
47
+        backgroundColor: BaseTheme.palette.section01,
43
         borderRadius: 12,
48
         borderRadius: 12,
44
         justifyContent: 'center',
49
         justifyContent: 'center',
45
         height: 24,
50
         height: 24,
53
         paddingBottom: 30
58
         paddingBottom: 30
54
     },
59
     },
55
 
60
 
61
+    headerCloseIcon: {
62
+        marginLeft: 12
63
+    },
64
+
65
+    headerSendInvite: {
66
+        color: BaseTheme.palette.text01,
67
+        marginRight: 12
68
+    },
69
+
56
     invitedList: {
70
     invitedList: {
57
         padding: 3
71
         padding: 3
58
     },
72
     },
80
     },
94
     },
81
 
95
 
82
     searchField: {
96
     searchField: {
83
-        backgroundColor: FIELD_COLOR,
97
+        backgroundColor: BaseTheme.palette.section01,
84
         borderBottomRightRadius: 10,
98
         borderBottomRightRadius: 10,
85
         borderTopRightRadius: 10,
99
         borderTopRightRadius: 10,
86
         color: DARK_GREY,
100
         color: DARK_GREY,
106
         alignItems: 'stretch',
120
         alignItems: 'stretch',
107
         flexDirection: 'row',
121
         flexDirection: 'row',
108
         height: 52,
122
         height: 52,
109
-        paddingHorizontal: 15,
123
+        paddingHorizontal: 12,
110
         paddingVertical: 8
124
         paddingVertical: 8
111
     },
125
     },
112
 
126
 
117
 
131
 
118
     searchIconWrapper: {
132
     searchIconWrapper: {
119
         alignItems: 'center',
133
         alignItems: 'center',
120
-        backgroundColor: FIELD_COLOR,
134
+        backgroundColor: BaseTheme.palette.section01,
121
         borderBottomLeftRadius: 10,
135
         borderBottomLeftRadius: 10,
122
         borderTopLeftRadius: 10,
136
         borderTopLeftRadius: 10,
123
         flexDirection: 'row',
137
         flexDirection: 'row',

+ 0
- 5
react/features/invite/constants.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
-/**
4
- * Modal ID for the AddPeopleDialog modal.
5
- */
6
-export const ADD_PEOPLE_DIALOG_VIEW_ID = 'ADD_PEOPLE_DIALOG_VIEW_ID';
7
-
8
 /**
3
 /**
9
  * Modal ID for the DialInSummary modal.
4
  * Modal ID for the DialInSummary modal.
10
  */
5
  */

+ 15
- 6
react/features/lobby/components/native/LobbyScreen.js Vedi File

2
 
2
 
3
 import React from 'react';
3
 import React from 'react';
4
 import { Text, View, TouchableOpacity, TextInput } from 'react-native';
4
 import { Text, View, TouchableOpacity, TextInput } from 'react-native';
5
+import { SafeAreaView } from 'react-native-safe-area-context';
5
 
6
 
6
 import { Avatar } from '../../../base/avatar';
7
 import { Avatar } from '../../../base/avatar';
7
-import { CustomDialog } from '../../../base/dialog';
8
 import { translate } from '../../../base/i18n';
8
 import { translate } from '../../../base/i18n';
9
 import { Icon, IconEdit } from '../../../base/icons';
9
 import { Icon, IconEdit } from '../../../base/icons';
10
+import JitsiScreen from '../../../base/modal/components/JitsiScreen';
10
 import { LoadingIndicator } from '../../../base/react';
11
 import { LoadingIndicator } from '../../../base/react';
11
 import { connect } from '../../../base/redux';
12
 import { connect } from '../../../base/redux';
12
 import AbstractLobbyScreen, { _mapStateToProps } from '../AbstractLobbyScreen';
13
 import AbstractLobbyScreen, { _mapStateToProps } from '../AbstractLobbyScreen';
26
         const { _meetingName, t } = this.props;
27
         const { _meetingName, t } = this.props;
27
 
28
 
28
         return (
29
         return (
29
-            <CustomDialog
30
-                onCancel = { this._onCancel }>
31
-                <View style = { styles.contentWrapper }>
30
+            <JitsiScreen
31
+                hasTabNavigator = { false }
32
+                style = { styles.contentWrapper }>
33
+                <SafeAreaView>
32
                     <Text style = { styles.dialogTitle }>
34
                     <Text style = { styles.dialogTitle }>
33
                         { t(this._getScreenTitleKey()) }
35
                         { t(this._getScreenTitleKey()) }
34
                     </Text>
36
                     </Text>
36
                         { _meetingName }
38
                         { _meetingName }
37
                     </Text>
39
                     </Text>
38
                     { this._renderContent() }
40
                     { this._renderContent() }
39
-                </View>
40
-            </CustomDialog>
41
+                </SafeAreaView>
42
+            </JitsiScreen>
41
         );
43
         );
42
     }
44
     }
43
 
45
 
234
                         { t('lobby.enterPasswordButton') }
236
                         { t('lobby.enterPasswordButton') }
235
                     </Text>
237
                     </Text>
236
                 </TouchableOpacity> }
238
                 </TouchableOpacity> }
239
+                <TouchableOpacity
240
+                    onPress = { this._onCancel }
241
+                    style = { styles.cancelButton }>
242
+                    <Text>
243
+                        { t('dialog.Cancel') }
244
+                    </Text>
245
+                </TouchableOpacity>
237
             </>
246
             </>
238
         );
247
         );
239
     }
248
     }

+ 24
- 5
react/features/lobby/components/native/styles.js Vedi File

12
     button: {
12
     button: {
13
         alignItems: 'center',
13
         alignItems: 'center',
14
         borderRadius: 4,
14
         borderRadius: 4,
15
-        marginVertical: 8,
16
-        paddingVertical: 10
15
+        marginVertical: 4,
16
+        paddingVertical: 8
17
     },
17
     },
18
 
18
 
19
     contentWrapper: {
19
     contentWrapper: {
20
         alignItems: 'center',
20
         alignItems: 'center',
21
+        display: 'flex',
21
         flexDirection: 'column',
22
         flexDirection: 'column',
22
-        padding: 32
23
+        justifyItems: 'center',
24
+        height: '100%'
25
+    },
26
+
27
+    closeIcon: {
28
+        color: 'red',
29
+        fontSize: 20
23
     },
30
     },
24
 
31
 
25
     dialogTitle: {
32
     dialogTitle: {
26
         fontSize: 18,
33
         fontSize: 18,
27
         fontWeight: 'bold',
34
         fontWeight: 'bold',
28
-        marginBottom: 10
35
+        margin: 'auto',
36
+        marginVertical: 24,
37
+        textAlign: 'center'
29
     },
38
     },
30
 
39
 
31
     displayNameText: {
40
     displayNameText: {
71
     },
80
     },
72
 
81
 
73
     joiningMessage: {
82
     joiningMessage: {
83
+        color: 'rgba(0, 0, 0, .7)',
84
+        paddingBottom: 36,
74
         textAlign: 'center'
85
         textAlign: 'center'
75
     },
86
     },
76
 
87
 
103
     },
114
     },
104
 
115
 
105
     secondaryText: {
116
     secondaryText: {
106
-        color: 'rgba(0, 0, 0, .7)'
117
+        color: 'rgba(0, 0, 0, .7)',
118
+        margin: 'auto',
119
+        textAlign: 'center'
120
+    },
121
+
122
+    cancelButton: {
123
+        alignItems: 'center',
124
+        backgroundColor: 'transparent',
125
+        marginVertical: 4
107
     },
126
     },
108
 
127
 
109
     // KnockingParticipantList
128
     // KnockingParticipantList

+ 10
- 11
react/features/participants-pane/components/native/LobbyParticipantList.js Vedi File

2
 
2
 
3
 import React, { useCallback } from 'react';
3
 import React, { useCallback } from 'react';
4
 import { useTranslation } from 'react-i18next';
4
 import { useTranslation } from 'react-i18next';
5
-import { ScrollView, Text, View } from 'react-native';
5
+import { Text, View } from 'react-native';
6
 import { Button, withTheme } from 'react-native-paper';
6
 import { Button, withTheme } from 'react-native-paper';
7
 import { useDispatch, useSelector } from 'react-redux';
7
 import { useDispatch, useSelector } from 'react-redux';
8
 
8
 
36
     }
36
     }
37
 
37
 
38
     return (
38
     return (
39
-        <View style = { styles.lobbyList }>
39
+        <View
40
+            style = { styles.lobbyListContainer } >
40
             <View style = { styles.lobbyListDetails } >
41
             <View style = { styles.lobbyListDetails } >
41
                 <Text style = { styles.lobbyListDescription }>
42
                 <Text style = { styles.lobbyListDescription }>
42
                     {t('participantsPane.headings.waitingLobby',
43
                     {t('participantsPane.headings.waitingLobby',
54
                     )
55
                     )
55
                 }
56
                 }
56
             </View>
57
             </View>
57
-            <ScrollView>
58
-                {
59
-                    participants.map(p => (
60
-                        <LobbyParticipantItem
61
-                            key = { p.id }
62
-                            participant = { p } />)
63
-                    )
64
-                }
65
-            </ScrollView>
58
+            {
59
+                participants.map(p => (
60
+                    <LobbyParticipantItem
61
+                        key = { p.id }
62
+                        participant = { p } />)
63
+                )
64
+            }
66
         </View>
65
         </View>
67
     );
66
     );
68
 };
67
 };

+ 4
- 1
react/features/participants-pane/components/native/MeetingParticipantList.js Vedi File

134
         } = this.props;
134
         } = this.props;
135
 
135
 
136
         return (
136
         return (
137
-            <View style = { styles.meetingList }>
137
+            <View
138
+                style = { styles.meetingListContainer }>
138
                 <Text style = { styles.meetingListDescription }>
139
                 <Text style = { styles.meetingListDescription }>
139
                     {t('participantsPane.headings.participantsList',
140
                     {t('participantsPane.headings.participantsList',
140
                         { count: _participantsCount })}
141
                         { count: _participantsCount })}
155
                     horizontal = { false }
156
                     horizontal = { false }
156
                     keyExtractor = { this._keyExtractor }
157
                     keyExtractor = { this._keyExtractor }
157
                     renderItem = { this._renderParticipant }
158
                     renderItem = { this._renderParticipant }
159
+                    scrollEnabled = { false }
158
                     showsHorizontalScrollIndicator = { false }
160
                     showsHorizontalScrollIndicator = { false }
161
+                    style = { styles.meetingList }
159
                     windowSize = { 2 } />
162
                     windowSize = { 2 } />
160
             </View>
163
             </View>
161
         );
164
         );

+ 9
- 12
react/features/participants-pane/components/native/ParticipantsPane.js Vedi File

2
 
2
 
3
 import React, { useCallback } from 'react';
3
 import React, { useCallback } from 'react';
4
 import { useTranslation } from 'react-i18next';
4
 import { useTranslation } from 'react-i18next';
5
-import { View } from 'react-native';
5
+import { ScrollView, View } from 'react-native';
6
 import { Button } from 'react-native-paper';
6
 import { Button } from 'react-native-paper';
7
 import { useDispatch, useSelector } from 'react-redux';
7
 import { useDispatch, useSelector } from 'react-redux';
8
 
8
 
9
 import { openDialog } from '../../../base/dialog';
9
 import { openDialog } from '../../../base/dialog';
10
-import { JitsiModal } from '../../../base/modal';
10
+import JitsiScreen from '../../../base/modal/components/JitsiScreen';
11
 import {
11
 import {
12
     isLocalParticipantModerator
12
     isLocalParticipantModerator
13
 } from '../../../base/participants';
13
 } from '../../../base/participants';
14
 import MuteEveryoneDialog
14
 import MuteEveryoneDialog
15
     from '../../../video-menu/components/native/MuteEveryoneDialog';
15
     from '../../../video-menu/components/native/MuteEveryoneDialog';
16
-import { close } from '../../actions.native';
17
 
16
 
18
 import { ContextMenuMore } from './ContextMenuMore';
17
 import { ContextMenuMore } from './ContextMenuMore';
19
 import HorizontalDotsIcon from './HorizontalDotsIcon';
18
 import HorizontalDotsIcon from './HorizontalDotsIcon';
29
 const ParticipantsPane = () => {
28
 const ParticipantsPane = () => {
30
     const dispatch = useDispatch();
29
     const dispatch = useDispatch();
31
     const openMoreMenu = useCallback(() => dispatch(openDialog(ContextMenuMore)), [ dispatch ]);
30
     const openMoreMenu = useCallback(() => dispatch(openDialog(ContextMenuMore)), [ dispatch ]);
32
-    const closePane = useCallback(() => dispatch(close()), [ dispatch ]);
33
     const isLocalModerator = useSelector(isLocalParticipantModerator);
31
     const isLocalModerator = useSelector(isLocalParticipantModerator);
34
     const muteAll = useCallback(() => dispatch(openDialog(MuteEveryoneDialog)),
32
     const muteAll = useCallback(() => dispatch(openDialog(MuteEveryoneDialog)),
35
         [ dispatch ]);
33
         [ dispatch ]);
36
     const { t } = useTranslation();
34
     const { t } = useTranslation();
37
 
35
 
38
     return (
36
     return (
39
-        <JitsiModal
40
-            headerProps = {{
41
-                headerLabelKey: 'participantsPane.header'
42
-            }}
43
-            onClose = { closePane }
37
+        <JitsiScreen
38
+            hasTabNavigator = { false }
44
             style = { styles.participantsPane }>
39
             style = { styles.participantsPane }>
45
-            <LobbyParticipantList />
46
-            <MeetingParticipantList />
40
+            <ScrollView bounces = { false }>
41
+                <LobbyParticipantList />
42
+                <MeetingParticipantList />
43
+            </ScrollView>
47
             {
44
             {
48
                 isLocalModerator
45
                 isLocalModerator
49
                 && <View style = { styles.footer }>
46
                 && <View style = { styles.footer }>
61
                         style = { styles.moreButton } />
58
                         style = { styles.moreButton } />
62
                 </View>
59
                 </View>
63
             }
60
             }
64
-        </JitsiModal>
61
+        </JitsiScreen>
65
     );
62
     );
66
 };
63
 };
67
 
64
 

+ 4
- 4
react/features/participants-pane/components/native/ParticipantsPaneButton.js Vedi File

6
 import { IconParticipants } from '../../../base/icons';
6
 import { IconParticipants } from '../../../base/icons';
7
 import { connect } from '../../../base/redux';
7
 import { connect } from '../../../base/redux';
8
 import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
8
 import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
9
-import { open } from '../../actions.native';
9
+import { navigate }
10
+    from '../../../conference/components/native/ConferenceNavigationContainerRef';
11
+import { screen } from '../../../conference/components/native/routes';
10
 
12
 
11
 type Props = AbstractButtonProps & {
13
 type Props = AbstractButtonProps & {
12
 
14
 
32
      * @returns {void}
34
      * @returns {void}
33
      */
35
      */
34
     _handleClick() {
36
     _handleClick() {
35
-        const { dispatch } = this.props;
36
-
37
-        dispatch(open());
37
+        return navigate(screen.conference.participants);
38
     }
38
     }
39
 }
39
 }
40
 
40
 

+ 16
- 18
react/features/participants-pane/components/native/styles.js Vedi File

165
     isLocal: {
165
     isLocal: {
166
         alignSelf: 'center',
166
         alignSelf: 'center',
167
         color: BaseTheme.palette.text01,
167
         color: BaseTheme.palette.text01,
168
-        marginLeft: 4
168
+        marginLeft: BaseTheme.spacing[1]
169
     },
169
     },
170
 
170
 
171
     participantsPane: {
171
     participantsPane: {
172
-        backgroundColor: BaseTheme.palette.ui01
172
+        backgroundColor: BaseTheme.palette.ui01,
173
+        flex: 1,
174
+        justifyContent: 'center'
173
     },
175
     },
174
 
176
 
175
     participantStatesContainer: {
177
     participantStatesContainer: {
196
         top: BaseTheme.spacing[1]
198
         top: BaseTheme.spacing[1]
197
     },
199
     },
198
 
200
 
199
-    lobbyList: {
201
+    lobbyListContainer: {
200
         position: 'relative'
202
         position: 'relative'
201
     },
203
     },
202
 
204
 
203
-    meetingList: {
204
-        position: 'relative',
205
-        marginTop: BaseTheme.spacing[3]
205
+    lobbyListDescription: {
206
+        ...participantListDescription
206
     },
207
     },
207
 
208
 
208
     lobbyListDetails: {
209
     lobbyListDetails: {
216
         width: '100%'
217
         width: '100%'
217
     },
218
     },
218
 
219
 
219
-    lobbyListDescription: {
220
-        ...participantListDescription
220
+    meetingListContainer: {
221
+        flex: 1
221
     },
222
     },
222
 
223
 
223
     meetingListDescription: {
224
     meetingListDescription: {
227
 
228
 
228
     footer: {
229
     footer: {
229
         alignItems: 'center',
230
         alignItems: 'center',
230
-        backgroundColor: BaseTheme.palette.ui01,
231
-        bottom: BaseTheme.spacing[0],
232
-        display: 'flex',
233
         flexDirection: 'row',
231
         flexDirection: 'row',
234
-        height: BaseTheme.spacing[10],
235
-        justifyContent: 'space-between',
236
-        paddingRight: BaseTheme.spacing[3],
237
-        position: 'relative',
238
-        right: BaseTheme.spacing[0],
239
-        left: BaseTheme.spacing[0]
232
+        paddingHorizontal: BaseTheme.spacing[3],
233
+        paddingVertical: BaseTheme.spacing[2]
234
+    },
235
+
236
+    headerCloseIcon: {
237
+        marginLeft: 12
240
     },
238
     },
241
 
239
 
242
     inviteButton: {
240
     inviteButton: {
243
         backgroundColor: BaseTheme.palette.action01,
241
         backgroundColor: BaseTheme.palette.action01,
244
-        marginTop: BaseTheme.spacing[2],
242
+        marginBottom: BaseTheme.spacing[4],
245
         marginLeft: BaseTheme.spacing[3],
243
         marginLeft: BaseTheme.spacing[3],
246
         marginRight: BaseTheme.spacing[3]
244
         marginRight: BaseTheme.spacing[3]
247
     },
245
     },

+ 32
- 33
react/features/polls/components/native/PollCreate.js Vedi File

141
                     keyExtractor = { (item, index) => index.toString() }
141
                     keyExtractor = { (item, index) => index.toString() }
142
                     ref = { answerListRef }
142
                     ref = { answerListRef }
143
                     renderItem = { renderListItem } />
143
                     renderItem = { renderListItem } />
144
-
145
-                <Button
146
-                    color = '#3D3D3D'
147
-                    mode = { BUTTON_MODES.CONTAINED }
148
-                    onPress = { () => {
149
-                        // adding and answer
150
-                        addAnswer();
151
-                        requestFocus(answers.length);
152
-                    } }
153
-                    style = { chatStyles.pollCreateAddButton }>
154
-                    {t('polls.create.addOption')}
155
-                </Button>
156
-            </View>
157
-
158
-            <View
159
-                style = { chatStyles.buttonRow }>
160
-
161
-                <Button
162
-                    color = '#3D3D3D'
163
-                    mode = { BUTTON_MODES.CONTAINED }
164
-                    onPress = { () => setCreateMode(false) }
165
-                    style = { chatStyles.pollCreateButton } >
166
-                    {t('polls.create.cancel')}
167
-                </Button>
168
-
169
-                <Button
170
-                    color = '#17a0db'
171
-                    disabled = { isSubmitDisabled }
172
-                    mode = { BUTTON_MODES.CONTAINED }
173
-                    onPress = { onSubmit }
174
-                    style = { chatStyles.pollCreateButton } >
175
-                    {t('polls.create.send')}
176
-                </Button>
144
+                <View style = { chatStyles.pollCreateButtons }>
145
+                    <Button
146
+                        color = '#3D3D3D'
147
+                        mode = { BUTTON_MODES.CONTAINED }
148
+                        onPress = { () => {
149
+                            // adding and answer
150
+                            addAnswer();
151
+                            requestFocus(answers.length);
152
+                        } }
153
+                        style = { chatStyles.pollCreateAddButton }>
154
+                        {t('polls.create.addOption')}
155
+                    </Button>
156
+                    <View
157
+                        style = { chatStyles.buttonRow }>
158
+                        <Button
159
+                            color = '#3D3D3D'
160
+                            mode = { BUTTON_MODES.CONTAINED }
161
+                            onPress = { () => setCreateMode(false) }
162
+                            style = { chatStyles.pollCreateButton } >
163
+                            {t('polls.create.cancel')}
164
+                        </Button>
165
+
166
+                        <Button
167
+                            color = '#17a0db'
168
+                            disabled = { isSubmitDisabled }
169
+                            mode = { BUTTON_MODES.CONTAINED }
170
+                            onPress = { onSubmit }
171
+                            style = { chatStyles.pollCreateButton } >
172
+                            {t('polls.create.send')}
173
+                        </Button>
174
+                    </View>
175
+                </View>
177
             </View>
176
             </View>
178
         </View>
177
         </View>
179
     );
178
     );

+ 42
- 19
react/features/polls/components/native/PollsPane.js Vedi File

1
 /* eslint-disable react-native/no-color-literals */
1
 /* eslint-disable react-native/no-color-literals */
2
 // @flow
2
 // @flow
3
 
3
 
4
-import React from 'react';
5
-import { View } from 'react-native';
6
-import { Button } from 'react-native-paper';
4
+import { useNavigation, useIsFocused } from '@react-navigation/native';
5
+import React, { useEffect } from 'react';
6
+import { Button, useTheme } from 'react-native-paper';
7
+import { useSelector } from 'react-redux';
7
 
8
 
9
+import JitsiScreen from '../../../base/modal/components/JitsiScreen';
8
 import { BUTTON_MODES } from '../../../chat/constants';
10
 import { BUTTON_MODES } from '../../../chat/constants';
11
+import { screen } from '../../../conference/components/native/routes';
12
+import { getUnreadPollCount } from '../../functions';
9
 import AbstractPollsPane from '../AbstractPollsPane';
13
 import AbstractPollsPane from '../AbstractPollsPane';
10
 import type { AbstractProps } from '../AbstractPollsPane';
14
 import type { AbstractProps } from '../AbstractPollsPane';
11
 
15
 
13
 import PollsList from './PollsList';
17
 import PollsList from './PollsList';
14
 import { chatStyles } from './styles';
18
 import { chatStyles } from './styles';
15
 
19
 
16
-const PollsPane = (props: AbstractProps) => {
17
 
20
 
21
+const PollsPane = (props: AbstractProps) => {
18
     const { createMode, onCreate, setCreateMode, t } = props;
22
     const { createMode, onCreate, setCreateMode, t } = props;
23
+    const isPollsScreenFocused = useIsFocused();
24
+    const navigation = useNavigation();
25
+    const nbUnreadPolls = useSelector(getUnreadPollCount);
26
+    const { palette } = useTheme();
27
+
28
+    const nrUnreadPolls = !isPollsScreenFocused && nbUnreadPolls > 0
29
+        ? `(${nbUnreadPolls})`
30
+        : '';
31
+
32
+    useEffect(() => {
33
+        navigation.setOptions({
34
+            tabBarLabel: `${screen.conference.chatandpolls.tab.polls} ${nrUnreadPolls}`
35
+        });
36
+    }, [ nrUnreadPolls ]);
19
 
37
 
20
     return (
38
     return (
21
-        <View style = { chatStyles.PollPane }>
22
-            { createMode
23
-                ? <PollCreate setCreateMode = { setCreateMode } />
24
-                : <View style = { chatStyles.PollPaneContent }>
25
-                    {/* <View /> */}
26
-                    <PollsList />
27
-                    <Button
28
-                        color = '#17a0db'
29
-                        mode = { BUTTON_MODES.CONTAINED }
30
-                        onPress = { onCreate }
31
-                        style = { chatStyles.createPollButton } >
32
-                        {t('polls.create.create')}
33
-                    </Button>
34
-                </View>}
35
-        </View>
39
+        <JitsiScreen
40
+            contentContainerStyle = { chatStyles.PollPane }
41
+            hasTabNavigator = { true }
42
+            style = { chatStyles.PollPaneContainer }>
43
+            {
44
+                createMode
45
+                    ? <PollCreate setCreateMode = { setCreateMode } />
46
+                    : <PollsList />
47
+
48
+            }
49
+            {
50
+                !createMode && <Button
51
+                    color = { palette.screen01Header }
52
+                    mode = { BUTTON_MODES.CONTAINED }
53
+                    onPress = { onCreate }
54
+                    style = { chatStyles.createPollButton } >
55
+                    {t('polls.create.create')}
56
+                </Button>
57
+            }
58
+        </JitsiScreen>
36
     );
59
     );
37
 };
60
 };
38
 
61
 

+ 12
- 6
react/features/polls/components/native/styles.js Vedi File

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { schemeColor } from '../../../base/color-scheme';
4
 import { ColorPalette, createStyleSheet } from '../../../base/styles';
3
 import { ColorPalette, createStyleSheet } from '../../../base/styles';
4
+import BaseTheme from '../../../base/ui/components/BaseTheme';
5
 
5
 
6
 export const answerStyles = createStyleSheet({
6
 export const answerStyles = createStyleSheet({
7
     question: {
7
     question: {
110
 
110
 
111
 export const chatStyles = createStyleSheet({
111
 export const chatStyles = createStyleSheet({
112
     messageFooter: {
112
     messageFooter: {
113
+        flex: 1,
113
         flexDirection: 'row',
114
         flexDirection: 'row',
114
         justifyContent: 'space-between',
115
         justifyContent: 'space-between',
115
         alignItems: 'center',
116
         alignItems: 'center',
123
 
124
 
124
     noPollText: {
125
     noPollText: {
125
         flex: 1,
126
         flex: 1,
126
-        color: schemeColor('displayName'),
127
+        color: BaseTheme.palette.ui05,
127
         textAlign: 'center',
128
         textAlign: 'center',
128
-        paddingTop: '10%'
129
+        paddingTop: '8%'
129
     },
130
     },
130
 
131
 
131
     pollItemContainer: {
132
     pollItemContainer: {
165
     },
166
     },
166
 
167
 
167
     pollCreateAddButton: {
168
     pollCreateAddButton: {
168
-        margin: 8
169
+        margin: BaseTheme.spacing[2]
169
     },
170
     },
170
 
171
 
171
     toggleText: {
172
     toggleText: {
172
         color: ColorPalette.blue,
173
         color: ColorPalette.blue,
173
-        paddingTop: 16
174
+        paddingTop: BaseTheme.spacing[3]
174
     },
175
     },
175
 
176
 
176
     createPollButton: {
177
     createPollButton: {
177
         padding: 8,
178
         padding: 8,
178
-        margin: 4
179
+        margin: BaseTheme.spacing[2]
179
     },
180
     },
180
 
181
 
181
     PollPane: {
182
     PollPane: {
183
         padding: 8
184
         padding: 8
184
     },
185
     },
185
 
186
 
187
+    PollPaneContainer: {
188
+        flex: 1
189
+    },
190
+
186
     PollPaneContent: {
191
     PollPaneContent: {
187
         justifyContent: 'space-between',
192
         justifyContent: 'space-between',
193
+        padding: BaseTheme.spacing[3],
188
         flex: 1
194
         flex: 1
189
     },
195
     },
190
 
196
 

+ 5
- 8
react/features/toolbox/components/native/Toolbox.js Vedi File

44
     /**
44
     /**
45
      * Whether or not the reactions feature is enabled.
45
      * Whether or not the reactions feature is enabled.
46
      */
46
      */
47
-    _reactionsEnabled: boolean,
48
-
49
-    /**
50
-     * The redux {@code dispatch} function.
51
-     */
52
-    dispatch: Function
47
+    _reactionsEnabled: boolean
53
 };
48
 };
54
 
49
 
55
 /**
50
 /**
88
                 <VideoMuteButton
83
                 <VideoMuteButton
89
                     styles = { buttonStylesBorderless }
84
                     styles = { buttonStylesBorderless }
90
                     toggledStyles = { toggledButtonStyles } />
85
                     toggledStyles = { toggledButtonStyles } />
91
-                { additionalButtons.has('chat')
86
+                {
87
+                    additionalButtons.has('chat')
92
                       && <ChatButton
88
                       && <ChatButton
93
                           styles = { buttonStylesBorderless }
89
                           styles = { buttonStylesBorderless }
94
-                          toggledStyles = { backgroundToggledStyle } />}
90
+                          toggledStyles = { backgroundToggledStyle } />
91
+                }
95
 
92
 
96
                 { additionalButtons.has('raisehand') && (_reactionsEnabled
93
                 { additionalButtons.has('raisehand') && (_reactionsEnabled
97
                     ? <ReactionsMenuButton
94
                     ? <ReactionsMenuButton

Loading…
Annulla
Salva